Event Sourcing: Архитектура на источниках событий за 14 минут

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

Сущности и события

Системы обычно описываются как совокупность сущностей (entities), хранящих состояние, и событий (events), отражающих изменения этих сущностей. События часто инициируются командами (commands) от пользователей, фоновых процессов или внешних систем.

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

<img src=»placeholder_image.jpg» alt=»Сравнение хранилища событий (Event Store) и хранилища сущностей (Entity Store)»>

Например, в хранилище сущностей банковский аккаунт хранится с текущим балансом (20 условных единиц). В Event Sourcing хранится история событий: начисление (100 условных единиц) и списание (80 условных единиц). Текущее состояние (баланс 20) вычисляется на основе этой истории.

Преимущества

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

  • Уменьшение несоответствия импеданса: Позволяет технологическим командам и бизнесу говорить на одном языке, так как бизнес часто мыслит событиями, а не сущностями.
  • Разделение ответственности (CQRS): Позволяет оптимизировать запись и чтение данных независимо друг от друга.
  • История изменений: Обеспечивает доступ к истории изменений системы, позволяя ответить на вопросы о её состоянии в прошлом.

Пример с банковским счётом

Рассмотрим пример с банковским счётом. Сущность — банковский счёт (Bank Account) с текущим балансом (20). Доступны команды: внесение денег (deposit) и снятие денег (withdraw). Бизнес-правило: снятие возможно, если сумма не превышает баланс.

События:

  • Account credited: счёт пополнен.
  • Account debited: средства списаны.

Последовательность команд:

  1. deposit amount 100
  2. withdraw amount 80
  3. withdraw amount 50 (эта команда не будет выполнена из-за недостаточных средств)

Журнал событий (Event Log) будет содержать только успешные операции:

<img src=»placeholder_image.jpg» alt=»Пример журнала событий»>

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

В реальной системе потребуется:

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

<img src=»placeholder_image.jpg» alt=»Сравнение хранилища событий и производного хранилища»>

Реализация

Для Event Sourcing необходима реализация записи и чтения событий. Варианты хранилища событий:

  • Файлы (простое решение).
  • Брокеры сообщений, системы обработки потоков событий (для больших систем).
  • Реляционные и документные базы данных (часто используются совместно с Event Sourcing).

В сложных системах применяются производные хранилища состояния для оптимизации чтения. Это соответствует принципу CQRS (Command Query Responsibility Segregation). Запросы направляются в производное хранилище, что позволяет оптимизировать его независимо от операций записи.

Проблемы и сложности

Несмотря на преимущества, Event Sourcing имеет сложности:

  • Изменение мышления разработчиков: Необходимо сфокусироваться на событиях, а не сущностях.
  • Неизменяемость событий: После записи события считаются неизменными.
  • Полная информация в событиях: События должны содержать всю необходимую информацию для восстановления состояния.
  • Повторная интерпретация событий: Системы и бизнес-правила могут меняться.
  • Обработка ошибочных событий: Необходимо корректно обрабатывать и валидировать данные.
  • Сложности интеграции с внешними системами.
  • Масштабируемость: Горизонтальное масштабирование журнала событий может приводить к асинхронной обработке и проблемам согласованности данных (eventually consistent).
  • Время обработки команд: Необходимо учитывать задержку между командой и записью события.
  • Обработка ошибок команд.
  • Обработка большого количества событий: Повторная обработка всего журнала событий может быть трудоёмкой. Периодические снимки состояния (snapshots) помогают в этом.
  • Изменение структуры событий: Необходимо учитывать эволюцию структуры событий и обеспечить совместимость со старыми событиями.

Выводы

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

Что будем искать? Например,программа