Архитектурные паттерны помогают системному аналитику говорить с архитектором на одном языке: понимать trade-offs, формулировать НФТ и фиксировать решения в ADR. Статья закрывает вопрос «какой паттерн выбрать под симптом» и «что именно описать в требованиях», а не даёт инструкцию по настройке Envoy или Debezium.

1. Суть темы

Архитектурный паттерн — повторяемое решение типовой проблемы распределённой системы: транзакции через границы сервисов, отказоустойчивость, публикация событий, миграция legacy. Паттерн задаёт границы ответственности сервисов и ожидаемое поведение при сбоях — то, что аналитик переводит в сценарии, НФТ и критерии приёмки.

Не всё, что обсуждают рядом с паттернами, является паттерном в том же смысле:

ТипПримерыГде фиксировать в KB
Архитектурные паттерныSaga, Outbox, API Gateway, Strangler FigЭта статья
Модели согласованностиEventual consistency, read-your-writes08.02 Нефункциональные требования (НФТ) — классификация и стандарты — как измеримые НФТ
Свойства операций и APIИдемпотентность, retry, timeout03.05.02 Синхронные протоколы (REST, gRPC, GraphQL), 03.05.03 Спецификации контрактов (OpenAPI, AsyncAPI, Protobuf)

Предпосылка большинства паттернов — принцип database per service: у каждого сервиса своя БД, общая схема — антипаттерн. Без этого границы Saga, Outbox и Event Sourcing не определены. Декомпозицию и границы контекстов см. 03.01.03 Декомпозиция системы на подсистемы и модули и 03.06.02 Основы Domain-Driven Design.

Граница с соседними статьями: здесь — какой паттерн и что зафиксировать в ADR/NFR; стиль интеграции через события, топология потоков и контракты брокера — в 03.05.06 Event-Driven Architecture.

2. Ключевые понятия

Saga

Управление распределённой бизнес-транзакцией через цепочку локальных транзакций. При сбое — компенсирующие операции, а не распределённый 2PC.

ПодходСутьКогда уместен
Хореография (Choreography)Сервисы реагируют на события без центрального координатораНебольшое число участников (ориентир 2–4), простой линейный поток; сложность растёт с числом типов событий и циклов обратной связи
Оркестрация (Orchestration)Центральный оркестратор ведёт состояние и шагиМного шагов, нужна видимость процесса для поддержки

Хореография — частный случай event-driven интеграции: кто публикует какое событие и в каком порядке, см. 03.05.06 Event-Driven Architecture; здесь фиксируем шаги, компенсации и инварианты.

Важно про «согласованность»: Saga обеспечивает бизнес-инварианты (заказ не оплачен без резерва, компенсации откатывают шаги). Это не ACID-транзакция между сервисами и не мгновенная согласованность read-моделей. Между шагами и после компенсаций данные eventually consistent — задержка и допустимые расхождения нужно явно описать в НФТ (см. 08.02 Нефункциональные требования (НФТ) — классификация и стандарты).

Что фиксировать в требованиях: перечень шагов и компенсаций; владелец процесса (при оркестрации — модель в BPMN или state machine); correlation id / business transaction id для сквозной трассировки; идемпотентность каждого шага и компенсации; SLA оркестратора (RTO при его падении); сценарии «частично выполнено» для приёмки. Если компенсация не удалась — отдельный сценарий: политика retry с лимитом, эскалация в очередь поддержки, ручной runbook (блокировка счёта, отмена резерва оператором), статус «требует вмешательства» в UI; без этого критерии приёмки и сценарии L2/L3 остаются дырявыми.

Circuit Breaker (автоматический выключатель)

Блокирует вызовы к проблемной зависимости после порога ошибок, чтобы не каскадировать отказ (fail fast → half-open → closed).

Что фиксировать в требованиях: пороги и окно подсчёта; бизнес-семантика fallback — не только технический ответ «503». Пример: при недоступности оплаты — можно ли оформить заказ «оплата позже», нужно ли отменить резерв, как уведомить клиента. Сценарии деградации оформляйте в Use Case и 02.04.02 Критерии приёмки (Acceptance Criteria); сценарии «circuit open / half-open» — в тест-план (08.03 Тестирование требований (статическое тестирование)). Это функциональные правила деградации, не деталь Resilience4j.

