Потоковая обработка

Event Sourcing

Клиент звонит: «Почему мой заказ отменён?» В классической БД - загадка: поле status='cancelled', кто и когда его выставил - неизвестно. В Event Sourcing - полная история: OrderPlaced → PaymentFailed (3 попытки) → OrderCancelled. Audit log бесплатно, time travel бесплатно, rebuild любой проекции - рутина.

  • **LinkedIn** использует Event Sourcing для системы уведомлений: возможность перестроить read model без потери истории критична при изменении алгоритмов
  • **Axon Framework** (Java) и **EventStoreDB** - продакшн-инструменты для Event Sourcing, используемые в банках и страховых компаниях
  • **Git** - пример Event Sourcing: commits = события, рабочий каталог = проекция, checkout = rebuild на определённую версию

Event Store: структура и append-only

Обычная база данных хранит текущее состояние: запись обновляется, предыдущее значение теряется. **Event Sourcing** переворачивает это: вместо текущего состояния хранится **полная история изменений** - последовательность событий. Текущее состояние вычисляется из событий на лету.

**Event Store** - это append-only лог: события только добавляются, никогда не изменяются и не удаляются. Каждое событие - факт, который уже произошёл: `OrderPlaced`, `ItemAdded`, `OrderShipped`. Не «установить status='shipped'», а «произошло событие OrderShipped в момент T».

**Superpowers Event Sourcing:** полный audit log бесплатно, возможность «путешествия во времени» (состояние на любой момент прошлого), debug через replay событий, возможность добавить новые проекции ретроспективно.

В Event Sourcing при обновлении заказа (смена адреса доставки) в базе происходит:

Projections: материализованные представления

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

Одни и те же события могут порождать **несколько проекций** для разных целей: одна проекция для UI (текущий статус заказа), другая для аналитики (Revenue по регионам), третья для уведомлений. Добавление новой проекции не требует изменений в event store - достаточно построить её из истории событий.

**CQRS + Event Sourcing:** Command side пишет события, Query side читает проекции. Команды и запросы используют разные модели данных - это ключевой паттерн для масштабируемых систем с Event Sourcing.

Нужно добавить новую проекцию: аналитику по времени обработки заказов. В Event Sourcing это требует:

Snapshots для оптимизации

Агрегат с долгой историей может иметь тысячи событий. Каждый раз проигрывать их все для получения текущего состояния - дорого. **Снапшот** (snapshot) - это сохранённое состояние агрегата на определённой версии событий. При загрузке достаточно взять последний снапшот и применить только события после него.

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

Агрегат имеет снапшот на версии 100 и 30 новых событий (версии 101-130). Сколько событий нужно применить при загрузке?

Rebuilding состояния из событий

Проекция устарела. Завели новое поле в событии, изменили бизнес-логику, обнаружили баг в reducer. Классическая БД требует сложной миграции. Event Sourcing даёт суперспособность: **просто выбросить проекцию и построить заново** из неизменных событий.

**Rebuild (replay)** - это применение всей истории событий к новому или изменённому reducer. При правильной архитектуре rebuild - рутинная операция, а не аварийная ситуация. Системы с Event Sourcing проектируют с расчётом на регулярный rebuild проекций.

**Производительность rebuild:** миллион событий - это минуты, не дни. Event store читается последовательно (оптимально для дисков), batch-обработка распараллеливается по партициям. Kafka как event store позволяет параллельный consumer group rebuild.

Event Sourcing сложен и подходит только для больших систем с большой командой.

Event Sourcing добавляет сложность проекций и снапшотов, но даёт бесплатный audit log, time travel и гибкий rebuild. Оправдан в доменах с высокой ценностью истории: финансы, инвентарь, workflow.

Сложность управляема при правильных инструментах (Kafka, EventStoreDB). Главный вопрос - нужна ли история изменений как первоклассная концепция в вашем домене.

Обнаружена ошибка в логике reducer проекции (неверно считается сумма). Действие в Event Sourcing:

Event Sourcing

  • Event Store: append-only лог событий-фактов; состояние вычисляется из событий, никогда не хранится напрямую
  • Проекции: reducer применяет события к состоянию; одни события порождают множество проекций для разных нужд
  • Снапшоты: оптимизация для агрегатов с долгой историей - снапшот + события после него
  • Rebuild: исправить reducer + перестроить проекцию из истории - killer feature Event Sourcing

Связанные темы

Event Sourcing соединяется с несколькими архитектурными паттернами:

  • Exactly-Once Semantics — Idempotent projections - естественная защита от дублей при replay
  • CQRS — Command side пишет события, Query side читает проекции
  • Kafka: основы — Kafka как event store: retention, consumer groups для rebuild

Вопросы для размышления

  • В каких доменах история изменений ценна настолько, чтобы оправдать сложность Event Sourcing?
  • Как обрабатывать изменение схемы событий (добавление полей) без миграции всего event store?
  • Чем Event Sourcing отличается от CDC (Change Data Capture) - и когда один паттерн предпочтительнее другого?

Связанные уроки

  • dist-07-transactions
Event Sourcing

0

1

Войти