Ответ
Event Sourcing (источники событий) — это архитектурный паттерн, при котором состояние системы реконструируется путем последовательного применения всех произошедших событий. Вместо хранения текущего состояния (state), система хранит полную историю изменений в виде неизменяемых событий.
Ключевые принципы:
- Все изменения — это события. Любая операция, изменяющая состояние (например,
UserRegistered,OrderPlaced), сохраняется как отдельное событие в хранилище. - События неизменяемы (immutable). Однажды записанное событие никогда не изменяется и не удаляется. Для отмены используется компенсирующее событие (например,
OrderCancelled). - Состояние — это проекция событий. Текущее состояние объекта (например, баланс счета) получается путем "проигрывания" всех его событий с самого начала.
Упрощенный пример на Python:
# События
class AccountOpened:
def __init__(self, account_id):
self.account_id = account_id
class MoneyDeposited:
def __init__(self, amount):
self.amount = amount
class MoneyWithdrawn:
def __init__(self, amount):
self.amount = amount
# Агрегат (сущность)
class BankAccount:
def __init__(self):
self.id = None
self.balance = 0
def apply(self, event):
"""Применяет событие для изменения состояния"""
if isinstance(event, AccountOpened):
self.id = event.account_id
elif isinstance(event, MoneyDeposited):
self.balance += event.amount
elif isinstance(event, MoneyWithdrawn):
self.balance -= event.amount
@staticmethod
def replay(events):
"""Восстанавливает состояние из списка событий"""
account = BankAccount()
for event in events:
account.apply(event)
return account
# Использование
event_stream = [
AccountOpened(account_id='acc-123'),
MoneyDeposited(amount=100),
MoneyWithdrawn(amount=30)
]
# Восстанавливаем текущее состояние
current_account_state = BankAccount.replay(event_stream)
print(f"Account ID: {current_account_state.id}, Balance: {current_account_state.balance}")
# -> Account ID: acc-123, Balance: 70
Преимущества:
- Полный аудит: Легко отследить, как система пришла в текущее состояние.
- Отладка и "путешествия во времени": Возможность восстановить состояние на любой момент времени.
- Гибкость: Можно создавать новые проекции данных (read models) из существующего потока событий, не меняя основную логику.
Недостатки:
- Сложность реализации: Требует иного подхода к проектированию по сравнению с традиционным CRUD.
- Согласованность в конечном счете (Eventual Consistency): Часто используется с CQRS, что приводит к задержкам в обновлении моделей для чтения.