API Gateway

Единая внешняя точка входа: маршрутизация, auth, агрегация, rate limiting. BFF (Backend for Frontend) — отдельный шлюз под канал (mobile/web/partner): разные контракты и агрегация, но больше команд и surface area.

Когда нужен (критерии, а не счётчик сервисов):

Один монолит с REST наружу gateway не требует. Десять внутренних сервисов без внешних клиентов могут обойтись без него, если auth и маршрутизация решены иначе.

Что фиксировать: матрица маршрутов; политики auth — 03.05.05 Безопасность API; один gateway vs BFF по каналам (scope, команды); НФТ по latency на edge.

Service Mesh

Внутренний слой сетевого взаимодействия между сервисами через sidecar-прокси (вспомогательный контейнер рядом с приложением: mTLS, политики, метрики): discovery, retry, timeout, circuit breaker, tracing, балансировка — 03.06.04 Стратегии балансировки нагрузки, 07.08 Контейнеризация и оркестрация (Docker, Kubernetes).

Отличие от Gateway: gateway — клиент → система; mesh — сервис ↔ сервис.

Что фиксировать: какие политики resilience (retry, timeout, DLQ) задаются на mesh, а какие в контракте сервиса — см. 03.05.04 Асинхронное взаимодействие (очереди, Kafka, Events) для асинхронных цепочек; требования к distributed tracing и propagation correlation id; какие сквозные функции выносятся на платформу (единые для всех сервисов), а какие остаются в коде.

Event Sourcing

Состояние — проекция из журнала неизменяемых событий (append-only), а не только текущая строка в таблице.

Пример (заказ): события OrderCreated → PaymentReceived → OrderShipped → DeliveryFailed. Текущий статус — редукция по типам событий (state machine / fold), а не «последнее событие вообще» (DeliveryFailed после OrderShipped меняет статус, но не отменяет факт отгрузки).

Что фиксировать: каталог типов событий и версионирование схем — 03.05.07 Управление версионированием API и жизненным циклом; стратегия upcasting; снимки (snapshots) и SLA построения read-модели; аудит и хранение. Тест-кейсы на порядок и комбинации событий — в 08.03 Тестирование требований (статическое тестирование) и 02.04.02 Критерии приёмки (Acceptance Criteria).

CQRS (Command Query Responsibility Segregation)

Раздельные модели записи (commands) и чтения (queries). CQRS не требует Event Sourcing: достаточно read replica или отдельной read-БД с синхронной/асинхронной репликацией, если мотив — разная нагрузка на чтение и запись. Event Sourcing — отдельное решение про аудит, историю и воспроизведение состояния; часто сочетается с CQRS, но это не следствие «по умолчанию».

Что фиксировать: допустимая задержка репликации read-модели (eventual consistency для чтения); какие экраны требуют read-your-writes, какие терпят задержку.

Outbox

Атомарная запись бизнес-данных и записи «исходящего события» в таблицу outbox в одной локальной транзакции; отдельный механизм публикует запись в брокер. Устраняет dual-write. Публикация из outbox — часть event-driven цепочки; топология и контракты событий — 03.05.06 Event-Driven Architecture.

Polling vs CDC (критерии для SRS/ADR, без привязки к конкретному инструменту):

  • Polling достаточен, если допустима задержка публикации в секундах–минутах, объём outbox умеренный, команда готова мониторить lag и нагрузку периодических SELECT;
  • CDC уместен, если нужна низкая задержка (субсекунды), высокий throughput, критичен контроль нагрузки на БД без частых poll-запросов; эксплуатация сложнее, в ADR фиксируйте SLA задержки публикации и алерты на lag.

Доставка — at-least-once на стороне брокера. На стороне consumer — Inbox (таблица или dedup store уже обработанных event id): перед бизнес-логикой проверка «обрабатывали ли уже»; без Inbox и идемпотентности получите дубли заказов и платежей. Требования к ключам — в контракте consumer, 10.01.07 Шаблон спецификации Consumer (Kafka, RabbitMQ) и 03.05.03 Спецификации контрактов (OpenAPI, AsyncAPI, Protobuf); producer — 10.01.06 Шаблон спецификации Producer (Kafka, RabbitMQ), 03.05.04 Асинхронное взаимодействие (очереди, Kafka, Events).

