~/tech-blog/posts/ddd-cqrs — zsh
지금 --명이 보고 있습니다오늘 --누적 --

CQRS

이전에 이벤트에 대해 작성하였습니다. 이번 글에서는 책 11장의 CQRS에 대해 정리하도록 하겠습니다. CQRS(Command Query Responsibility Segregation)는 스프링 데이터 JPA를 이용한 조회 기능에서 잠깐 언급했던 것처럼, 상태를 변경하는 명령(Command) 모델과 데이터를 조회하는 조회(Query) 모델을 분리하는 패턴입니다.

단일 모델의 한계

주문 내역 조회 기능을 구현하려면 여러 애그리거트에서 데이터를 가져와야 합니다.

  • Order에서 주문 정보
  • Product에서 상품 이름
  • Member에서 회원 이름과 ID

주문 상세 조회 화면을 만들려면 Order, Product, Member 세 애그리거트에서 데이터를 가져와야 하는 구조눌러서 원본 크기로 보기

조회 화면은 특성상 조회 속도가 빠를수록 좋은데, 위와 같이 여러 애그리거트의 데이터가 필요하면 구현 방법을 고민해야 합니다.

애그리거트에서 정리한 것처럼 식별자를 이용해서 애그리거트를 참조하는 방식을 사용하면, 즉시 로딩 방식과 같은 JPA의 쿼리 관련 최적화 기능을 사용할 수 없습니다. 이는 한 번의 select 쿼리로 조회 화면에 필요한 데이터를 읽어 올 수 없어 성능에 문제가 생길 수 있다는 것을 의미합니다.

문제가 생기는 이유

이런 문제가 생기는 이유는 아래와 같습니다.

  • 시스템 상태를 변경할 때와 조회할 때 단일 도메인 모델을 사용하기 때문입니다. ORM 기법은 Order#cancel()이나 Order#changeShippingInfo()처럼 도메인 상태를 변경하는 기능을 구현하는 데 적합합니다.
  • 반면 주문 상세 조회 화면처럼 여러 애그리거트에서 데이터를 가져와 출력하는 기능은 고려할 것이 많아 구현이 복잡해집니다.

해결 방법

해결 방법은 상태 변경을 위한 모델과 조회를 위한 모델을 분리하는 것입니다. 구조는 아래와 같습니다.

UI의 변경 요청은 명령 모델이 처리해 DB에 반영하고, 조회 모델은 DB에서 읽은 데이터를 UI에 출력하는 CQRS 구조눌러서 원본 크기로 보기

그림에서 애플리케이션은 변경 요청을 명령 모델로 처리하고, 조회 모델을 이용해 표현 계층에 데이터를 출력합니다.

명령 모델과 조회 모델의 구현

도메인이 복잡할수록 명령 기능과 조회 기능이 다루는 데이터 범위에 차이가 납니다. 이 때문에 두 모델이 서로 다른 구현 기술을 사용할 수도 있습니다. 아래는 명령 모델은 RDBMS를, 조회 모델은 NoSQL을 사용하는 예입니다.

명령 모델은 응용 서비스, 도메인, JPA 리포지터리와 RDBMS를 쓰고, 조회 모델은 DTO/DAO와 NoSQL을 쓰며 둘 사이를 이벤트로 동기화하는 구조눌러서 원본 크기로 보기

NoSQL의 경우 메모리 기반이라 조회 성능이 좋습니다.

두 모델 간 데이터 동기화

명령 모델과 조회 모델이 서로 다른 저장소를 사용하면, 명령 모델에서 변경한 데이터를 조회 모델에 반영해야 합니다. 방법은 아래 두 가지입니다.

  1. 명령 모델에서 데이터가 변경되면 바로 조회 모델에 반영합니다. 이때 동기 이벤트와 글로벌 트랜잭션을 사용하는데, 전반적인 성능이 떨어진다는 단점이 있습니다.
  2. 서로 다른 저장소의 데이터를 특정 시간 안에만 동기화합니다. 통계 데이터처럼 비동기로 데이터를 전송하는 방식입니다.

두 방식을 그림으로 비교하면 아래와 같습니다.

명령 모델의 변경을 조회 모델에 반영하는 두 방식 — 동기 이벤트와 글로벌 트랜잭션으로 바로 반영하거나, 비동기로 특정 시간 안에 반영눌러서 원본 크기로 보기

CQRS의 장단점

장점

  1. 도메인 자체에 집중할 수 있습니다.
    • 복잡한 도메인은 주로 상태 변경 로직이 복잡한데, 명령 모델과 조회 모델을 구분하면 조회 성능을 위한 코드가 명령 모델에 없으므로 도메인 로직을 구현하는 데 집중할 수 있습니다.
    • 또한 명령 모델에서 조회 관련 로직이 사라져 복잡도가 낮아집니다.
  2. 조회 성능을 향상시키는 데 유리합니다.
    • 조회 단위로 캐시 기술을 적용할 수 있고, 조회에 특화된 쿼리를 마음대로 사용할 수 있습니다.
    • 조회 전용 저장소를 사용하면 조회 처리량을 대폭 늘릴 수 있습니다.
    • 조회 전용 모델을 사용하기 때문에 조회 성능을 높이기 위한 코드가 명령 모델에 영향을 주지 않습니다.

단점

  1. 구현할 코드가 많아집니다.
  2. 더 많은 구현 기술이 필요합니다. 데이터 동기화를 위해 메시징 시스템을 도입해야 할 수도 있습니다.

마무리

오늘은 명령 모델과 조회 모델을 분리하는 CQRS와 두 모델 간 데이터 동기화 방식, 장단점에 대해 정리하였습니다. 장점이 분명한 만큼 구현할 코드와 기술도 늘어나기 때문에, 도입할 때는 조회 성능이 얼마나 중요한지 함께 따져 봐야 할 것 같습니다.

참조 : 도메인 주도 개발 시작하기 - 예스24

댓글

GitHub 계정으로 로그인하시면 댓글과 질문을 남기실 수 있습니다. 남겨 주신 글은 이 저장소의 Discussions에 쌓입니다.

● main 231 posts UTF-8 LF © 2026 코징 RSS · GitHub