CQRS Pattern

 

CQRS(Command Query Responsibility Segregation) 패턴

에 대해 알아보자...

 

단어 자체의 해석은..

명령 조회 책임 분리(커멘드 쿼리 책임 분리)이다.

(명령과 조회의 책임을 분리하자)

-> 보통 성능이 중요한 조회용 외부 시스템과 비즈니스 명령이 많은 내부 시스템으로 분리한다.

 

자세한 정의

CQRS 패턴은 도메인에서 발생하는 이벤트와 상태를 분리하여 처리한다.

즉, 명령(Command)과 조회(Query)를 각각 다른 모델로 처리하는 것이다.

명령 모델은 상태 변경을 처리하고, 조회 모델은 상태를 조회한다.

이렇게 하면 각각의 모델은 명확한 역할을 가지게 되어

유지보수 및 확장이 용이해지며, 코드의 복잡성이 줄어들게 된다.

또한 CQRS 패턴은 이벤트 소싱(Event Sourcing)과 결합하여 사용될 때 매우 유용하다.

이벤트 소싱은 애플리케이션의 모든 상태 변경을 이벤트로 기록하는 패턴으로,

이벤트를 통해 언제든지 이전 상태로 되돌릴 수 있다.

이러한 이벤트 기록을 통해 명령(Command) 모델이 상태 변경을 처리하고,

조회(Query) 모델이 이벤트를 이용하여 상태를 조회하는 것이 가능해진다.

CQRS 패턴은 애플리케이션의 복잡성이 증가할 때 사용하기 좋은 패턴이다.

하지만 패턴의 사용은 항상 상황에 맞게 판단되어야 하며,

프로젝트의 크기나 복잡성, 비즈니스 요구사항 등에 따라 패턴의 적용 여부를 결정해야 한다.

 

 

CQRS의 필요성

기존에 RDB를 사용하는 Application 이 있다고 치자..

이 시스템은 CRUD를 모두 처리하는 상황이었다.

하지만.. R에 해당하는 조회의 트래픽이 엄청나게 늘어난 상황을 가정하겠다.

 

1. Application 내부 코드 관점

전통적인 Application은 Data를 연결된 DataBase에 CRUD (생성, 조회, 갱신, 삭제) 작업을 한다.

Data를 다룸에 있어서 Data는 Application에서 Model(Domain, Entity)로써 다루어진다.

 

비즈니스 요구사항(주로 veiw 측면의 조회)이 늘면서..

해당 Model은 속성이 점점 많아지며 거대해진다..

또한, CUD는 변경사항이 없지만, 조회(R)에 필요한 코드들이 점점 더 덧붙여져서

순수한 명령에 기반한 비즈니스 로직은 변경이 없지만

조회용 코드 수정 때문에 코드 자체가 복잡해진다. (유지보수성 하락)

서로 필요없는 데이터도 같이 사용될 확률이 높아져서 전체 성능도 나빠질 수 있다.

-> 모델과 로직을 명령형/조회형 으로 나눌 필요가 생김

 

2. 시스템 관점

내부 코드 관점에 이어서, DB 자체도 명령기반 DB는

핵심 비즈니스 로직이 변경되지 않으므로 변경될 필요가 없지만..

view 측면의 비즈니스 요구사항이 늘면서 조회용 데이터에서 필요한 속성이 추가 되는 것이다.

 

이 상황에서 트래픽도 엄청나게 증가 하면..

기존에는 CRUD 모두 처리하고 명령형 기반으로 설계된 시스템이므로

데이터의 정확성과 안정성이 중요하므로 RDB를 사용할텐데..

조회용 트래픽이 증가되면서 기존 시스템과는 다른 방향의 설계(대용량 트래픽을 처리할 수 있도록)가

필요한 상태에 이르게된다.

-> 명령형 시스템과 조회용 시스템으로 Application + DB 자체를 나눌 필요가 생김

-> 기존의 명령형 시스템은 그대로 RDB를 사용하면 되고,

조회용 시스템은 명령형 RDB를 미러링 하는 성능이 좋은 DB(캐시, NoSQL)를 사용해보자

 

1번 2번의 결과로 CQRS가 등장하게 되었다.

 

 

이번에는 MSA를 곁들여서 더 생각해보자..

MSA 구조에서 CQRS를 적용했다.

(가게노출은 가게/업주로 묶여야 하지만, 명령/조회를 분리하여 따로 구성)

각 시스템간 메시지 처리를

단순하게.. API 조회 형식으로 시스템 구성했다면?

 

 

위 그림 처럼, 가게/업주 시스템이 장애가 나면.. 의존성이 있는 모든 시스템이 장애가난다...

따라서 다른 구조로 변경 필요

 

 

