1. 개요

1.1. 개념

이벤트 소싱 패턴은 도메인 내부 데이터의 현재 상태 그대로 저장하는 방식 대신에, 데이터에 수행된 전체 작업을 덧붙이는 방식으로 저장한다. 다시 말해, 이벤트 소싱은 애플리케이션에 의한 상태 변화를 변경 불가능한 연속된 사건들 또는 일어난 사건에 대한 로그를 통해 표현한다. 이벤트 소싱에서 특정 상태가 필요한 경우 집계(Aggregate)를 통해 이벤트에 대한 리플레이를 수행하여 상태를 생성하게끔 한다. 

< 이벤트 >

  • 과거에 일어난 사건, ex) 좌석이 예약됨, 10000원이 출금 됨
  • 이벤트는 변경 불가능(Immutable) → 상태를 보정하는 다른 이벤트를 수행해야함 ex) 좌석이 예약됨 + 좌석 예약이 취소됨
  • 이벤트는 단방향 메시지: Publisher(1)와 Subscriber(N) 존재

< 집계/집합체(Aggregate) >

  • 일반적인 CRUD 모델에서는 현재의 상태를 직접 DB에 쿼리하지만, 이벤트소싱 패턴을 사용 한 경우 이벤트 스토어에는 해당 리소스와 연관된 이벤트 모음만 저장되어 있다.  따라서, 현재의 상태를 얻기 위해서 수행된 이벤트를 리플레이하여야 한다. 
  • 집계/집합체(Aggregate)는 이러한 작업을 수행하는 요소이다. 

< 스냅샷 >

  • 이벤트를 지속적으로 저장하게 되면, 오랫동안 살아남은 도메인 오브젝트의 경우 엄청난 갯수의 이벤트를 가지며, 성능과 용량에 영향을 미치게 된다. 이를 해결하기 위해 별도의 스냅샷 저장소를 두고 특정 시점의 스냅샷을 저장

1.2. ORM(Object-Relation Mapping)과 Event Sourcing 비교 예시

일반적인 ORM 레이어를 통해 요청을 처리하는 과정은 아래와 같다. 

  1. 사용자가 좌석 2개 예약 요청을 Command Handler에 전달
  2. Aggregate가 ORM Layer에 SeatsAvailability 정보를 요청하고, ORM Layer는 DB에 쿼리를 보내 데이터 조회
  3. Command Handler가 Aggregate 인스턴스에 예약을 수행 할 것을 명령
  4. Aggregate가 ORM Layer에 상태 저장 요청
  5. ORM Layer가 DB에 업데이트 수행

1.3. Event Sourcing 

  • 사용자가 좌석 2개 예약 요청을 Command Handler 에 전달
  • Aggregate 인스턴스가 예약 및 취소를 설명하는 이벤트를 쿼리하여 회의에 대한 모든 예약 정보를 포함하는 집계가 생성
  • Command Handler가 Aggregate 인스턴스를 호출하여 예약 수행 명령
  • SeatsAvailability aggregate가 도메인 로직을 수행 ex)이벤트를 통해 남아있는 좌석 수 계산 
  • 해당 좌석에 대한 이벤트 저장소에 새로운 이벤트 추가  

장점은 다음과 같다.

  • 확장성 - 동일한 이벤트에 대해 미래에 애플리케이션을 추가하는 것이 가능
  • 데이터 모델과 비즈니스 모델의 동기화 불필요 - 이벤트 로그를 통해 추적이 가능함
  • 모든 이벤트가 로깅되므로 트러블슈팅 용이
  • 애플리케이션의 Resiliency 향상 - 롤백 용이
  • 성능 향상 - 읽기/쓰기에 대해 개별적인 스케일링 가능
  • 복잡한 도메인의 태스크 간소화
  • 트랜잭션 데이터의 일관성 보장
  • 전체 감사 추적 및 기록 유지 가능

2. CRUD와의 비교

CRUD 모델의 문제점은, CRUD 모델에서 일반적인 데이터 프로세스는 저장소에서 데이터를 읽고 수정한 다음 데이터를 잠그는 트랜잭션을 사용하여 데이터의 현재 상태를 새 값으로 업데이트 하는 것이다.

  • 데이터 저장소에서 직접 업데이트 작없을 수행하여 성능 및 응답속도 저하
  • 처리 오버헤드가 필요해져 확장성 제한됨
  • 동시 사용자가 존재하는 공동 작업 도메인의 경우, 단일 데이터 항목에서의 업데이트가 업데이트 충돌을 일으킬 수 있음
  • 각 작업으이 세부 정보를 개별 로그에 기록하는 추가 감사 매커니즘이 없으면 기록 유실됨

3. Event Sourcing Pattern의 특징

3.1. 장점

이벤트 변경이 불가능함

  • 이벤트를 시작한 사용자 인터페이스, 워크플로 또는 프로세스가 계속 진행됨
  • 이벤트를 처리하는 태스크를 백그라운드에서 진행 가능
  • 트랜잭션 처리 중 경합 없음
  • 애플리케이션의 성능과 확장성 향상

이벤트는 데이터와 함께 수행된 작업을 설명하는 단순 객체

  • 이벤트가 데이터 저장소를 직접 업데이트 하지 않음, 적절한 시간에 처리하기 위해 기록됨
  • 구현 및 관리 간소화
  • 동시 업데이트로 인한 충돌 방지
  • 상태 불일치를 초래할 수 있는 요청으로부터 보호되도록 디자인 필요

전용 이벤트 스토리지에서 제공하는 Audit Logging 사용 가능

  • 데이터 스토리지에 수행된 작업 모니터링
  • 이벤트를 재생하여 현재 상태를 재생성 가능
  • 시스템 테스트 및 디버그 지원
  • 취소된 변경 기록이 제공됨
  • 이벤트 목록을 통해 성능 분석 및 사용자 경향 분석 등 가능

Event Sourcing은 일반적으로 이벤트에 대한 응답으로 데이터 관리 태스크를 수행하고 저장된 이벤트에서 뷰를 구체화하여 CQRS 패턴과 결합됨

3.2. 문제 및 고려사항

구체화된 뷰를 만들거나 이벤트를 재생하여 데이터 프로젝션을 생성할 때만 시스템이 일치