참조 아키텍처: 이벤트 기반 / CQRS
이벤트 기반 아키텍처에서는 서비스가 서로를 직접 호출하는 대신 이벤트 로그(예: Kafka)에 이벤트를 발행하고, 컨슈머가 이를 비동기로 처리한다. 이 트리는 이벤트 백본 구축에서 출발해 event sourcing(이벤트로부터 상태 도출), CQRS를 통한 command/query 분리, read model projection, 멱등성, 최종 일관성 허용, 'exactly-once 전달'의 오류를 단계별로 다룬다. 목표는 일관성 트레이드오프를 잘 이해한, 느슨하게 결합되고 확장 가능한 시스템이다.
이벤트 기반 아키텍처에서 어떤 결정을 앞두고 있는가?
이벤트 기반 시스템의 기반은 비동기 이벤트로 서비스를 연결하는 내구성 있는 이벤트 로그다. 아직 백본을 구축 중인가, 이벤트로부터 상태를 도출하고 싶은가(event sourcing), 아니면 읽기와 쓰기 경로를 분리하려는가(CQRS)?
- 서비스를 연결하는 이벤트 백본을 구축 중
- 이벤트 이력으로부터 상태를 도출하고 싶음
- 읽기와 쓰기 경로를 분리하고 싶음(CQRS)
CQRS에서 읽기 측을 어떻게 구축하며, 일관성 허용 범위는 어느 정도인가?
CQRS에서는 command(쓰기)와 query(읽기) 측이 분리된다. 쓰기 이벤트가 read model에 공급하는 projection을 갱신한다. 핵심 질문: read model이 쓰기보다 뒤처지는 것(최종 일관성)을 허용할 수 있는가, 아니면 모든 이벤트가 정확히 한 번 처리되기를 기대하는가?
- projection을 통해 이벤트로 read model을 공급할 것임
- 읽기는 최신이어야 함, 지연은 허용 불가
- 이벤트가 '정확히 한 번' 처리되기를 원함
권장: 내구성 있는 이벤트 로그 백본
이벤트 기반 아키텍처의 중심에는 프로듀서가 쓰고 컨슈머가 각자의 속도로 읽는, 내구성 있고 순서가 보장되는 이벤트 로그가 있다. 이 백본은 서비스를 시간과 규모 측면에서 분리한다.
권장: Event sourcing(이벤트로부터 상태 도출)
event sourcing에서는 엔티티의 현재 상태가 아니라 엔티티에 적용된 모든 (불변) 변경 이벤트를 저장한다. 현재 상태는 이 이벤트를 순서대로 적용해 도출한다. 완전한 감사 이력과 과거 임의 시점으로 돌아갈 수 있는 능력을 제공한다.
권장: 읽기 모델 projection
CQRS에서는 쓰기 측이 이벤트를 생성하고, projection이 이 이벤트를 수신해 쿼리에 최적화된 read model(비정규화 뷰)을 갱신한다. 읽기는 쓰기 경로와 완전히 분리된 이 준비된 모델에서 제공되며, 양측은 독립적으로 확장된다.
권장: 최종 일관성 허용을 전제로 설계
이벤트 기반/CQRS 시스템에서 read model은 쓰기보다 약간 뒤처진다(최종 일관성). 이를 '제거'하려 하기보다 허용하도록 설계하고, 엄격한 즉시 일관성이 필요한 소수의 흐름은 따로 둔다.
권장: 멱등성(exactly-once의 오류)
분산 메시징에서 종단 간 'exactly-once 전달'은 실제로는 오류다. 네트워크와 재시도 때문에 메시지 중복은 피할 수 없다. 올바른 목표는 멱등적 처리다: 같은 이벤트를 두 번 처리해도 한 번 처리한 것과 같은 결과가 나와야 한다.