- Монолит – единый backend и frontend.
- SPA +API Backend - frontend и backend с API.
- SOA - frontend, backend с API, шина к другим backend сервисам.
- Микросервисы - frontend, API Gateway к разным backend с API, messageBroker для межсервисной коммуникации.
- Микрофронтенды – разные frontend, API Gateway к разным backend с API, messageBroker для межсервисной коммуникации.
«Большой комок грязи»:
- Нет четкого разделения на части;
- Каждая часть системы связана со всеми остальными частями;
- В эту архитектуру сложно вносить изменения, за счет сильной связанности могут потянуть за собой сбой .
- Каждый слой изолирован от остальных;
- Каждый слой отвечает за определенный функционал;
- Но изменения зачастую пронизывают все свои системы.
- Использует логическое группирование функциональности в соответствии с bounded context c хорошо определенной изоляцией;
- Логика отделена от инфраструктуры;
- Легко перейти на микросервисы.
- Распределенная система;
- Централизация – ESB (корпоративная шина) – через нее идет коммуникация у всех сервисов;
- Стремление к повторному переиспользованию сервисов и разделению ресурсов.
Корпоративная шина может содержать конвертацию данных, коннект собственный к БД – может стать узким местом.
- Распределенная система;
- Децентрализация;
- Без совместного использования ресурсов (отдельные БД);
- Разделение по bounded context;
- Общение через брокера без трансформации: что отправил, то и получил;
- API Gateway без бизнес логики;
- Тестирование идет только самих сервисов, где есть логика.
- Frontend декомпозирован в соответствии с микросервисами;
- Кросс-функциональные команды.
Монолит
Минусы:
- Сложность понимания;
- Сложность внесения изменений;
- Сложность масштабирования разработки;
- Привязанность к технологическому стеку;
- Хрупкость (утечка памяти будет во всем монолите);
- Сложность тестирования.
Плюсы:
- Простота разработки;
- Простота развертывания;
- Меньшие требования к компетенциям;
- ACID транзакционность.
Микросервисы
Минусы:
- Сложность правильной декомпозиции;
- Трудозатраты на интеграции;
- Отсутствие транзакционности между сервисами.
Плюсы:
- Легкое масштабирование разработки;
- Легче вносить изменения;
- Лояльность к инновациям;
- Легче тестировать;
- Оптимизация ресурсов: можно подбирать технологии под выполнение конректных задач.
Области применения:
- Идея/Стартап - Монолит
- Продукт до 50-70 разработчиков - SPA +API Backend
- Большой продукт, больше 50-70 разработчиков – Микросервисы
Цели внедрения MSA:
- Быстрая реакция на изменения рынка;
- Сокращение или удержание Lead Time (время от взятия из backlog до релиза) на прежнем уровне.
Определение границ сервисов
Доменная модель (domain model) – набор классов для решения определенной проблемы.
Ограниченный контекст (bounded context) – один и тот же объект может обладать совершенно разными признаками, исходя из области применения.
Нельзя использовать единую модель во всех случаях, поскольку:
- Сущность будет перегружена;
- Нельзя валидировать поля (для каждой области она своя);
- Риск внесения изменений, надо учитывать все области применения.
Bounded context – инструмент для ограничения физических границ владения. Карта контекстов (context map) - группировка по области применения
Разделение на агрегаты
Value Object – POJO, без ID. Сравнивается по совокупности его полей. Описывает свойства более высокоуровневого объекта.
Entity (сущность) – POJO с ID и value objects
Aggregate (агрегат) - кластер доменных сущностей, несколько различных entities, отвечает за соблюдение инвариантов (валидацию) и транзакционность (одновременное сохранение всех сущностей агрегата).
Микросервис – это автономный, независимо развертываемый программный компонент, который реализует определенные полезные функции. Границы сервисов формируются на основе бизнес-границ. Содержит один bounded context.
Размер и границы микросервиса. Деление по слабым связям и по агрегатам (минимальный микросервис 1 агрегат – большой и самодостаточный).
Когда у одной команды много сервисов - потери от развертывания и побочных инфраструктурных доработок -> снижение Lead Time Когда у нескольких команд один сервис – ожидание друг друга, согласование на внедрение технологий -> снижение Lead Time Количество сервисов в 1 команде = 1 Слишком мелкое распределение – риск создать распределенный монолит.
Сильное зацепление внутри сервиса и слабая связанность между сервисами.
Для проектирования микросервисов, выработки общей архитектуры и согласование используемых технологий используется event storming. Event Storming – work shop (встречи бизнеса, аналитиков и разработчиков).
Для подготовки встречи необходимы продумать: расписание встречи, цели, перерывы, Big picture, легенда, Process modeling, Software design.
Легенда (заданная по цветам):
- Domain Event – событие, происходящее в бизнес процессе (БП). Пишется в прошедшем времени;
- User/Actor – человек, выполняющий действие (команду) через интерфейс;
- Command – команда, выполняемая пользователем через интерфейс, воздействует на агрегат, после исполнения логики в котором порождаются доменные события, в наст. времени;
- Aggregate – кластер доменных объектов, которые могут быть рассмотрены как единое целое.
- External System – сторонний поставщик услуг, например, платежный шлюз или транспортная компания.
- View/Read Model – представление, с которым пользователи взаимодействуют, чтобы выполнить задачу в системе.
- Policy – правило, например, «если клиент с золотой картой, то скидка 5%».
- Hot Spot – проблема, вопрос, идея, комментарий - необходим для фиксации что «тут что-то не так, можно сделать лучше».
- Term – служит для фиксации терминов, которыми мы оперируем. Единая терминология.
Флоу Изображение БП с карточками в цветах легенды, расположенные в нужном порядке.
Big picture:
- Сбор доменных событий;
- Расстановка событий по хронологии.
Рекомендации:
- Строим успешный путь
- Выстраиваем Альтернативный путь
- Ключевое событие - большего размера, bounded context отделяем пограничные события вертикальной чертой
- Проверка трэйсинг (убедиться, что все события присутствуют и в нужном порядке, прочитать в обратном порядке)
- Внести термины
Process modeling: Обогащаем модель с событиями командами, пользователями, агрегатами, правилами. Выделение границ контекстов:
- Анализ ключевых событий;
- Агрегаты нельзя разбивать;
- Анализ свимлейнов (побочных БП);
- Анализ различающихся терминов – признак bounded context
Software design: Определяем границы сервисов. Переложить обогащенную модель на технологии и связи с БД.
Антипаттерны:
- Всегда говорит 1 человек;
- «Есть же документация»
- Видео трансляция вместо общего ресурса (например, Miro)
Сигналы неправильного разбиения:
- Сервис А не может работать без сервиса Б;
- Сервис А и сервис Б изменяются по одной причине в большинстве случаев;
- Вам нужны ACID транзакции (разбиение агрегата);
- Слишком большая команда на область (больше 9 человек на сервис).
Когда использовать Event Storming
- Вы моделируете БП;
- Вы изучаете новые бизнес требования;
- Вы хотите восстановить знание домена;
- Вы хотите улучшить существующий БП;
- Вы хотите поделиться знаниями с новыми членами команды.
Закон Конвея «Организации проектируют системы, которые копируют структуру коммуникаций в этой организации»
Структура команд должна является отражением структуры сервисов.
У каждого сервиса должен быть владелец.
Структура команды:
- Специалисты в своей области;
- Небольшая (9 человек);
- Кросс-функциональная;
- Автономная;
- Долгоживущая;
- Владеет 1-2 сервисами;
- Несет полную ответственность за развитие и поддержку;
- В команде: web, QA, back x2, IOS, Android.
Работа по backlog и быстрый выпуск фичей. Разбиение команд на микросервисы не отменяет совместных сквозных задач. Но нужен CPO для контроля общих приоритетов в команде.
Архитектора:
- Границы сервисов;
- Автономность, независимость сервисов;
- Виды межсервисного взаимодействия.
Команда:
- Глубокое понимание бизнес области сервиса;
- Архитектура внутри сервиса;
- Технологии внутри сервиса.
Платформенные команды на frontend:
- Самые опытные разработчики;
- Контролируют стек;
- Определяют архитектуру;
- Выпускают релизы.
Платформенные команды на backend:
- Гайды и стандарты;
- Стандарты коммуникации;
- Шаблон сервиса.
API Gateway pattern
Без общего API:
- теряется гибкость (если появился новый серсис или объединились другие, а у веб нет этой информации);
- проблема авторизации (на всех мс, вместо одного).
Задачи API Gateway:
- Проксирование запросов;
- Аутентификация;
- Ограничение частоты запросов;
- Сбор показателей;
- Кэширование;
- Журнал запросов.
Проблема единого API Gateway для всех frontend (web, mobile и др.)
- нагрузка;
- нельзя использовать разные виды аутентификации;
- получают доступ к тем методам и функционалу, который не используется.
Поэтому необходимо создавать свой API Gateway под каждый вид frontend.
API Composition pattern Когда вызов идет к одному backend сервису, а на нем вызов в другие сервисы и сбор общей информации для передачи на frontend.
Часто API Composition реализуется функцией API Gateway.
Access token pattern

