System Design Space
Граф знанийНастройки

Обновлено: 23 июня 2026 г. в 00:19

Событийно-ориентированная архитектура

средний

Практический разбор событийной архитектуры: где действительно нужны хранение состояния через события, разделение команд и чтения, долгие бизнес-процессы и очередь ошибочных сообщений.

Событийная архитектура ценна не абстрактным обещанием слабой связности, а тем, что позволяет разнести принятие решения, публикацию факта и реакцию зависимых сервисов во времени.

Глава раскладывает хранение состояния через события, разделение команд и чтения и долгие бизнес-процессы на отдельные инженерные решения, чтобы было видно, где асинхронность действительно упрощает систему, а где она приносит эволюцию схем, повторное воспроизведение, лаги согласования и более дорогую эксплуатацию.

В инженерных обсуждениях это помогает спокойно разбирать оркестрацию и хореографию, границы событий, зависающие процессы и цену асинхронности без наивной идеи, что один брокер автоматически сделает систему гибче.

Практическая польза главы

Контракты событий

Проектируйте события как устойчивые бизнес-факты с совместимой эволюцией схем, а не как случайные транспортные пакеты.

Координация шагов

Осознанно выбирайте между оркестрацией и хореографией и заранее фиксируйте, где нужен явный управляющий контур.

Повторы и проблемные сообщения

Планируйте повторное воспроизведение, и идемпотентность обработчиков так, чтобы сбой не превращался в потерю данных.

Аргументация выбора

Объясняйте, когда события действительно снижают связанность, а когда они только добавляют лаги и операционную сложность.

Источник

Martin Fowler: Event Sourcing

Классический текст о том, зачем хранить историю состояния через события и где этот подход действительно полезен.

Открыть материал

окупается не из-за самого брокера, а из-за того, что момент принятия решения и момент реакции на него больше не обязаны совпадать во времени. Эта развязка даёт масштабируемость и слабую связность, но цена за неё конкретная: события, контракты и восстановление после сбоев приходится проектировать заранее, иначе развязка превращается в источник скрытых отказов.

Базовые принципы событийной архитектуры

В этой главе мы отдельно разберём , и . Это не обязательный комплект на все случаи, а три разных инструмента, которые по-разному помогают управлять историей изменений, нагрузкой на чтение и запись и длинными бизнес-процессами.

Прежде чем выбирать инструмент, стоит закрыть базовый словарь — иначе спор уходит в термины, а не в решение. Договоритесь, что считается , как устроены и , когда требуется и какую роль играют , и , и где действительно нужен . Если система живёт с , доставкой , , , и , то эти решения нужно принимать отдельно внутри каждого , а не размазывать один и тот же шаблон на всю систему.

Событие фиксирует факт

Событие описывает то, что уже произошло в домене, и не должно меняться задним числом.

Асинхронность разрывает связность

Производители и потребители могут развиваться отдельно, если контракт события остаётся стабильным.

Согласование приходит не мгновенно

Между записью и итоговым видом данных есть лаг. Если продукт и API не закладывают его явно, пользователь увидит «свой» заказ ещё не обновлённым — и решит, что система потеряла данные.

Визуализация потоков данных

Ниже показаны три характерных сценария: базовый событийный поток, разделение чтения и записи в и координация шагов в .

Анимации потоков данных

Каждую схему можно запускать отдельно кнопкой «Старт».

Базовый поток событий

1

API команд

Принимает бизнес-команду

2

Доменный агрегат

Проверяет инварианты и принимает решение

3

Хранилище событий

Последовательно записывает события

4

Брокер или журнал

Раздаёт события потребителям

5

Потребители

Строят проекции, интеграции и побочные действия

CQRS: путь записи и путь чтения

Обе ветки показаны параллельно и запускаются независимо.

Путь записи

1

Клиент

Отправляет команду POST или PUT

2

Модель команд

Применяет правила и инварианты

3

Поток событий

Фиксирует факты домена

4

Проектор

Обновляет модель чтения

Путь чтения

1

Клиент

Отправляет запрос GET

2

API чтения

Отдаёт только данные для чтения

3

Модель чтения

Хранит денормализованную проекцию

Saga: стили координации

Отдельный координатор решает, какой шаг запускать дальше и когда начинать компенсации.

Все ключевые команды и решения проходят через одного координатора.

Сервис заказов

OrderCreated

Оркестратор
Оркестратор

ReserveFunds

Платёжный сервис
Платёжный сервис

PaymentReserved

Оркестратор
Оркестратор

ReserveStock

Сервис склада
Сервис склада

InventoryReserved

Оркестратор
Оркестратор

CreateShipment

Сервис доставки
Сервис доставки

ShipmentCreated

Оркестратор
Оркестратор

OrderCompleted

Сервис заказов
Ключевая идея: один координатор принимает решения и управляет вызовами сервисов.

Связанная глава

Microservice Patterns

Отдельная глава про интеграционные паттерны, паттерн Saga и границы распределённых транзакций.

Открыть главу

Хранение состояния через события (Event Sourcing), разделение команд и чтения (CQRS) и паттерн Saga (saga pattern)

Event Sourcing

Состояние восстанавливается из последовательности событий, а не хранится только как последнее значение.

Когда применять

  • Нужен полный журнал аудита и воспроизводимая история изменений.
  • Важно пересчитывать проекции или строить новые представления данных по истории событий.
  • Предметная область естественно описывается через факты, которые произошли во времени.

Компромиссы

  • Сложнее эволюция схемы событий и миграции старой истории.
  • Нужны снимки состояния и стратегия повторного воспроизведения, чтобы не замедлить систему.

