DBAtlas · Атлас эксплуатации баз данных

Эталонная архитектура: Событийно-ориентированная / CQRS

В событийно-ориентированной архитектуре сервисы не вызывают друг друга напрямую, а публикуют события в журнал событий (например, Kafka), а потребители обрабатывают их асинхронно. Начиная с построения событийной магистрали, это дерево шаг за шагом проходит через event sourcing (получение состояния из событий), разделение команд и запросов с CQRS, проекцию модели чтения, идемпотентность, допустимость eventual consistency и заблуждение «доставки exactly-once». Цель — слабо связанная, масштабируемая система, компромиссы согласованности которой хорошо понятны.

Какое решение стоит перед вами в событийно-ориентированной архитектуре?

Основа событийно-ориентированной системы — надёжный журнал событий, связывающий сервисы асинхронными событиями. Вы ещё строите магистраль, хотите получать состояние из событий (event sourcing) или разделяете пути чтения и записи (CQRS)?

  • Я строю событийную магистраль, связывающую сервисы
  • Я хочу получать состояние из истории событий
  • Я хочу разделить пути чтения и записи (CQRS)

Как вы построите сторону чтения в CQRS и какова ваша допустимость рассогласования?

В CQRS стороны команд (запись) и запросов (чтение) разделены; события записи обновляют проекцию, наполняющую модель чтения. Ключевой вопрос: допустимо ли отставание модели чтения от записей (eventual consistency) или вы ожидаете, что каждое событие будет обработано ровно один раз?

  • Я буду наполнять модель чтения из событий через проекцию
  • Чтение должно быть актуальным; отставание недопустимо
  • Я хочу, чтобы события обрабатывались «ровно один раз»

Рекомендация: надёжный журнал событий как основа системы

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

Рекомендация: Event sourcing (получение состояния из событий)

В event sourcing хранится не текущее состояние сущности, а все применённые к ней (неизменяемые) события изменений; текущее состояние получается последовательным применением этих событий. Это даёт полную историю аудита и возможность вернуться к любому моменту в прошлом.

Рекомендация: проекция модели чтения

В CQRS сторона записи порождает события; проекция слушает эти события и обновляет оптимизированную под запросы модель чтения (денормализованное представление). Чтение обслуживается из этой готовой модели, полностью отделённой от пути записи, и обе стороны масштабируются независимо.

Рекомендация: проектируйте с учётом eventual consistency

В событийно-ориентированных/CQRS-системах модель чтения немного отстаёт от записей (eventual consistency). Вместо попыток это «устранить» проектируйте так, чтобы это допускать; немногие потоки, требующие строгой немедленной согласованности, держите отдельно.

Рекомендация: идемпотентность (миф об exactly-once)

В распределённом обмене сообщениями сквозная «доставка exactly-once» на практике — заблуждение; дубликаты сообщений неизбежны из-за сети и повторных попыток. Правильная цель — идемпотентная обработка: двукратная обработка одного события должна давать тот же результат, что и однократная.

Открыть в DBAtlas →