Популярное решение - keycloak.
Shared database anti-pattern
- Одна БД на несколько мс.
- Миграция в одном сервисе может повлечь ошибки при работе в других;
- Невозможность использовать более подходящий вид БД в конкретном случае;
- Нагрузка;
- Мс не разделены по bounded context. Нельзя получать данные напрямую из БД другого сервиса тоже.
Database per service pattern
- Использовать разные вендоры;
- Снижение нагрузки;
- Можно использовать несколько БД в одном сервисе.
Структура микросервиса
- Деление по слоям: бизнес-логика отдельно от интеграции и межсервисного взаимодействия;
- Разделение ООП/DDD и CRUD: для GET использовать просто queries с преобразованием в DTO, в то время как для POST/PUT/DELETE прописывать логику и бизнес правила;
- Отделение API (endpoints) от Application (commands - service и бизнес логика).
- Commands настраивает взаимодействия entity с repository.
- Валидациям сущности в Domain Layer.
Общие библиотеки и повторное использование кода. Можно столкнуться с проблемой, когда сервисы будут развиваться по-разному, но использовать одни библиотеки, что создает дополнительную зависимость. В общих библиотеках писать стандарты и правила, вроде логирования и т.д., а классы с бизнес логикой у каждого свои.
Общие справочники:
- Иметь одинаковый enum (если редко обновляется);
- Создать мс со справочником;
- Репликация БД.
Template service pattern Использование шаблона сервиса позволяет сконфигурировать общие взаимодействия, реализовать правила и стандарты, единообразие сервисов.
Синхронное/асинхронное взаимодействие (request/response или queue)
Где возможно, нужно использовать асинхронное.
Синхронное - RPC pattern
- Выполняется медленно (иногда медленнее, чем в монолите);
- Снижение доступности (если несколько мс в цепочке, SLA умножается на количество мс);
- Каскадные сбои.
Circuit Breaker pattern (предохранитель) Библиотека устанавливается на http клиент. Отслеживает ошибки по таймауту и размыкает эти запросы, если получил более 3-5 сбоев, далее возвращает ошибку сразу, через какое-то время (30 сек) снова размыкает соединение.
Популярные решения:
- Polly;
- Istio Circuit Breaking.
Асинхронное - Messaging pattern
Использование брокеров очередей.
Достоинства:
- Буферизация сообщений (данные запроса не будут потеряны);
- Слабая связанность мс;
- Гибкое взаимодействие.
Недостатки:
- Потенциальное узкое место по производительности;
- Потенциальная единая точка отказа;
- Дополнительная сложность администрирования.
CAP теорема (отказ брокера, рассинхронизованность данных в мс) Невозможно выбрать все 3, только 2:
- Доступная;
- Распределенная;
- Согласованная.
А значит для MSA уже есть распределенная и приходится пожертвовать доступностью (отказываем в выполнении изначального запроса) или согласованностью (данные будут получены позднее). Обычно жертвуем согласованностью временно.
Transactional outbox pattern и Polling publisher pattern
Сделать в БД две таблицы с записыванием самого действия и отправки сообщения о нем – Outbox table – стандартного формата для всех агрегатов (id, aggregateType, aggregateId, eventType, payload).
Polling publisher опрашивает, какие события еще не опубликовал, и отправляет повторно в брокер.
Риск повторной отправки и задвоение записи
Transactional log tailing + Outbox
Использование Debezium (анализатор журнала транзакций) как Polling publisher, только нагружает не БД, а Журнал транзакций.
Защита на стороне потребителя от повторов. Введение таблицы Inbox. И общая транзакция в таблицу inbox и действия.
CQRS как альтернатива API Composition
Отправка сервисами в очередь для получения данных одним общим сервисом и сохранением в своей БД для комбинации данных.
Плюсы:
- Меньше точек зависимости (только от своей БД);
- Возможность эффективного использования запросов в микросервисной архитектуре (применения соответствующей технологии при решении конкретной проблемы);
- Возможность эффективной реализации разнородных запросов (выгрузка большого объема данных для дальнейшего анализа);
- Улучшенное разделение ответственности.
Минусы:
- Более сложная архитектура;
- Отставание репликации.
Saga pattern (альтернатива распределенным транзакциям)
Поочередное выполнение транзакций в каждом мс и отправка сообщения в брокер.
Компенсирующие транзакции в Saga – нужно продумать неуспешный вариант на каждом этапе.
Координация Saga: хореография (самостоятельное реагирование на событие) и оркестрация (есть дирижер – алгоритм для выполнения команд).
Хореография
Преимущества:
- Простота;
- Слабая связанность.
Недостатки:
- Сложная диагностика проблем;
- Риск циклических зависимостей между сервисами.
Оркестрация Создание алгоритма управления процессами с перечислением действий в случае успеха и ошибки.
Преимущества:
- Не создает циклических зависимостей;
- Улучшенное разделение ответственности: сервисы занимаются действиями, а оркестратор – координацией.
Недостатки:
- Риск избыточной реализации у оркестратора прикладной логики.
Способы развертывания мс:
- Multiple service instances per host;
- Service instance per host:
- Serverless deployment;
- Service instance per VM;
- Service instance per Container.
Multiple service instances per host
Легче в развертывании и эффективная работа с ресурсами, но:
- Несколько сервисов конкурируют за общие инфрастуктурные ресурсы;
- На сервере будет установлены разные фреймворки для разных сервисов, которые могут привести к конфликтам;
- Несовместимость версий разных сервисов.
Service instance per host
Serverless deployment – облачное хранение
Service instance per VM
Плюсы:
- Четкое разграничение ресурсов;
- Работа на разных версиях и разных фреймворках;
- Облегченный анализ и мониторинг.
Минусы:
- Установка и управление инфрастуктурой сторонней поддержкой (установка БД, брокера и т.д.).
Service instance per Container
Плюсы:
- Быстро поднимается;
- Инфрастуктура внутри.
Один мс – один репозиторий; Один мс – один CI конвейер.
Continuous Integration (CI) сервиса (Сначала быстрые шаги, потом медленные):
- Статический анализ кода;
- Unit тесты;
- Сборка артефакта;
- Интеграционные тесты;
- Компонентные тесты;
- Отправка в хранилище (поднятие версии и отправка в нексус, например);
- Запуск триггеров.
Быстрая обратная связь - о падении пайплайн должно приходить оповещение.
Continuous Delivery (CD)
- Выкачивание артефакта;
- Доставка и развертывание;
- Запуск технических шагов;
- Дымовое тестирование (имитация действий клиента, базовая функциональность);
- Откат (если необходимо).
Deploy инструменты:
- Ci cd (gitlab);
- Kubernetes;
- Jenkins.
Externalized configuration pattern
Потребность разворачивать на разных стендах, в облаке, локально и т.д. решается поставлением конфигураций извне.
Пассивная модель