Альтернатива без outbox-таблицы — Polling Publisher (периодический опрос изменений в основной таблице): проще внедрить, но слабее гарантии атомарности и выше задержка; компромисс явно согласуйте с заказчиком.

Что фиксировать: семантика доставки; Inbox/dedup на consumer; идемпотентность обработки; порядок событий (ordering) где критичен; SLA задержки публикации; мониторинг «застрявших» записей в outbox.

Bulkhead (переборка)

Изоляция пулов ресурсов по зависимостям: сбой или перегрузка одной зависимости не исчерпывает все потоки.

Что фиксировать: критичность зависимостей; лимиты и поведение при исчерпании пула (очередь vs отказ); связка с Circuit Breaker там, где нужен fail fast после исчерпания.

Strangler Fig (душитель)

Постепенная замена legacy: Intercept → Replace → Redirect → Retire. Новый функционал — в новых сервисах, трафик переключается по маршрутам.

Что фиксировать: карта маршрутов по релизам; контракты на границе legacy/new при перехвате трафика — 03.01.04 Интерфейсы и интеграционные взаимодействия; критерии parity с монолитом; план отключения legacy; границы bounded context — 10.02 Разбор кейса "Миграция legacy-системы", 03.06.02 Основы Domain-Driven Design.

Согласованность и идемпотентность (сквозные темы, не отдельные «паттерны»)

Eventual consistency — при отсутствии новых записей все реплики сходятся к одному значению; между запись и чтение возможен лаг. Приемлема для каталога, рекомендаций, профиля с некритичной задержкой. Неприемлема без явных правил — для баланса, остатков со строгим учётом, бронирования единственного ресурса. Формулировки измеримых порогов — в 08.02 Нефункциональные требования (НФТ) — классификация и стандарты.

Идемпотентность обязательна там, где возможны retry: шаги Saga, компенсации, consumer Outbox/Inbox, POST платежей и создания заказов. Детали HTTP и ключей — 03.05.02 Синхронные протоколы (REST, gRPC, GraphQL), 07.02 Работа с API (практика).

3. Как применяется в работе аналитика

Точка входа — симптом из инцидента, NFR-воркшопа или архитектурного ревью → таблица выбора ниже → фиксация в 10.01.13 Шаблон архитектурного решения (ADR) с последствиями для НФТ.

Рамка выбора паттерна

Симптом / рискПаттерн(ы)Что описать в SRS / ADR / NFR
Бизнес-операция затрагивает несколько сервисов, 2PC недоступенSagaШаги, компенсации, failed compensation, correlation id, идемпотентность, eventual consistency между шагами
Dual-write: БД + брокер без общей транзакцииOutbox (+ Inbox на consumer)At-least-once, polling vs CDC, SLA lag публикации, dedup по event id, мониторинг outbox
Каскадные тайм-ауты при падении зависимостиCircuit Breaker, BulkheadПороги CB; бизнес-fallback; изоляция пулов
Одна зависимость исчерпывает все потоки / thread poolBulkheadЛимиты по зависимости; поведение при saturation; связка с CB
Support не может проследить заказ через N сервисовDistributed tracing, correlation idPropagation id gateway → saga → логи; требования observability в NFR
Разная нагрузка на чтение и записьCQRS (+ ES при аудите)SLA lag read-модели; read-your-writes для сценариев; ES — только если нужна история
Полный аудит «как пришли к состоянию»Event SourcingКаталог событий, версии, snapshots, upcasting
Много внешних клиентов, единый входAPI Gateway / BFFМаршруты, auth, rate limit, выбор один vs BFF по каналам
Единые политики service-to-service на сотнях сервисовService MeshRetry/timeout на mesh vs в коде; tracing; mTLS; sidecar как носитель политик
Миграция монолита без big bangStrangler FigМаршрутизация по релизам, контракты на границе, parity, retire plan

Решение фиксируйте в ADR: контекст, выбранный паттерн, отвергнутые альтернативы (например 2PC vs Saga, sync publish vs Outbox, polling vs CDC), последствия для НФТ.

