[Design] EDA의 개념 (2) – Event Sourcing

이전 글에 이어서 EDA Martin Fowler가 제시하는 EDA의 중요한 개념인 EventSourcing 에 대해서 알아보자.

Event Sourcing

마틴 파울러는 이벤트 소싱에 대한 개념을 개발자라면 단번에 이해할 수 있는 예시를 들어 설명한다.

… Every software developers should be intimately familiar with one particular form of event source system. which is? ersion control. Event Sourcing is basically provide to your users a system that works on their data the way version control works on your code.

Event Sourcing 을 가장 잘 활용하고, 많은 사람들이 이용하는 분야가 바로 Version Control ( Git, SVN .. ) 이다.
Git을 예시로 들어보자. Git은 Commit 을 통해서 Repository 의 소스코드가 업데이트 된다. 그리고 사용자는 언제든지 Commit 을 Revert 하여 과거의 특정 시점으로 Source Code 를 되돌리는 것 또한 가능하다. 또는 Commit 여러개를 하나의 Commit 으로 합치는 일도 가능하다.

이 Commit을 실제로 저장하고 있는, 로그 저장소와 같은 역할을 하는 것을 Event Store 라고 부르고, 이 Event Store 에 쌓인 Commit을 하나씩 읽으면서( Event Replay ) 현재 Repository 의 Source Code 를 구성하는 이 시스템을 Event Sourcing 이라고 한다.
즉 Event Sourcing은 Version Control System 이 하는 일을 우리의 Application State 에 적용함으로써 동일한 역할을 수행할 수 있게 만드는 것이라고 이해하면 된다.
Event ( Commit ) 를 통해 현재 Application State( Repository ) 를 만들어내고, Event 를 삭제함으로써 RollBack을 구현할 수 있다.

Event Sourcing System은 반드시 모든 Event를 하나하나 저장하고 Replay 할 필요는 없다. 예를 들어 Commit 이 100만 개인 Repository 에서 Commit 현재 Repository 의 SourceCode 상태를 만들기 위해 첫번째 커밋부터 100만개의 커밋을 하나씩 읽어들이며 현재 상태를 만들어야 한다면 처참한 성능이 나올것이다.

… Of course the system internally doesn’t necessary store it as all events. But it stores it effectively as it were all events. There are snapshots that are contained at various points to speed up performance which is basically a copy of the entire application state as at some commit.

이를 해결하기 위한 개념으로 Snapshot 을 제시한다. 이 Snapshot 은 특정 Event 까지 적용된 Application State 의 전체를 Copy 하여 Replay 할 Event 를 줄이는 방법을 말한다. 예를들어, 앞선 예제에서 설명했던 백만개의 Commit 이 있는 Repository 를 예로 들면, 10만개의 Commit 마다 그때 당시의 Repository 의 SourceCode 를 통으로 복사하여 따로 저장하는 것을 말한다. 이런 식으로 Snapshot 을 만들면 100만개의 Commit 이 아닌 10개의 Snapshot 만 Replay 하면 현재 Repository 의 Source Code 를 더 빠른 속도로 구성할 수 있다.

장점

“There’s no silver bullet.” 이라는 말이 있듯, 이 Event Sourcing System 에도 장점이 있고 단점이 있다.

Event Sourcing Pattern 을 적용하였을 때 얻는 이점은 무엇이 있을까?
바로 Auditing & Debugging 이다. 현재 상태가 왜 이렇게 구성되었는지에 대한 이유가 궁금한 경우에 사용하기 좋다. 예를들어, 일반적인 Database 같은 경우에는 “현재 상태가 이렇다” 를 빠르고 직관적으로 알려주지만, ” 이런 이유들로 인해서 현재 상태가 되었다” 는 직관적으로 나타나지 않는다. 하지만 Event Sourcing 자체는 현재 상태를 표현하기 위해 Snapshot 들과 Event 들을 Replay 해서 구성하기 때문에 어떤 이유로 현재 상태가 되었는지를 흐름을 통해 쉽게 알아볼 수 있다.
즉 현재 상태가 왜 이렇게 되었는지를 통해 과거 시점으로 상태를 쉽게 RollBack 하거나 평가할 필요가 있는 경우에 적용하면 좋다. 좋은 예시로 강남언니팀의 기술블로그에도 이런 글이 작성되어 있다. 한번 읽어보자.

즉 Event Sourcing Pattern 을 적용하면 History 를 기반으로 과거의 State 를 재현할 수 있다는 것에서 오는 장점이 많다.

단점

Event Sourcing 을 적용하게 되었을 때 가장 직관적으로 떠오르는 문제점은 바로 전통적으로 많이 사용한 방법인 Database 기반의 State 복원 방식과 많은 차이가 있다는 점이다.
Database 에 현재 State 를 저장하고, 해당 State 를 불러옴으로써 현재 상태를 만들어내는 방법과 다르게 Event 를 Replay 하는 방법은 분명 친숙하지 않은 방법임은 확실하다.

