-
에그리거트: DDD(domain-driven design)에 기반한 설계에서 하나의 도메인에서 필요한 객체들을 하나로 모아놓은 것. 하나의 트랜잭션에서는 하나의 애그리거트만 업데이트.
-
Entity의 상태 변화를 이벤트 기반으로 저장하여 처리하는 방식
-
대부분의 상황에서 우리는 Object Relation Mapping 방식에 의거하여 상태를 관리함. 다만, 이는 이런 문제를 갖고 있음
- Object Relation Impedance mismatch
- 애그리거트가 업데이트 되면 이전 상태가 사라지고 없기 때문에, 기록을 남기기 위해 별도의 작업이 필요함
- 감사 로깅을 구현하기 어려움 (뭐가 어떻게 된 거지?)
- 비즈니스 로직과 이벤트 발행 로직을 분리하기 어려움
-
이벤트 소싱을 이용하여 이러한 문제점 중 많은 부분을 개선할 수 있음
| event_id | event_type | entity_type | entity_id | event_data |
|---|---|---|---|---|
| 102 | ORDER_CREATE | Order | 101 | {…} |
| 103 | ORDER_APPROVED | Order | 101 | {…} |
| 104 | ORDER_SHIPPED | Order | 101 | {…} |
| 105 | ORDER_DELIVERED | Order | 101 | {…} |
- 이벤트 소싱은 이런식으로 상태 변화를 일련의 이벤트로 저장함.
- (책에서는 애그리거트를 이벤트로 저장한다고 했는데.. 대체 왜 이게 애그리거트인지)
- 이렇게 생성된 이벤트들은 쭉 순회하며 다음과 같이 처리함
- 애그리거트의 이벤트를 로드
- 기본 생성자를 호출하여 이스턴스 생성
- 이벤트를 하나씩 순회
- 이렇게 하면 인 메모리 상태를 이벤트를 기반해서 재구성 하는 것

-
계속 프로세스를 호출하여 새 이벤트를 발생시킨다는데 대체 뭔소리인지 모르겠음
- 애그리거트 상태 변경 없이 이벤트가 생성된대;
-
앞서 계속 화두에 올랐던 동시 업그레이드 문제는 대부분 시맨틱 락 / 옵티미스틱 락으로 해결
-
그럼 이벤트는 어떻게 가져오는가?
- 앞서 말한대로 위에 전체 이벤트를 관리하는 테이블을 둔 이유가 있음. 마지막으로 가져온 event_id부터 천천히 가져오는 폴링 기법을 이용할 수 있음
- 트랜젝션 로그 테일링?
-
다만 이렇게 했을 때, 시간이 지나거나 자주 업데이트 하는 도메인의 경우, 데이터를 구성하는데 오랜 시간이 걸릴 수 있음. 하여 그런 엔티티에 대해서 스냅샷을 뜨는 식으로 해결할 수 있음
-
이벤트 소싱은 다음과 같은 장점이 있음
- 상태가 변경될 때 마다 기록함 > 데이터 재현 등에 도움이 됨
- Object Relation Impedance mismatch > 하나의 큰 Object에 대해서 관리하게 되므로, 기존 RDB를 사용했을 때 생기는 문제점을 해소할 수 있음
-
대신 다음과 같은 단점이 있음
- 메시징 기반 애플리케이션은 복잡함
- 데이터를 삭제하기 어려움
- 이벤트 저장소를 쿼리하기 어려움
- 데이터 삭제가 어려움 (관계나 데이터 등이 명시적으로 나와있는 게 아니라서..)
- 이벤트 저장소 쿼리가 어려움
-
이를 Saga 기반 패턴과 엮기 위해서는 다음과 같은 전제조건이 필요함
- 커맨드 메시지를 멱등하게 처리
- 응답 메시지를 원자적으로 전송
- 응답도 한번만 처리하거나 / 멱등하면 됨 (다만 버전들 때문에 1번만 하도록 하는게 나을듯)