Активная модель

Хранение/получение секретных данных (Vault)
End-to-end Проход сценария по всему функционалу:
- Маленький процесс покрытия;
- Нужно заготавливать входные данные, которые возможно формируются в сервисе и создается неконсистентность данных.
Тестирование в распределенной системе
Написание unit и integration тестов, компонентные тесты внутри одного мс.
CDC – контрактные тесты, контракты между мс.
Модульных тестов должно быть больше. Меньше интеграционных, еще меньше компонентных и e2e (end-to-end) тесты.
Модульные тесты Задача – проверять бизнес-логику сервиса и доменный слой. Использование заглушек на остальной функционал.
Интеграционные тесты API слой, репозиторий, интеграция с брокерами или api другого мс – cdc тесты (контракты).
Популярные решения: PACT.
Компонентные тесты Направлены на публичные методы сервисов.
End-to-end Тестирование всего процесса интеграции всех сервисов. Не дают ответ – можно ли релизиться. Тестируйте маршруты, а не истории.
Нужно также писать контрактные тесты между backend и frontend.
Антипаттерн «Рожок с мороженным» Когда неправильно распределено количество тестов, не по сложности и скорости проведения.
Кто создает тесты:
- Unit - разработчики;
- Интеграционные - разработчики;
- Компонентные – разработчики и тестировщики;
- End-to-end – тестировщики.
Health Check API pattern
Kubernetes
Опрашивает работоспособность сервиса
Grafana
Получает и хранит метрики
Log aggregation pattern
Агрегация логов в файлы, перекладывать в файловый агент – logstash, а далее хранить в elasticsearch, а в kibana анализировать. Если напрямую писать в elasticsearch, есть риск потерять логи или накопить до отключения сервиса. Logstash также помогает преобразовать в единый формат, вырезать sensitive data.
Distributed tracing pattern
Найти traceId в первом запросе и отследить по всем сервисам.

