[Design] EDA의 개념 (3) – CQRS

EDA 개념 마지막편으로 CQRS에 대해 알아보자.

CQRS

The basic idea with CQRS is that you separate the components that read and write to your permanent store. So you have effectively two separate models one for dealing with updates and one for dealing with reads.

CQRS( Command and Query Responsibility Segregation ) 는 이름에서 유추할 수 있는 것 처럼 Command( 명령 ) 을 처리하는 시스템과 Query( 조회, Read )를 처리하는 시스템을 서로 분리하는 방식을 말한다.
이 CQRS 를 사용하고, 적용하는 이유는 간단하다. Read Model 과 Comand Model 을 서로 분리함으로써 관심사를 나눌 수 있다는것이 핵심이다.

아래쪽에 후술하겠지만, CQRS 패턴을 적용하였을 때 생기는 “장점”은 여러가지가 있다. 그러나 핵심적으로 CQRS 를 적용하는 근본적인 이유는 관심사를 분리하는 것을 말한다.


I think what’s important about the CQRS model is notion that the command model( the thing that’s used for updating )isn’t used by anything for reading. It’s only used in the process and you’ve got a distinctly different model that’s only used in the update area.

즉, Command Model 은 업데이트에 대해 복잡한 비즈니스 로직만을 수행하여 저장하고, 읽기 모델은 절대로 데이터베이스를 수정하거나 변경하지 않고, 오직 사용자에게 Data 를 전달하기 위해 읽는 역할만을 담당해야 한다는 것이다.
Event Sourcing System 에서, 어떤 Command 나 Event 가 발행되었을 때 구독자가 그 일을 처리하기 위한 여러 비즈니스 로직이나 복잡한 수행 과정이 있을 수 있다. 이런 것들은 오직 Command Model 이 관심사를 갖고 처리하고, Read Model 은 그냥 처리된 결과물만 읽어들이면 된다는 것이다.

장점

이런 의도를 갖고, Command Model 과 Query Model 을 나누었을 때에 생기는 장점들이 있다.
우선, Command Model 과 Query Model 이 서로 나누어진( 물리적으로 나뉘어진 2개의 데이터베이스 일수도 있고, 혹은 서로 다른 테이블을 사용할 수도 있다. ) 상태에서 오는 이점들은 아래와 같다.

  1. Command 저장소와 Query 저장소를 처리되기 빠른 쪽으로 각각 다르게 구성할 수 있다. -> 예를 들어, 데이터베이스 자체를 Command Model 은 Transaction과 높은 정합성 보장을 위해 SQL로 설계하고 Read Model 은 NoSQL 로 구성한다던가, 혹은 둘다 SQL 이라도 읽기 모델은 읽기에 특화되게 Table 을 구성하여 Join 되는 경우를 줄인다던가.. 하는 것들을 말한다.
  2. 읽기와 쓰기 사이에 자원 투자를 다르게 할 수 있다. -> 예를 들어 읽기가 압도적으로 많이 일어나는 경우라면 읽기 쪽 Database 를 더 늘리는 방향으로 유동적으로 조절할 수 있게 된다.
  3. 데이터 일관성 관리 -> Event Sourcing과 CQRS를 함께 사용하면, 쓰기 모델에서 발생한 이벤트를 읽기 모델로 전파하는 과정을 명확하게 정의할 수 있게 된다. 이벤트가 발생할 때마다 읽기 모델을 업데이트하거나, 일정 주기마다 동기화 할 수 있게 된다.

Event Sourcing 과 CQRS

Event Sourcing 패턴을 사용할때 CQRS 패턴은 함께 이용되는 경우가 많다.
그 이유는 CQRS 가 갖는 관심사 분리에서 오는 장점들이 Event Sourcing System 을 구성할때 굉장히 많은 이점을 가져다 주기 때문에 그렇다.

Event Sourcing은 시스템 상태를 마치 Log 처럼 관리하며, 모든 변경 사항을 이벤트로 저장한다. 전편에서도 이미 설명했지만 현재 상태를 구현하기 위해 이벤트 Replay 하여 재구성하는 과정은 복잡성을 증대시킨다.
이때 CQRS 패턴을 사용하면, 쓰기 모델과 읽기 모델을 분리하여 관심사를 분리할 수 있기 때문에, “Event 와 Command를 구독하여 비즈니스 로직을 처리하는 것” 과 “현재 상태를 구현하기 위해 Snapshot 등을 구현하여 빠르게 Replay하는 것” 을 나눌 수 있게 된다.

그리고 무엇보다, Event Sourcing 은 Replay를 통한 과거 상태를 확인할 수 있다는 것이 주요 장점이다. 따라서 이 Event Sourcing 이 적용되는 곳은 이력관리가 무엇보다 중요하다는 얘기이고, 이는 곧 Read 를 하는데 비용이 높아질 수 밖에 없는 구조임을 의미한다. ( 이력관리가 중요하지 않은 도메인이라면 굳이 Event Sourcing 을 적용하지 않고 다른 방법을 사용해 볼 수 있을것이다. )
Snapshot 을 적용하더라도, Snapshot 을 1건 마다 새로 만들 수는 없고, Snapshot 을 만드는 빈도가 적으면 적을수록 replay 비용은 커지게 될 것이다.

CQRS 는 Read 에 강점이 있는 해결방법이다. Command Model 을 분리하여 관심사를 나눈 뒤, 결과를 Read Model 로 Projection 받기만 해서 Read 를 빠르게 하겠다는게 핵심 요소이기 때문이다.
또한 이와 더불어서 여러 외부 시스템과 결합해야 할 때 복잡성도 줄여주고, Command 모델의 장애가 Read 모델에는 영향을 미치지 않는다는 점도 그 이유중 하나이다. 이런 이유들 때문에 CQRS 가 Event Sourcing 과 함께 자주 쓰이게 된다.

단점


I think it’s an appropriate pattern for a number of situations, but it is one that seems to correlate a lot with people getting into trouble. So you’ve got to really kind of be careful and make sure you really understand how it works and what its benefits are and if you really need it when you’re using. it might sense is it’s got to be pretty deep down in the tool bag to pull this one out.

CQRS 패턴은 강점은 확실하지만, 복잡성도 확실하다. Command 모델의 데이터를 Read Model 로 Projection 할 때 까지의 Delay 나, 반드시 하나의 트랜잭션에서 동작함을 보장해야 하는 등, 복잡성을 많이 증대시킨다.
Martin Fowler 또한 이것이 어떻게 작동하고, 어떤 이점이 있는지, 그리고 여러분이 사용할 때 정말로 이것이 필요한지를 확실히 이해할 때 사용해야 한다고 말한다.

결론

이렇게 해서 EDA 에 필요한 4가지 패턴들에 대해서 하나씩 살펴보았다. EDA 는 중요한 아키텍쳐이고, 많이 사용되는 방법이기 때문에 중요한 개념들을 잊지 말고 잘 기억하도록 하자.

Leave a Comment