이벤트 소싱(Event Sourcing) 개념
이벤트 소싱 혹은 CQRS라는 말을 SNS에서 자주 보게 되었어요. 비슷한 시기에 번역을 의뢰받아서 진행하게 되었어요. 아카(Akka) 관련 책인데 약속했던 마감일보다 늦어지고 있습니다. 이유는, 아카 및 스칼라(Scala) 외에 새로운 개발 패턴 개념이 많이 녹아있었고, 경험이 약한 내가 번역하는게 맞는 건가 의구심이 들어서 평소보다 속도가 더디게 진행되었죠. 날 더디게 했던 패턴 중 2가지가 이벤트 소싱과 CQRS였습니다.
그러던 중 지인분들이 운영하고 있는 SPRING CAMP 2017의 프로그램 목록을 보게 되었고, 평소 신뢰와 존경하고있던 이규원님과 심천보님이 이벤트 소싱 이론부 & 실습부를 진행하신다는 것을 확인했어요. 망설임없이 표를 구걸해서 SPRING CAMP 2017에 참여하게 되었습니다.
훌륭한 세션을 듣고, 꼭 잊지 말아야 할 개념에 대해서만 간단하게 정리하려고 합니다. (규원님과 천보님의 발표 자료를 기반으로 작성했어요.)
이벤트 소싱 개념
이벤트 소싱은 데이터 저장 방법에 대한 것이에요. 평소 우리는 어떠한 로직을 처리하고, 그 결과 값 만을 저장해왔죠. 하지만 이벤트 소싱은 순차적으로 발생하는 이벤트를 모두 저장해요. 다음 그림을 확인해 볼까요?
사용자가 온라인 서점에서 책을 주문한다고 가정해 볼게요. 1번 책을 구매하고 싶어서 주문을 생성하고, 2번 책도 한번에 주문하려고 추가하게 되었어요. 다시 생각해보니 1번 책은 구매할 필요가 없어서 주문에서 삭제하게 되었죠. 이 상황에서 기존의 데이터 저장 방식이라면, 최종적으로 주문하게 되는 2번 책만 최종 값으로 저장하게 됩니다.
같은 상황에서 이벤트 소싱은, 이벤트 자체를 데이터로 저장하게 됩니다. “사용자가 1번 책을 추가하여 주문을 생성한다.”, “2번 책을 주문에 추가한다”, “1번 책을 주문에서 삭제한다.” 라는 이벤트 자체가 저장되는 방식이죠. 그래서 이벤트 소싱에서는 UPDATE 혹은 DELETE의 개념이 없어요.
스냅샷
그럼 결국 현재 시점의 최종 값을 알기 위해서는 어떻게 할까요? 순차적으로 저장된 이벤트들을 재생하면 결국 현재 시점의 최종 값을 얻게 되겠죠! 그런데 만약, 사용자가 책을 1000000번 추가했다 삭제했다를 반복한다면 어떨까요? 최종 값을 얻기 위해 1000000개의 이벤트를 재생해야겠죠.. 자연스럽게 최종 값을 얻기 위한 처리시간이 길어집니다.
그래서 스냅샷의 개념을 도입합니다. 1000번째 이벤트가 발생할 때 스냅샷으로 저장해 두면 결국 최종 값은 1001번째 이벤트부터 재생해서 얻을 수 있겠죠?
CQRS
근데 이런 요청을 받았다고 가정해볼게요.
2번 책만 주문한 사용자 리스트를 반환해 주세요!
상상만해도 이벤트를 모두 재생해서 2번 책만 주문한 사용자 리스트를 반환하는 일이 오래걸릴 것 같다는 느낌이 들죠? 그래서 CQRS는 이벤트 소싱과 궁합이 좋다고 하네요.
CQRS(Command and Query Responsibility Segregation)는 상태를 변경하는 Command와 조회를 담당하는 Query를 Object 혹은 시스템 단위로 분리시키는 것을 말합니다.
결론
저장 단위가 이벤트라는 것 알겠어요. 이벤트가 저장되기만 하니 쓰기 성능에 좋을 것 같아요. 조회 성능을 위해 CQRS와 궁합이 좋을거라는 느낌은 들어요. MSA(Microservices Architecture)에 적용해야 할 것 같아요. 제가 쓴 글은 아래 참고자료의 규원님 천보님 자료를 그대로 앵무새처럼 따라 쓴 글이에요. 아래 자료를 보면 더 깊이있는 설명과 코드를 확인할 수 있어요.
TODO
- “이벤트 소싱은 어디에 적용하면 좋을까”에 대한 고찰
- 샘플 프로젝트를 구현 w/ Scala