이벤트 소싱(Event Sourcing)은 시스템 상태를 현재 상태 스냅샷 대신 이벤트의 시퀀스로 저장하는 패턴이다. 현재 상태는 모든 이벤트를 재생(replay)해서 도출한다.
전통적 방식 vs 이벤트 소싱
전통적 방식 (CRUD):
accounts 테이블: id=1, balance=500
→ 이전 잔액을 알 수 없음, 변경 이력 없음
이벤트 소싱:
events 테이블:
id=1, AccountOpened, balance=0
id=2, MoneyDeposited, amount=1000
id=3, MoneyWithdrawn, amount=500
→ 현재 잔액 = 0 + 1000 - 500 = 500
→ 전체 히스토리 보존
구현 예시
python
from dataclasses import dataclass
from datetime import datetime
@dataclass
class Event:
aggregate_id: str
event_type: str
data: dict
timestamp: datetime = None
class Account:
def __init__(self):
self.balance = 0
self._events = []
def deposit(self, amount):
if amount <= 0:
raise ValueError("양수만 가능")
event = Event("acc1", "MoneyDeposited", {"amount": amount})
self._apply(event)
self._events.append(event)
def _apply(self, event):
if event.event_type == "AccountOpened":
self.balance = 0
elif event.event_type == "MoneyDeposited":
self.balance += event.data["amount"]
elif event.event_type == "MoneyWithdrawn":
self.balance -= event.data["amount"]
@classmethod
def from_events(cls, events):
acc = cls()
for e in events:
acc._apply(e)
return acc
장단점
| 장점 | 단점 |
|---|
| 완전한 감사 추적(Audit Trail) | 조회 복잡도 증가 |
| 과거 상태 재현 가능 | 이벤트 스키마 변경 어려움 |
| 버그 재현 및 디버깅 용이 | 이벤트 수 많아지면 재생 느려짐 |
| 이벤트 스트림으로 다른 시스템과 통합 | 스냅샷 필요 (성능) |
스냅샷 (Snapshot)
재생 비용 감소를 위해 특정 시점의 상태를 저장하고, 그 이후 이벤트만 재생.
관련 개념