- Jaeger;
- Zipkin.
Подход «кто разработал, тот и поддерживает» - более ответственный подход к разработке, высокое погружение в возможные проблемы.
Не класть все сервисы в 1 место, которое может отказать. Изолированность и масштабирование реплик. Балансировка нагрузки RPC. Масштабирование БД. Балансировка нагрузки через очереди.
Необходимо реализовать следующие шаги:
- Поддержка сверху и снизу (работа бизнеса совместно с разработкой);
- Построение карты контекстов - полностью копировать структуры монолита нельзя, поскольку есть риск создать распределенный монолит.
- Проведение Event Storming;
- Реорганизация команд, сделав их кросс-функциональными;
- Квадрант приоритизации – поочередное вынесение из монолита наиболее подходящего функционала.
Метрики успеха:
- Количественные – уменьшение Lead Time
- Качественные – happy index
- Отделение Frontend от Backend (добавление API gateway);
- Постепенные изменения – поочередное вынесение функционала в сервис.
- Реализация новых бизнес возможностей в виде сервисов (добавление нового функционала);
- Разбиение монолита путем выделения сервисов - появляется интеграционный слой
между монолитом и выделенным сервисом.
Branch by abstraction pattern
Создание интерфейса между частями и вынос имплементации в новый мс.
Change data capture pattern
Уйти из монолита, не обладая исходным кодом.

Split table pattern – декомпозиция БД
Перенесение одной таблицы в несколько таблиц
Шаги выделения мс из монолита:
- Event Storming;
- Выделяем авторизацию в мс;
- Создаем api gateway между auth и монолитом;
- Рефакторинг выделяемого функционала в мс;
- Декомпозиция БД;
- Выделяем мс.
- Отчет и аналитика - настройка репликации БД монолита в Систему отчетности, прибегнув к перекачке данных на основе событий, используя брокер очередей
