CQRS

Путь записи и путь чтения разделяются, чтобы каждый из них оптимизировать под свою нагрузку и модель данных.

Когда применять

  • Нагрузка на чтение и запись заметно различается.
  • Нужны отдельные проекции, оптимизированные под быстрые чтения.
  • Система выросла настолько, что пути чтения и записи выгодно масштабировать независимо.

Компромиссы

  • Увеличиваются операционная сложность и число компонентов.
  • Модель чтения часто сходится с путём записи не мгновенно, а с лагом.

Saga

Распределённая операция раскладывается на локальные шаги и компенсирующие действия вместо одной общей транзакции.

Когда применять

  • Одна бизнес-операция затрагивает несколько сервисов или хранилищ.
  • Двухфазная фиксация (two-phase commit) недоступна или слишком дорога по задержке и связанности.
  • Нужно управляемо откатывать частично завершённый процесс через компенсации.

Компромиссы

  • Каждый шаг и каждая компенсация должны переживать повторы без двойного эффекта.
  • Отладка долгоживущих и частично завершённых процессов становится сложнее.

Связанная книга

Software Architecture: The Hard Parts

Подробный разбор инженерных компромиссов, распределённых процессов и практики применения Saga.

Открыть главу

Saga: стили координации

делает процесс прозрачнее и централизует решения, а сильнее ослабляет связанность, но сложнее для трассировки и отладки.

Хореография

Сервисы подписываются на события и сами запускают следующий шаг без центрального координатора.

Плюсы

  • Слабее связность между сервисами
  • Нет единой управляющей точки, которая станет узким местом

Риски

  • Сложнее проследить весь путь операции целиком
  • Легко получить хаотичную сеть событий без явных границ

Оркестрация

Отдельный координатор явно решает, какой шаг выполнять дальше и когда запускать компенсации.

Плюсы

  • Проще наблюдать процесс целиком
  • Легче проверять бизнес-логику и правила переходов

Риски

  • Появляется центральная точка сложности
  • Контур оркестрации нужно отдельно масштабировать и защищать

Как выбирать паттерн

ЗадачаЧто выбратьПочему
Нужна полная история изменений и восстановление состоянияEvent SourcingИстория становится первичными данными, а не побочным журналом.
К чтению и записи предъявляются разные требования по уровню сервиса и профилю нагрузкиCQRSМожно отдельно оптимизировать и масштабировать путь чтения и путь записи.
Одна операция охватывает несколько сервисов без общей транзакцииSagaЛокальные шаги и компенсации дают контролируемое завершение процесса.
Система остаётся простой CRUD-моделью без сложных интеграцийНе навязывать событийную архитектуруОперационная сложность может оказаться выше реальной бизнес-пользы.

Частые ошибки

  • Внедрять хранение состояния через события (Event Sourcing), разделение команд и чтения (CQRS) и паттерн Saga (saga pattern) одновременно без явной проблемы, которую нужно решить.
  • Публиковать в события технический шум вместо фактов предметной области.
  • Не проектировать идемпотентность обработчиков при доставке как минимум один раз.
  • Оставлять эволюцию схемы событий без политики обратной совместимости.
  • Не следить за проблемными сообщениями, лагом обработки, скоростью роста дублей и временем завершения процесса: паттерн Saga (saga pattern).

Связанная глава

Паттерны отказоустойчивости

Очередь ошибочных сообщений дополняет повторы, тайм-ауты и изоляцию сбоев в контурах асинхронной обработки.

Открыть главу

Очередь ошибочных сообщений

нужна не для того, чтобы спрятать сбой, а чтобы безопасно изолировать проблемные сообщения, разобраться в причине и вернуть их в поток контролируемо. Она особенно важна там, где обработчик работает с внешними зависимостями, нестабильными данными или дорогими побочными эффектами.

Когда изолировать сообщение

Сообщение исчерпало лимит повторов, нарушает контракт события или стабильно падает из-за самих данных — повторять его дальше бессмысленно, оно только держит партицию.

Что сохранять

Идентификатор сообщения, число попыток, последнюю ошибку, источник, время сбоя и ссылку на полезную нагрузку.

Что делать дальше

Разобрать причину, исправить её и вернуть сообщения в основной поток с контролем скорости и идемпотентности.

Практический чеклист для проблемных сообщений

  • Выделяйте отдельную очередь ошибочных сообщений для каждого критичного потока, чтобы не смешивать домены и приоритеты.
  • Сохраняйте причину ошибки, число попыток, исходный топик или очередь и ссылку на полезную нагрузку для расследования.
  • Разделяйте временные и постоянные ошибки: не все сообщения должны уходить в изоляцию после одинакового числа повторов.
  • Настройте процесс возврата сообщений в основной поток после исправления причины сбоя: вручную или автоматически.
  • Следите за скоростью роста проблемных сообщений и договоритесь о целевом времени их разбора.

Проверки перед внедрением

1. Зафиксируйте контракты событий и политику версионирования.
2. Обеспечьте идемпотентность и у производителей, и у обработчиков.
3. Настройте очередь ошибочных сообщений, правила повторов и процесс возврата сообщений.
4. Следите за лагом обработки, временем воспроизведения и завершением Saga.

Практический подход: начните с одного-двух критичных процессов, сначала зафиксируйте контракт, наблюдаемость и правила повторов, и только потом масштабируйте событийную модель на остальные контуры системы.

Сначала контракт и операционная дисциплинапотом расширение событийной архитектуры.

Связанные главы

Чтобы отмечать прохождение, включи трекинг в Настройки