Вопросы на архитектурное ревью

  • Какой бизнес-инвариант должен выполняться после сбоя на шаге N Saga?
  • Что делать, если компенсация не удалась — retry, эскалация, ручной runbook, блокировка?
  • Как пользователь видит промежуточное состояние (оплата прошла, доставка ещё нет)?
  • Что происходит при повторной доставке того же события из Outbox — есть ли Inbox/dedup на consumer?
  • Какой fallback при open circuit для оплаты — можно ли завершить заказ?
  • Где проходит correlation id от API Gateway через Saga до логов поддержки?
  • Database per service соблюдён или есть shared DB — и как это ломает границы?
  • Кто владеет моделью процесса при orchestrated Saga — 03.04.01 BPMN 2.0 - введение и основы?
  • Какой SLA задержки публикации из outbox и кто алертит на lag?

Связка паттернов

flowchart TB
  GW[API Gateway] --> S1[Service A]
  S1 -->|local TX + outbox| DB1[(DB A)]
  OUT[Outbox poller / CDC] --> K[Event bus]
  K -->|choreography| S2[Service B]
  K -->|choreography| S3[Service C]
  ORCH[Orchestrator] -.->|commands| S2
  ORCH -.->|commands| S3
  S2 -->|on failure| COMP[Compensation]
  S3 -->|on failure| COMP
  MESH[Service Mesh / sidecar] -.-> S1
  MESH -.-> S2
  MESH -.-> S3

Типовая цепочка: Gateway принимает запрос → сервис A в одной транзакции пишет данные и outbox → poller/CDC публикует событие → шаги Saga идут через хореографию (реакция на события) или оркестратор (явные команды) → mesh обеспечивает retry/timeout/CB между сервисами → при сбое — компенсации; consumer ведёт Inbox для dedup.

4. Типовые ошибки и ограничения

ОшибкаПочему опасноКак избежать
«Saga = ACID между сервисами»Ложные ожидания заказчика, неверные критерии приёмкиРазделять бизнес-инварианты и модель согласованности read-моделей
Saga без сценария failed compensation«Застрявшие» процессы, ручной разбор после первого инцидентаRetry, эскалация, runbook, статус в UI — в AC и ADR
Outbox без Inbox/идемпотентности consumerДубли заказов и списаний при at-least-onceevent id / idempotency key и dedup store в 10.01.07 Шаблон спецификации Consumer (Kafka, RabbitMQ)
«CQRS ⇒ Event Sourcing»Лишняя сложность без потребности в аудитеCQRS с read replica; ES — отдельное решение
Circuit Breaker только как «503»Неопределённое поведение для бизнеса и UXСценарии деградации в Use Case / 02.04.02 Критерии приёмки (Acceptance Criteria)
Event Sourcing «статус = последнее событие»Неверная модель для state machineРедукция по типам; тест-кейсы на порядок событий — 08.03 Тестирование требований (статическое тестирование)
Gateway «обязателен от 5 сервисов»Спорное решение без контекстаКритерии: клиенты, edge security, агрегация
Общая БД на несколько сервисовНевозможны независимые Saga/Outbox/ESDatabase per service в границах декомпозиции
Паттерн ради паттернаОперационная сложность без выигрышаADR с отвергнутыми альтернативами и измеримым симптомом

Пустые формулировки заменяйте вопросами: не «нужна зрелая DevOps-культура», а «кто владеет runbook оркестратора Saga, какой RTO, кто on-call». Не «продуманная стратегия компенсаций», а таблица шаг → компенсация → инициатор → идемпотентный ключ → действие при failed compensation.

Детали протоколов, Kafka, OpenAPI, rate limiting и балансировки сознательно не разворачиваются здесь — см. 03.05.01 Виды интеграции (точка-точка, ESB, API-led), 03.05.06 Event-Driven Architecture, 03.06.03 Rate Limiting — управление пропускной способностью, 03.06.04 Стратегии балансировки нагрузки.

Связи с другими разделами базы

Источники и дополнительные материалы

Книги и стандарты

  • Chris Richardson — Microservices Patterns (Saga, Outbox, Gateway, CQRS, Event Sourcing)
  • Sam Newman — Building Microservices (Gateway, Service Mesh, Strangler Fig)
  • Martin Fowler — Patterns of Enterprise Application Architecture (базовые паттерны интеграции и persistence; CQRS и Event Sourcing у Fowler — в отдельных статьях, не как ядро POEAA)

Статьи и каталоги паттернов

Спецификации и инструменты (реализации, не теория)