Эпиграф: «Talk is cheap. Show me the code.»
Здравствуйте.
Книга «Искусство неизменяемой архитектуры: теория и практика управления данными в распределенных системах» дала интересные идеи создания приложений. Появилось желание проверить утверждения из книги на практике и сравнить теорию и практику в реальном примере.
Для проверок концепций изложенных в книге было решено разработать ТЕСТОВОЕ, НЕ PROD, решение. Решение именно для проверок идей, а не для использование в рабочем окружении.
Сокращения
|
Книга |
Вся данная работа делается ради проверок идей изложенных в книге «Искусство неизменяемой архитектуры: теория и практика управления данными в распределенных системах». Далее по тексту если указано слово «книга» и не названо ее имя, подразумевается книга «Искусство неизменяемой архитектуры: теория и практика управления данными в распределенных системах». |
|
Gateway |
Основное бизнес приложение для проверки идей описанных в книге. |
|
Generator |
Приложение для создание тестовых сообщений, подписи их тестовыми сертификатами, отправки в Gateway и контроля результатов. |
|
Сертификаты |
Самоподписанные сертификаты для проверок работы с безопасностью в рамках идей изложенных в книге. |
Задача цикла
Данная статья является первой в цикле статей о проверке идей описанных в книге. По результатам цикла будет создано ТЕСТОВОЕ приложения ДЛЯ ПРОВЕРКИ идей изложенных в книге. Все создаваемые приложения должны запускаться локально и не требовать отдельной инфраструктуры.
Какие идеи из книги хочется проверить т. к. описанная в книге архитектура дает возможность их использования:
-
Возможность очень простой репликации данных между базами. Особенно заинтересовало, что базы данных для репликации могут быть очень разными.
-
Возможность создания приложений которые смогут часть времени работать в режиме offline без потери качества работы. И автоматической синхронизации после появления связи.
-
Возможность очень простой реализации асинхронной работы приложения.
-
Возможность горизонтального масштабирования.
-
Возможность иметь автоматически обновляемый кэш данных.
-
Возможность подключения безопасности на основе сертификатов с минимальными доработками.
-
Возможность поддерживать стабильную производительность на любом объеме данных с минимальными техническими доработками.
-
Очень легкое подключение версионирования записей.
Используемые технологии
Для реализации приложения обработки данных выбран Spring Boot с реализацией бизнес логики на Kotlin.
База данных выбрана встроенная (in memory) H2 https://github.com/Enroi/xml-gateway База не сохраняется при перезапусках приложения. При каждом запуске база данных создается новая.
Для обеспечения безопасности работы с данными выбрана работа с Public/Private сертификатами, описанная в книге.
Для тестирования бизнес части было создано приложение на Python. Это приложение создает запросы к бизнес части и контролирует результат их выполнения. Описание технических идей приложения для тестирования выходит за рамки данного описания. Достаточно сказать что Python справляется с генераций нагрузки для бизнес приложения.
Взаимодействие между приложением XML-Gateway и Generator идет через классические HTTP REST запросы.
Общая постановка задачи для реализации
В рамках проверки идей описанных в книге решено реализовать следующую задачу.
Generator создает заданное количество запросов в Gateway. В процессе отправки каждое сообщение подписывается Private ключом. Gateway проверяет пришедшие сообщения на корректность подписи Public ключом.
Запрос ответа и получение результата должны быть асинхронными. Т. е. Сначала Generator запрашивает результат и через некоторое время получает ответ от Gatweay.
Необходимо понять какую нагрузку выдерживает решение построенное на идеях описанных к книге.
Цикл обработки сообщения следующий:
-
Generator создает пакет запросов на обработку документов.
-
Generator отправляет запросы на обработку в Gateway, параллельно для каждого документа из созданного пакета сообщений.
-
Gateway получает и обрабатывает каждый запрос отдельно, параллельно.
-
Gateway проверяет подпись каждого документа. Если подпись не корректна то пользователю должен быть возвращен код HTTP результата 401
-
Если подпись корректная то пользователю должен быть возвращен какой то идентификатор обработки, с которым он может запросить и получить результат позже.
Детальная бизнес задача на первый этап
Что бы проверить работоспособность всей инфраструктуры был выбран документ «эмуляции» запроса выписки. Пример:
<statement-request date-from="2025-11-11" date-to="2025-12-12" document_type="a">
<account number="40702812222222222222">
<bank bic="045678901" name="БАНК 1"/>
</account>
</statement-request>
В Generator должен отправить множество таких сообщений и для каждого получить один из следующих ответов:
-
Принят в работу
-
Завершен и сразу Generator должен иметь возможность получить ответ
-
Подпись не может быть проверена
Это простая задача на первый этап, для создания инфраструктура.
Общие примененные архитектурные и технические решения
В этой главе будет описана общая архитектура приложения и будут пропущены детали специфичные для приложений «неизменяемой архитектуры».
Generator
Для создания тестовых запросов создано Python приложение. В нем отдельно создан список счетов для которых будут создаваться запросы и шаблон запроса.
Generator создан как FastAPI приложение. Вся работа идет через asyncio технологию и библиотеки.
Generator позволяет на компьютере с процессором Intel(R) Core(TM) i5-10310U CPU @ 1.70GHz создавать 40`000 файлов, с перебором счетов из списка, за 33 секунды.
На первом этапе указано 3 уникальных счета для проверки.
Gateway
Хэш суммы
В рамках правил написания приложений для «неизменяемой архитектуры» все связи между данными должны быть сделаны через Hash суммы объектов/документов. Соответственно каждый документ/таблица в Gateway имеет поле хэш суммы хранимого документа.
База данных
Одним из интересных свойств решений описанных в книге это возможность работы с полностью универсальной структурой данных, которая автоматически поддерживает версионность объектов. Однако на первом этапе решено использовать «классические» таблицы для хранения данных. К реализации идей «универсального хранилища» описанных в книге вернемся на следующих этапах.
Архитектура приложения создается исходя из концепций описанных в книге. И главное правило книги это использование при работе с изменением базы данных только Insert. Update и Delete должны быть полностью исключены.
Проект тестовый. Смысла добавлять в проект поддержку управления структурой базы данных нет. Вместо этого в проекте применен Spring data JPA, который подключает через зависимости Hibernate. Для Hibernate указано автоматическое создание таблиц БД относительно описанных Entity.
Структура
Для реализации задачи первого этапа решено создать 3 таблицы/Hibernate Entity:
-
Таблица пришедших документов XmlInputDocument.kt
-
Таблица документов отправленных на обработку SentToAbs.kt
-
Таблица обработанных документов ReceivedFromAbs.kt
Дальше описанные выше Hibernate Entity будут именоваться как таблицы базы данных для облегчения описания. Плюс используемые технологии позволяют легко переключиться на любую поддерживаемую Spring Data JPA / Hibernates базу данных, где имена таблиц возможно будут другие.
Обработка документов
Перед отправкой Generator подписывает отправляемый XML и вставляет в заголовок отправляемого сообщения два заголовка:
-
Имя использованного сертификата. По этому имени Gateway будет искать сертификат для проверки в своем хранилище.
-
Электронную подпись т. е. подпись хэш суммы документа.
Gateway получает документы из Generator через REST контроллер.
Gateway проверят подпись пришедших документов используя свою копию public сертификатов. На данный момент времени сертификаты жестко записаны в класс сервиса проверки. В будущем будет сделано более корректное техническое решение.
Если подпись верна то Gateway записывает пришедший документ в таблицу XmlInputDocument.kt вместе с его хеш суммой.
После записи пришедшего документа в XmlInputDocument.kt делается запись в SentToAbs.kt что означает эмуляцию отправки сообщения во внешнюю систему.
После задержки в 10 миллисекунд делается запись в ReceivedFromAbs.kt
Что дало применение технологий из книги в приложении
Асинхронность появилась «сама собой»
Это был один из первых результатов применения технологии неизменяемых данных. Т. к. запросы записываются с одним и тем же хешем. Все связи идут через этот хеш. То нет никакого смысла «держать» сессию. Можно возвращать текущее состояние при каждом запросе с одним и тем же содержимым запроса. Хотя это и дало описанную ниже проблему обновления данных.
«идея сессий» была заменена на запрос с одним и тем содержимым
Применение идей из книги привело к отказу от механизма сессий. Согласно идеям книги «сессии» это привязка к конкретному серверу.
Было решено отказаться от сессий. Вместо этого идентификация запроса и ответа идет тексту запроса. Текст запроса хешируется и записывается в базу вместе с хешем. Детали описаны в книге.
Пользователь приложения приходит за результатам отправленного запроса с текстом прошлого запроса. Из пришедшего запроса получается хеш и по хешу ищется был ли уже запрос. Если запрос был то делается запрос на результат. Результат тоже ищется по хешу, но уже запроса к внешней системе.
Ожидание от поведения системы подтвердились. Без наличия сессий приложение работоспособно. Перезапуск приложения также не приводит к потери работоспособности, при каждом приходе пользователь дает один и тот же запрос и даже если работа прошлого экземпляра приложения была потеряна, работу по запросу данных из внешней системы можно начать еще раз, не информируя пользователя о проблемах при перезапусках приложения. Пользователю придется немного дольше подождать, но это много лучше чем если бы пользователь получил ошибку что его сессия не найдена в новом, запущенном экземпляре приложения.
Явно видна польза при параллельной работе двух и более версий приложения, но в этом случае нужна минимальная репликация. Этот случай будет рассмотрен в следующих описаниях.
Авторизация через сертификаты упростила работу с безопасностью
Переход на сертификаты в книге описывается как упрощение. Идея подтвердилась. В полученной реализации что бы авторизация прошла клиенту приложения нужно подписать сообщение своих сертификатом. Только клиент отвечает за свой private ключ. Сервер проверяет сообщение с помощью public ключа. В серверной реализации не нужно обеспечивать надежное и секретное хранилище паролей или хешей паролей. Т. к. сертификат public то и хранится он может с меньшим количеством сложностей.
Сертификаты «из коробки» дают возможность обеспечить доступ определенным пользователям на определенное время. Механизм отзыва сертификатом и оповещения об этом всех кто заинтересован в проверке сертификата также можно решить множеством известных способов..
Код приложения стал проще
В книге утверждается что переход на технологии «неизменяемого состояния» упрощает приложения. Идея подтвердилась. Отсутствие необходимости обеспечивать еще одно место обновления статуса запроса позволила проще проверять статус запроса. Данное утверждение будет перепроверено позже, на документе с большим количеством статусов.
Появилась проблема «обновления» данных
В книге подчеркивается что применение описанных в ней технологий потребует изменений в правилах работы.
Для первого теста специально был выбран случай когда пользователь приходит с одним и тем же запросом, однако результат может измениться. Конкретно в этом примере проверяется работа на примере выписки по счету. В течении дня выписка по счету может изменится. Однако текущая реализация «закеширует» результат первого запроса. Это проблема.
Однако в книге описаны возможные решения данной проблемы. Это будет сделано в дальнейших шагах по работе с приложением.
Применение неизменяемой архитектуры ложится на текущие реляционные базы данных
Идея подтвердилась. Все описанные подходы «неизменяемой» архитектуры удалось не большими усилиями использовать в реляционной БД.
Однако процесс записи новых данных пришлось реализовывать не средствами классических репозиториев Spring Data JPA / Hibernate, а средствами SQL Merge
Не получилось получать ID новых записей сразу после записи. Конечно применен поиск по индексированному полю, однако это хоть и не большой, но минус этого решения.
Итог
Результаты, которые дала «неизменяемая архитектура» очень хорошие и много превышают сложности, которые дает эта архитектура.
Планы на дельную работу с этой задачей
Текущий, первый этап был сделан для запуска «технологической» базы тестирования идей описанных в книге.
Дальше планируется работа по следующему плану:
-
Вывод места хранения public сертификатов клиентов в отдельное место, вывести их из текущего hardcode места.
-
Реализация работы с более сложным бизнес процессом. В планах реализовать работу с документом типа «заявка на что то». Заявка должна будет пройти через несколько этапов/отделов.
-
Реализация механизма репликации данных и проверка утверждения из книги что данная архитектура не просто позволяет работать децентрализовано, но даже в режиме off-line с автоматической связью результатов сделанных в off-line режиме после появления связи между узлами.
-
Реализации описанной в книге технологии автоматического обновления кеша по изменившимся результатам.
ссылка на оригинал статьи https://habr.com/ru/articles/1026078/