또한, 순간적으로 엄청난 트래픽이 가게 노출 시스템으로 몰려오면..

대용량 트래픽 처리를 위한 시스템이 아닌 광고, 가게/업주 시스템은 죽어버릴 수 있다.

 

<참고>

모든 시스템을 대용량 트래픽을 감당 가능한 시스템으로 전환하기엔 현실적으로 어려움이 있다.

광고, 가게/업주 시스템은 정확하고 안정적으로 시스템을 운영하게 맞춰진 시스템(명령형 위주 시스템)이어야 한다.

 

그래서 단순한 API 조회 형식에서 벗어나서 CQRS 구조로 변경해보자..

 

CQRS 구조를 도입하게 된다면..

명령형 기반(CUD)의 시스템은 변경 사항이 생긴다면

조회용 시스템에 변경 이벤트를 발행한다. (미러링)

-> 여기서는 DB자체를 미러링 할 수도 있고 Application에서 처리할 수도 있다.

 

이러한 CQRS 구조에서는 조회용 트래픽이 몰려와도

조회용 시스템은...

대용량 트래픽 처리가 가능한 시스템(캐시를 적극적으로 도입하고, view에 fit한 쿼리와 로직으로 구성)이므로

장애가 나지 않고, 해당 트래픽을 명령형 시스템으로 전이 시키지 않는 구조이므로 안정적이게 된다.

 

<참고>

조회와 명령이 분리된 구조이므로 데이터 싱크가 밀릴 수 있지만,

Eventually Consistency 최종적 일관성을 맞춘다는 가정하에 수용할 수 있다.

 

 

 

(위 그림에서는 이벤트 처리를 AWS의 SNS와 SQS로 했지만, 보통 Kafka, RabbitMQ를 많이 사용한다.)

 

위 그림은, 명령형 기반 시스템에서 조회용 기반 시스템으로 데이터 변경 이벤트를 발행하는 예시이다.

(조회용 시스템, 명령형 시스템 모두 용도에 맞는 DB를 가지고 있다고 생각)

 

 

CQRS 구조가 필요한 시스템은?

앞서 봤던 예시와 같이 기존 CRUD를 모두 담당하는 하나의 시스템에서

조회용 트래픽이 엄청나게 증가된 상황이 생긴다면 좋은 해결 방법 중 하나가 CQRS 패턴이라 볼 수 있다.

 

하지만..

대부분의 시스템은 CRUD를 모두 처리하는 구조로도 충분한 경우가 많으며..

CQRS 패턴은 쉽게 구현할 수 있는 패턴이 아니며, 시스템 복잡도가 많이 올라가버린다.

또한, 모델의 적절한 경계를 구분하기 위해서 DDD 방법론을 학습해야할 수 도 있다.

CQRS는 전제 시스템에 적용하는 것이 아닌 특정 부분(DDD의 BoundedContext) 에서만 사용해야한다.

 

 

 

Martin Fowler의 CQRS와 관련된 개념 및 인사이트

https://martinfowler.com/bliki/CQRS.html

(아래는 각각 포스팅 예정)

 

1. event-based programming models

2. Event Sourcing

3. eventual consistency

4. EagerReadDerivation

5. read models as EventPosters, allowing them to be MemoryImages

(To avoiding a lot of data interactions)

6. Domain-Driven Design

 

 

단일 CRUD 시스템에서 CQRS 시스템으로 변경되는 모습

단일 CRUD 시스템 (Classical layered architecture)

 

 

하나의 Application 내부에서 코드상 모델과 로직을 분리

-> 단일 Data Store에 Command Query Model을 분리된 계층으로 나누는 방식

(Simple CQRS architecture)

 

 

 

단일 Application 내부에서 모델과 로직이 분리 되었고, 명령용 DB와 조회용 DB를 나눈 상황

(CQRS with separated persistance mechanisms)

DB를 나누어 다수의 DataBase를 혼용하여 사용하였기 때문에 polyglot 구조이다.

 

여기서 한번 더 나간게 앞서 봤던 구조인 Application도 나눠버린 구조가 된다.

(우아한 형제들)

 

 

 

 

참고 자료

http://auconsil.blogspot.com/2013/08/cqrs-command-query-responsibility.html

https://www.youtube.com/watch?v=BnS6343GTkY

https://martinfowler.com/bliki/CQRS.html

 

 

 

 

 

'대규모 시스템 설계' 카테고리의 다른 글

Event-Driven 아키텍처 와 Pub/Sub 모델  (0) 2023.06.03
Hexagonal Architecture 정리  (0) 2023.05.15
Saga Pattern (feat. MSA)  (0) 2023.02.13
Two Phase Commit (feat. MSA)  (0) 2023.02.13
안정 해시 설계 2  (0) 2022.09.03