1. 개요

이벤트 소싱은 상태에 대한 변경 사항을 모두 저장하는 개발 패턴이다.

우리는 과거에는 그 결과값을 저장해왔다. 하지만 이벤트 소싱은 순차적으로 발생하는 이벤트를 모두 저장한다.

마틴 파울러 said "애플리케이션의 모든 상태를 순서에 따라 이벤트로 보관"

2. 목적

모든 갱신 이력 로그를 저장하여 해당 로그를 통해 과거 상태로 재구성할 수 있다는 장점이 있다.

로그와 유사한 점이 있지만 분명히 다른 점이 있다. 그것은 로그는 예외나 향후 문제 추적을 위한 각종 정보를 함께 남긴다. 하지만 이벤트 소싱은 철저히 비즈니스 이벤트만 다룬다.

3. 개념

  • 이벤트 소싱은 삽입(insert)의 개념만 있다. 수정(update), 삭제(delete)는 없다. (즉 이들도 삽입의 하나이다)
  • 예를 들어 주문의 경우, 1) 책을 장바구니에 담는다, 2) 다른 책을 추가한다, 3) 그 중 한책을 제거한다, 등의 이벤트가 계속 추가된다.
  • 하지만 이벤트의 수가 엄청 많아지면 최종 값을 얻기 위해 많은 이벤트를 재생해야 한다. 그래서 스냅샷의 개념을 도입한다.
  • 저장소는 특정 기술이나 제품과 관련없다. RDBMS든 NoSQL이든 무관하다.

핵심을 다시 정리하자면 Immutable, Append Only다.

4. 구성

  • 이벤트 식별자 (에그리것 ID)
  • 이벤트 타입
  • 이벤트 버전
  • 발생시간
  • 내용 (페이로드)

5. 저장소

모든 이벤트는 순서대로 "영구"적인 저장소에 보관된다.

이벤트 스토어는 파일, NoSQL, RDBMS 뭐든 무관하다.

6. 장점

  • 저장소 확장이 용이하다. 데이터베이스 분할을 위한 유일한 키는 해당 집합체의 식별자이다.
  • 도메인 이벤트를 수정하기 위한 수정, 삭제가 없기 때문에 데이터 접근을 위한 경쟁이 없다. 따라서 동시성에 자유롭다.
  • 성능 : 저장 operation만 존재하기 때문에 성능이 좋다.

7. 단점

  • 조회 요구에 적합치 않다. 이에 대한 보완재는 스냅샷과 CQRS이다 (Command와 Query의 책임을 분리하는 패턴이다)
    예: 특정 계좌에 1,000개 이상의 이벤트가 저장되어 있음
          ▶ 계좌의 현재 상태를 알기 위해서는 매번 1,000개 이상의 이벤트를 리플레이
          ▶ 저장된 이벤트 수에 비례하여 리플레이 타임 증가
  • 아직 개발자들이 익숙치 않다.
  • 관련 도구가 부족하다.
  • 단순한 모델이면 배보다 배꼽이 더 커진다.

8. 스냅샷

이벤트 식별자(에그리것 ID), 이벤트 버전, 리플레이된 도메인 객체 로 구성된다.

스냅샷은 이벤트 스토어와 분리된 저장소에 저장하고, 가급적 성능이 좋은 저장소(인메모리 등)를 사용한다.

9. 흐름

  1. 요청 (커맨트 객체 생성 + Validation)
  2. 커맨드 핸들러
  3. Query인 경우 : 애그리것 생성 ▶ 이벤트 조회 (이벤트 스토어) ▶ 스냅샷 조회 & 병합 ▶ 이벤트 리플레이
    Command인 경우 : 이벤트 저장 (이벤트 스토어) ▶ 스냅샷 저장 (스냅샷 저장소)