… If i want to be able to rebuild my application state, I can’t just say “oh i called this external system two weeks ago, what was the result?” because i can’t call it again two weeks ago. I have to make sure i save basically every response from an external system as an event.

직관적으로 바로 알아볼 수 있는 문제점이다.
Event 가 중간에 빠지거나, 어떠한 이유로든 누락되면 서로 다른 Application state 가 구성된다는 점이다. 즉, 내가 만약 다시 Application state 를 구성하려고 한다면 그동안 다른 외부 시스템이 발행한 Event 들을 모두 가지고 있을 때만 가능하다. 중간에 어디에선가 이벤트가 누락되어서는 절대로 안된다.

… I have to think about how do i store my events in a way that i can confidently replay them even as i’m changing the code that process system. So the event schema starts becoming interesting to be able to do that.

Event를 소비하는 소비자들의 처리 방법( 코드 )가 변경되더라도 Event의 Schema 가 변경되는 것은 아니다. 그렇다고 Event의 Schema 를 변경하게 된다면, 이벤트를 구독하는 다른 소비자들에게도 영향이 생길 수있다. 따라서, 이 이벤트의 스키마를 어떻게 설계하고 구성해야 하는 고민과 관리 포인트가 늘어날 수 있음을 의미한다.
이 부분은 직관적으로 와닫는 문제점은 아니지만, 분명 복잡성을 늘리는 원인이 된다.

즉 이런 것들은 전체 시스템의 Complexity 를 가중시키는 일이고, 이런 것들로 인해 관리 포인트가 늘어나는 점은 Event Sourcing 의 단점으로 꼽힐 수 있다.

단점?

Event Sourcing 하면 막연하게 떠오르는 복잡성에는 비동기 프로세싱이 분명 포함되어 있을 것이다. 필자도 그렇게 생각했다. 이에 대해서 그는 이렇게 말한다.

… They processed all their events in an asynchronous manner and asynchronous processing got difficult for people. Because asynchrony trends to be hard to work with, hard to reason about.
There’s no reason why you have to have asynchrony with your system. When i just make a local commit in git, that’s not an asynchronous operation. Now okay when people pushing up to shared repositories then asynchrony comes into play.
But there’s none of that, It’s all synchronous operations that i’m doing a local commit.

다시한번 Git을 떠올려보자. Git 에서 내 local repository 에 commit 하는것은 비동기 흐름이 아니라는게 자명하다. 하지만 나는 얼마든지 Local repository 에 적용된 commit 을 삭제함으로써 과거의 상태로 돌아갈 수도 있으며, Local Repository 는 여전히 Commit 들을 모아서 현재 Source code 를 구성하는 Event source system이다.
즉, Event Sourcing 의 본질은 Asynchronous 와 크게 관련이 없다는 얘기다. 만약, 내가 만드는 것이 Local Repository 밖에 존재하지 않는 Git 을 만든다면 비동기 패턴은 전혀 필요 없을것이다.

… But often people take advantage of the event sourcing to introduce asynchrony into the system which can be a good thing. Because it improves responsiveness. But asynchrony then adds complexity.

Asynchrony often comes along with event sourcing systems and it does add a lot of complexity. But you don’t have to use asynchronous event sourced approach. Even though it seems common that people confuse that.

물론, 이 commit 을 Remote repository 로 업로드 한다면 그때는 비동기 흐름이 포함되겠지만, 그것이 반드시 Event Sourcing 에 포함될 필요는 없고, 해당 시스템과 서비스의 특성에 따라서 비동기성이 추가되는 것 뿐이다.
여기서 그는 추가적으로 Versioning 에 관해서도 이야기하는데, 버전 관리 부분은 분명 중요한 요소가 맞다. 그러나, 너무 크게 걱정할 부분은 아니라고 말한다. 그 예시로 One-day snapshot 즉 매일매일 Snapshot 을 만들고, 그 다음 Event 는 해당 Snapshot 에 대해서 작동하게 하는 사례를 통해 설명한다.
시간이 지나 Application State가 변경되고, Event Schema 도 바뀌게 되면 1년전의 Event 를 처리할 수 없게 되는것은 당연하다.

결론

여기까지 Event Sourcing 에 대한 개념을 살펴보았다. 처음 접했을 때는 막연하게 어렵고 복잡하다고만 생각했는데, 하나씩 천천히 살펴보니 아주 이해하지 못할 것은 아닌 것 같다. 다음 편에서는 EDA 개념 마지막 편으로 CQRS 에 대해서 알아본다.

Leave a Comment