2. 이벤트 소싱 기반 비지니스 로직 개발하기
이벤트 소싱이란?
이벤트를 위주로 비지니스 로직을 구현하고, 애그리거트를 일련의 이벤트로 DB에 저장하는 기법이다.
뭐라구요?
위 설명으로 이해할 수 있을리가 없다.
일반적인 RDB의 활용과 구현법을 생각해보자.
회원 정보 혹은 상품 정보 등을 저장할 때는 주로
- 1개의 table은 서버 입장에서 객체의 집합체(저장소)
- 1개의 row는 1개의 객체
의 구조로 사용하거나 혹은
- 사용자가 특정 API를 호출했다는 이력을 저장하기 위한 이력형 table
로 사용한다.
여기서 우리가 사용할 것은 두번째 방법인 이력형 테이블(historical table)이다.
이벤트의 이력을 기준으로 애그리거트를 활용한다!
애그리거트는 어디까지나 객체의 정책이기 때문에 그에 맞춰서 실행하면 되지만, 약간 다른 방식을 사용한다.
순서는
- 호출자는 원하는 애그리거트의 상태 변화를 이벤트 DB 테이블에 저장한다.
- 이벤트 DB 테이블의 변경점을 발견한 앱이 이벤트를 읽는다.
- 읽어들인 이벤트에 속하는 애그리거트의 인스턴스를 생성한 후 이력 정보에 있는 기능을 수행한다.
라는 3개의 과정을 통해 실행된다.
ex) 주문 정보 애그리거트가 있다고 하자.
발생한 요청은 주문 정보 애그리거트가 가지고 있는 주문 생성 기능이다.
호출자는 애그리거트의 상태가 [없음]에서 [주문 생성]으로 변경되는 작업을 요청하기 때문에, 해당 이벤트를 DB에 저장한다. 이후 해당 이벤트 DB를 모니터링하고 있던 소프트웨어는 이벤트 로그에 기록된 애그리거트의 작업을 실행시킨다.
그렇구나... 하고 지나갈 법 하지만 매우 무책임한 과정이다. 저장은 하면 되지만 모니터링은 어떻게 할 것인가? DB에 저장하면 신규 이벤트인지 알게 뭔가?
이벤트 감지는?
참고 서적에서 제시한 방법은 아래 두 가지이다.
- 폴링(Pollin)
- 주기적으로 이벤트 발행 테이블을 조회한다.
- 미쳤냐?
- 주기적으로 이벤트 발행 테이블을 조회한다.
- 트랜잭션 로그 테일링(참고 서적에선 이 방법을 추천)
- 해당 테이블의 트랜잭션 로그에서 insert를 감지하여 메시지 브로커로 이벤트를 전달한다.
- 메시지 브로커를 구독하고 있던 앱에서는 전달 받은 이벤트를 실행한다.
그리고 둘 다 내 취향은 아니다.
폴링은 비용 소모가 너무 크고, 트랜잭션 로그 테일링은 설명만 들어도 어렵다. 교수님은 분명 소프트웨어에서 Simple is beautiful만큼 중요한 덕목은 없다고 하셨다.
내가 원하는 방식은 트랜잭션 로그 테일링에서 나온 메시지 브로커를 데이터의 저장과 전달의 역할이 가능한 MQ로 구현하여 메시지 브로커만을 사용하는 것이다. 이벤트 이력 저장은 이벤트가 전달된 다음에 하면 되잖아!
적용 범위는 서버 프로젝트 내부
위 과정은 사실 MSA가 적용된 서버 간 통신 방식이 서버 프로젝트 내에 적용된 방식이다. 때문에 위 내용만 봐서는 단일 프로젝트 내에서 객체 간 호출을 하려고 DB에 저장하고 조회해야 하는 심각한 뻘짓이다. 하지만 뻘짓이라고 위 과정을 뺄 순 없다.
왜 이렇게 해야 하는가?
애그리거트는 도메인의 철저한 관리를 주목표로 한 정책과 주고를 가지고 있다. (비록 뇌피셜이지만, Root Entity와 PK만을 통한 참조 정책은 이것을 노린 것이 분명하다.) 애그리거트 간 호출은 하나의 프로젝트 내에서 작동할지 몰라도, 역할은 다른 서버에서 작동하는 것처럼 구현하여 철저한 이력 관리를 할 수 있어야 한다는 것이다.
* 위 내용을 책으로 보기 전에, 실무에서 유사한 구조를 직접 설계/구현한 적이 있었다. 그 당시 목적은 데이터의 소실을 우려하여 모든 이벤트를 이력으로 남기는 것이었다. 이후 이력을 베이스로 정확한 데이터 오차 검증을 로직으로 구현하였다. 솔직히 처음에만 반짝 뜬 후 빛의 속도로 꼬라박아 사라진 서비스지만, 분명 꽤 많은 이벤트가 발생했음에도 단 하나의 오차도 발생하지 않은 성과를 이루었다. 이런 경험 때문에 위 내용을 책에서 읽으면서 뿌듯하기도 했고, 이 방식을 쓰는 이유를 이해하는데 큰 시간이 걸리지도 않았다.
설명하지 않은 내용들
책에는 이벤트의 전달 파라미터 변경, api 포맷의 변경 등의 조치를 위한 이벤트 버전 관리, 이벤트 이력 용량이 커짐에 따른 방안, 이벤트 중복 발생에 대한 처리 등 여러 예외 처리 과정을 추가적으로 언급하고 있다.
하지만 이런 부분들은 당장 내가 위에서 취향에 안맞아 다른 방식을 쓰는 것과 같이 책의 저자가 구현한 방식에 맞춘 방식이기 때문에, 여기서 언급하지는 않았다.