기술과 산업/아키텍처

소프트웨어 아키텍처 시리즈 13화 – CQRS 아키텍처의 실전 설계 전략: 분리를 넘어 책임의 정렬로

B컷개발자 2025. 7. 18. 12:26
728x90

CQRS는 단순히 읽기와 쓰기를 나누는 패턴이 아닙니다. 올바른 책임 분리를 통해 복잡한 시스템을 정리하고, 확장성과 유지보수를 확보할 수 있는 구조적 전략입니다. 이번 글에서는 실전 아키텍처에 CQRS를 도입할 때의 설계 방식과 고려사항을 자세히 다룹니다.
 
 

CQRS는 왜 생겨났는가?

 
전통적인 시스템에서는 데이터 모델이 단일하게 사용되며, 같은 레이어에서 읽기와 쓰기를 모두 처리합니다. 하지만 복잡한 도메인에서는 다음과 같은 문제가 자주 발생합니다:
 

  • 읽기/쓰기 요구사항이 전혀 다름
    • 예: 관리자 페이지는 복잡한 통계 기반 조회, 주문 처리 로직은 트랜잭션 중심
  •  
  • 성능 최적화 방향이 다름
    • 읽기는 캐싱, 인덱스 설계가 중요하고
    • 쓰기는 무결성과 트랜잭션 관리가 핵심
  •  
  • 모델의 책임이 혼재되어 복잡성 증가
    • 하나의 서비스/엔티티가 지나치게 많은 역할을 수행
  •  

 
이러한 문제를 해결하기 위한 전략으로 등장한 것이 CQRS입니다.
 


 

CQRS 구조 핵심 요약

[ UI ]
 ┣━▶ [ Command Service ] ─▶ [ 도메인 모델 / 이벤트 생성 ]
 ┗━▶ [ Query Service ] ──▶ [ 읽기 최적화 모델 / Projection ]

구성 요소책임

Command상태 변경 처리
Query상태 조회 처리
도메인 모델비즈니스 규칙, 트랜잭션 책임
Projection읽기용 데이터 모델, 성능 최적화용
Event Handler쓰기 결과를 읽기 모델로 반영

 


 

실전 예제 – 상품 주문 시스템

 
Use Case 1: 주문 등록
 

  • PlaceOrderCommand → Command Handler에서 도메인 호출
  • 주문 엔티티가 생성되고, OrderPlacedEvent가 발생
  • 이벤트 핸들러가 읽기 모델(예: OrderSummaryView)를 갱신

 
Use Case 2: 주문 목록 조회
 

  • OrderQueryService.getOrders(userId) 호출
  • 읽기 전용 DB 또는 캐시된 Projection에서 주문 목록 반환

 


 

Projection 모델 설계 팁

 

  1. View 중심 데이터 모델링
    • 고객이 자주 조회하는 항목을 중심으로 테이블 재구성
    • 주문 목록, 상품 추천, 최근 활동 로그
  2.  
  3. 데이터 중복 허용
    • Projection은 정규화보다 속도와 사용 편의성 우선
    • 정합성은 쓰기 모델에서 보장
  4.  
  5. 비동기 업데이트 전략 필요
    • 도메인 이벤트 수신 후 비동기로 Projection 갱신
    • 일관성은 Eventually Consistent 방식 채택
  6.  

 


 

Command 모델 설계 시 주의점

 

  • 쓰기 모델은 오직 의미 있는 유즈케이스 단위로 설계
  • 도메인 규칙을 철저히 캡슐화 (엔티티, 밸류 객체 중심)
  • 외부 의존성은 포트를 통해 분리 (ex. 결제 API, 외부 시스템 호출)

 


 

실무에서 자주 저지르는 실수

실수설명

읽기/쓰기 모델 분리 없이 서비스만 분리구조가 분리된 것처럼 보이지만 실제로는 하나의 DB와 모델을 공유하고 있음
Projection을 너무 일반화도메인 모델과 Projection이 너무 유사해지고, 성능 개선 효과 없음
이벤트 누락 또는 순서 보장 실패비동기 이벤트 기반 시스템에서 가장 흔한 오류

 


 

CQRS와 헥사고날 아키텍처의 연결점

 
CQRS의 구성요소는 헥사고날 아키텍처의 구조와 자연스럽게 연결됩니다.
 

  • Command는 Inbound Port로 설계되고, 도메인과 연계
  • Query는 별도의 Adapter 혹은 Read-Only UseCase로 구현
  • Projection 갱신은 Outbound Port 또는 비동기 Subscriber에서 수행

 

즉, 헥사고날 구조는 CQRS의 흐름을 물리적으로 격리할 수 있게 해주는 좋은 틀이 됩니다.

 


 

CQRS 도입 기준 체크리스트

 
다음 중 다수에 해당하면 CQRS를 도입할 수 있습니다:
 

  • 읽기 성능이 매우 중요한 시스템이다
  • 도메인이 복잡하여 비즈니스 로직 분리가 절실하다
  • 이벤트 소싱을 병행하고자 한다
  • 읽기/쓰기 모델이 구조적으로 완전히 다르다
  • 실시간 통계나 분석 조회가 빈번하다

 
그렇지 않다면 굳이 CQRS까지 가지 않아도 됩니다.
단순한 CRUD 서비스에서 CQRS는 복잡성을 도입하는 요인이 될 수 있습니다.
 


 

‘책임을 분리한다’는 의미

 
CQRS는 단순한 기술 트렌드가 아니라, 소프트웨어에서 읽기와 쓰기라는 본질적으로 다른 책임을 올바르게 분리하자는 설계 철학입니다.
 
그 철학이 잘 적용된 구조는 다음과 같은 결과를 줍니다:
 

  • 도메인은 복잡한 로직에 집중할 수 있고
  • 읽기는 사용자에게 최적화된 경험을 제공하며
  • 시스템은 변화에 유연하게 대응할 수 있습니다

 
하지만 그만큼 아키텍처 설계, 이벤트 처리, Projection 모델링 등에서 선택과 집중이 필요합니다.

728x90