• 에그리거트: DDD(domain-driven design)에 기반한 설계에서 하나의 도메인에서 필요한 객체들을 하나로 모아놓은 것. 하나의 트랜잭션에서는 하나의 애그리거트만 업데이트.

  • Entity의 상태 변화를 이벤트 기반으로 저장하여 처리하는 방식

  • 대부분의 상황에서 우리는 Object Relation Mapping 방식에 의거하여 상태를 관리함. 다만, 이는 이런 문제를 갖고 있음

    • Object Relation Impedance mismatch
    • 애그리거트가 업데이트 되면 이전 상태가 사라지고 없기 때문에, 기록을 남기기 위해 별도의 작업이 필요함
      • 감사 로깅을 구현하기 어려움 (뭐가 어떻게 된 거지?)
    • 비즈니스 로직과 이벤트 발행 로직을 분리하기 어려움
  • 이벤트 소싱을 이용하여 이러한 문제점 중 많은 부분을 개선할 수 있음

event_idevent_typeentity_typeentity_idevent_data
102ORDER_CREATEOrder101{…}
103ORDER_APPROVEDOrder101{…}
104ORDER_SHIPPEDOrder101{…}
105ORDER_DELIVEREDOrder101{…}
  • 이벤트 소싱은 이런식으로 상태 변화를 일련의 이벤트로 저장함.
    • (책에서는 애그리거트를 이벤트로 저장한다고 했는데.. 대체 왜 이게 애그리거트인지)
  • 이렇게 생성된 이벤트들은 쭉 순회하며 다음과 같이 처리함
    1. 애그리거트의 이벤트를 로드
    2. 기본 생성자를 호출하여 이스턴스 생성
    3. 이벤트를 하나씩 순회
  • 이렇게 하면 인 메모리 상태를 이벤트를 기반해서 재구성 하는 것

image

  • 계속 프로세스를 호출하여 새 이벤트를 발생시킨다는데 대체 뭔소리인지 모르겠음

    • 애그리거트 상태 변경 없이 이벤트가 생성된대;
  • 앞서 계속 화두에 올랐던 동시 업그레이드 문제는 대부분 시맨틱 락 / 옵티미스틱 락으로 해결

  • 그럼 이벤트는 어떻게 가져오는가?

    • 앞서 말한대로 위에 전체 이벤트를 관리하는 테이블을 둔 이유가 있음. 마지막으로 가져온 event_id부터 천천히 가져오는 폴링 기법을 이용할 수 있음
    • 트랜젝션 로그 테일링?
  • 다만 이렇게 했을 때, 시간이 지나거나 자주 업데이트 하는 도메인의 경우, 데이터를 구성하는데 오랜 시간이 걸릴 수 있음. 하여 그런 엔티티에 대해서 스냅샷을 뜨는 식으로 해결할 수 있음

  • 이벤트 소싱은 다음과 같은 장점이 있음

    • 상태가 변경될 때 마다 기록함 > 데이터 재현 등에 도움이 됨
    • Object Relation Impedance mismatch > 하나의 큰 Object에 대해서 관리하게 되므로, 기존 RDB를 사용했을 때 생기는 문제점을 해소할 수 있음
  • 대신 다음과 같은 단점이 있음

    • 메시징 기반 애플리케이션은 복잡함
    • 데이터를 삭제하기 어려움
    • 이벤트 저장소를 쿼리하기 어려움
    • 데이터 삭제가 어려움 (관계나 데이터 등이 명시적으로 나와있는 게 아니라서..)
    • 이벤트 저장소 쿼리가 어려움
  • 이를 Saga 기반 패턴과 엮기 위해서는 다음과 같은 전제조건이 필요함

    • 커맨드 메시지를 멱등하게 처리
    • 응답 메시지를 원자적으로 전송
    • 응답도 한번만 처리하거나 / 멱등하면 됨 (다만 버전들 때문에 1번만 하도록 하는게 나을듯)