Event Sourcing이란?
일반적인 애플리케이션은 데이터베이스에 ‘현재 상태’만 저장합니다. 예를 들어 은행 계좌 잔액이 10만원이면, 테이블에는 그냥 balance = 100000이라는 값 하나만 남습니다. 이전에 얼마가 입금되고 출금됐는지는 기록되지 않고 사라집니다.
Event Sourcing은 이런 방식과 반대로 접근합니다. 상태 자체를 저장하는 대신, 상태를 변화시킨 ‘이벤트’를 순서대로 모두 저장하는 설계 방식입니다. 즉 ‘잔액 10만원’이 아니라 ‘5만원 입금됨’, ‘3만원 출금됨’, ‘8만원 입금됨’ 같은 이벤트들을 시간순으로 쌓아두고, 현재 상태는 이 이벤트들을 처음부터 순서대로 재생(replay)해서 계산해냅니다.
동작 원리: 가계부에 비유하기
Event Sourcing을 이해하는 가장 쉬운 방법은 가계부입니다. 통장 잔액만 적어두는 대신, ‘언제 얼마를 썼다’, ‘언제 얼마를 벌었다’를 하나하나 기록하는 가계부를 떠올려보세요. 잔액이 궁금하면 가계부 첫 페이지부터 모든 항목을 더하고 빼서 계산하면 됩니다.
실제 구현에서는 다음과 같은 흐름을 가집니다.
- 사용자가 ‘주문 생성’, ‘결제 완료’, ‘배송 시작’ 같은 행위를 하면 각각 이벤트로 기록
- 이벤트는 ‘OrderCreated’, ‘PaymentCompleted’, ‘ShippingStarted’처럼 불변(immutable) 데이터로 이벤트 스토어에 저장
- 현재 상태가 필요하면 저장된 이벤트를 순서대로 재생해서 상태를 조립
- 매번 재생하는 비용을 줄이기 위해 특정 시점의 상태를 스냅샷으로 캐싱해두기도 함
여기서 중요한 점은 한 번 저장된 이벤트는 수정하거나 삭제하지 않는다는 것입니다. 잘못된 값이 있었다면 이를 취소하는 새로운 이벤트(‘OrderCancelled’ 등)를 추가로 기록해서 바로잡습니다.
실무에서 왜 쓰는가
Event Sourcing은 구현 복잡도가 높은 편이라 모든 시스템에 적합하지는 않지만, 다음과 같은 상황에서 큰 강점을 발휘합니다.
- 감사(Audit) 추적: 누가 언제 무엇을 바꿨는지 완벽한 이력이 남아 금융, 결제 시스템에 유리
- 디버깅과 재현: 버그가 발생한 시점의 이벤트를 그대로 재생해 원인 분석 가능
- 상태 복원: 이벤트만 있으면 언제든 과거 특정 시점의 상태를 재구성 가능
- CQRS와의 결합: 이벤트를 쓰기(Command) 모델로, 조회 최적화된 뷰를 읽기(Query) 모델로 분리해 확장성 확보
다만 이벤트가 계속 쌓이면서 재생 비용이 늘어나고, 이벤트 스키마 변경 시 과거 이벤트와의 호환성을 고려해야 하는 부담도 있습니다. 그래서 트랜잭션 이력이 핵심 자산인 도메인, 예를 들어 결제, 주문, 재고 관리 시스템에서 특히 많이 채택되는 설계 방식입니다.