Статьи

Event sourcing и CQRS: архитектура событийных систем для микросервисов

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

Одним из архитектурных паттернов, который помогает решить эти задачи, является Event sourcing в связке с CQRS (Command Query Responsibility Segregation).

Напоминание: что это за подходы

• Event sourcing — состояние системы восстанавливается не из «текущей фотографии» (таблицы в БД), а из истории событий, которые к этому состоянию привели.

• CQRS — разделение логики на две части:

Command side — принимает команды, меняет состояние через генерацию событий.

• Query side — подписывается на события и строит удобные проекции для чтения.


Вместе эти подходы позволяют:

• Легко масштабировать чтение/запись,
• Хранить полную историю изменений,
• Откатывать или пересобирать состояние,
• Гибко интегрировать новые сервисы через события.

Практические инструменты для Java

1. Axon Framework

Фреймворк, который «из коробки» даёт Event sourcing + CQRS.

• Управление агрегатами и событиями.
• Поддержка snapshotting.
• Axon Server (отдельный продукт) для хранения событий и маршрутизации.

Пример агрегата:
Здесь чётко видно разделение: команда → событие → изменение состояния.


Восстановление состояния через события и snapshot

Axon позволяет восстанавливать агрегат либо из всей цепочки событий, либо «срезом» через снапшот.

Пример использования snapshotting:
Axon автоматически создаёт снапшоты (например, каждые 100 событий). При восстановлении агрегата сначала подгружается последний snapshot, а потом только «дельта» событий после него. Это сильно ускоряет реплей и экономит ресурсы.


2. EventStoreDB

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

Как хранятся данные:

• Каждое событие — это append-only запись в поток (stream).
• Поток соответствует агрегату или категории (например, order-123 или orders).
• Событие хранится в виде JSON или protobuf с обязательными метаданными (eventId, eventType, created, metadata).

Пример записи:
В чём оптимизация под event sourcing:

• append-only модель (нет апдейтов, только добавления), что даёт высокую производительность и лёгкий реплей;
• Подписки (catch-up и persistent subscriptions) позволяют обрабатывать события асинхронно и надёжно;
• Оптимизированная запись в потоки с возможностью репликации и шардинга.


3. Kafka

Kafka — это не event store в чистом виде, но она идеально подходит для потоковой обработки событий и интеграции микросервисов.

Классическая схема:

• Command side публикует событие в топик Kafka.
• Query side подписывается и обновляет проекции.


Важно про масштабирование:

• Kafka масштабируется по числу партиций.

• Каждая партиция читается только одним consumer в группе → если не продумать стратегию партиционирования, система упрётся в ограничение по throughput.

• Хорошая практика: ключ партиционирования = идентификатор агрегата (orderId, userId).

Это гарантирует, что все события одного агрегата попадут в одну партицию, сохраняя порядок.

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

Где чаще всего спотыкаются

1. Путают команды и события.
Команда — это «намерение», событие — это «свершившийся факт». Если команда не может быть выполнена, событие не возникает.

2. Хранят только текущее состояние.
Тогда теряется сама суть event sourcing: история. Восстановление после ошибок становится невозможным.

3. Не продумывают проекции.
Query side нужен для быстрого чтения. Если сразу не продумать проекции, то нагрузка на систему возрастает, а ответы на запросы становятся медленными.

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

Event sourcing + CQRS дают надёжную основу для построения микросервисных систем, где важны масштабируемость, история изменений и гибкая интеграция.

В экосистеме Java для этого уже есть зрелые инструменты:

• Axon Framework для полной реализации паттерна;
• EventStoreDB как специализированный event store;
• Kafka для потоковой обработки и интеграции.

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


Хотите узнать больше? Изучите другие статьи из разделов:
2025-10-01 11:46 Java Базы данных DevOps