시스템이 제공하는 기능은 크게 두 가지로 나눌 수 있다.
1. 상태를 변경하는 기능
ex) 새로운 주문 생성, 배송지 정보 변경
2. 상태 정보를 조회하는 기능
ex) 주문 상세 내역 보기, 회원 정보 보기
도메인 모델 관점에서 상태 변경 기능은 주로 한 애그리거트의 상태를 변경한다. 예를 들어 주문 취소 기능, 배송지 정보 변경 기능은 한개의 Order 애그리거트를 변경한다. 반면 조회 기능에 필요한 데이터를 표시하려면 두 개 이상의 애그리거트가 필요할 때가 많다.
상태를 변경하는 범위와 상태를 조회하는 범위가 정확하게 일치하지 않기 때문에 단일 모델로 두 종료의 기능을 구현하면 모델이 불필요하게 복잡해진다. 이러한 복잡도를 해결하기 위해 사용하는 방법이 CQRS다.
CQRS
Command Query Responsibility Segregation, 상태를 변경하는 명령을 위한 모델과 상태를 제공하는 조회를 위한 모델을 분리하는 패턴이다.
CQRS는 복잡한 도메인에 적합하다. 도메인이 복잡할수록 명령 기능과 조회 기능이 다루는 데이터 범위에 차이가 난다.
이 두 기능을 단일 모델로 처리하면 조회 기능의 로딩 속도를 위해 모델 구현이 필요 이상으로 복잡해진다. CQRS 패턴을 통해 둘을 분리하는 것이다.
위처럼 조회를 위한 모델을 따로 분리하게 될 경우 복잡하게 Join, SubQuery, N + 1 문제 등 조회와 관련된 고민을 줄일 수 있다. 또한 조회에 최적화된 DB를 따로 구축하기도 편하다.
만약 데이터 베이스를 분리할 경우, 데이터베이스 간 동기화가 문제인데 이는 이벤트를 활용해 처리한다. 명령 모델에서 상태를 변경하면 이에 해당하는 이벤트가 발생하고, 그 이벤트를 조회 모델에 전달해서 변경 내역을 반영하면 된다.
그런데, 동기화가 실시간으로 이뤄져야 한다면 동기 이벤트, 글로벌 트랜잭션을 사용해야 하는데 전반적인 성능(응답 속도, 처리량)이 떨어지는 단점이 존재한다.
하지만 실시간으로 동기화해도 되지 않는 영역이 존재한다고 해보자. 예로 들면 통계 데이터이다. 소추, 수분 또는 1시간 단위로 최근 데이터를 반영해도 문제가 되지 않을 때가 있다. 이런 경우라면 비동기로 데이터를 보냄으로써 데이터 동기화로 인해 명령 모델의 성능이 나빠지지 않도록 할 수 있다.
웹과 CQRS
일반적인 웹 서비스는 상태를 변경하는 요청보다 상태를 조회하는 요청이 많다. 예로 들면 주문 요청보다 상품의 상세 정보를 조회하는 요청이 비교할 수 없을 정도로 많다.
그 만큼 조회 기능 요청 비율이 높기 때문에 개발팀은 조회 성능을 높이기 위해 다양한 기법을 사용한다. 쿼리 최적화, 캐싱 혹은 조회 전용 저장소를 따로 사용하기도 한다.
대규모 트래픽이 발생하는 웹 서비스는 알게 모르게 CQRS를 적용하게 된다. 단지 명시적으로 명령/조회 모델을 구분하지 않을 뿐이다.
CQRS 장단점
CQRS 패턴을 적용했을 때 얻을 수 있는 장점 명령 모델을 구현할 때 도메인 자체에 집중할 수 있다는 점이다. 또한 조회 성능을 향상시키는 데 유리하다는 점이다.
한편 단점도 있다. 구현해야 할 코드가 더 많다는 점이다. 더 많은 구현 기술이 필요하기도 하다. 조회 모델을 따로 구현하기 위해 다른 데이터베이스를 사용하기도 하고 데이터 동기화를 위해 메시징 시스템을 도입해야 할 수도 있다.
'개발일기장' 카테고리의 다른 글
AWS 람다로 서버리스 서비스 만들기 (2) AWS lambda 적용 (0) | 2023.04.21 |
---|---|
AWS 람다로 서버리스 서비스 만들기 (1) 로컬에서 테스트 (0) | 2023.04.21 |
DDD 아주 살짝 맛보고 후기 남기기 (0) | 2023.04.16 |
Bulk INSERT로 그룹 시작 기능 성능을 최적화 해보겠습니다. (0) | 2023.04.15 |
동시성 문제 - 원인과 해결 (2) (0) | 2023.04.13 |