오늘의 키워드
CQRS, 나의 컨셉
CQRS
이전의 프로젝트에서 MA를 MSA로 변경하며 DB 구성에 대한 고민을 한 적이 있다.
예를들어, prodcut-service에서 Product의 List를 불러오는 API가 있다.
해당 List를 가지고 올 때 각 Product마다 Product를 생성한 User의 정보도 함께 가져오고 싶었다.
간단하게 생각할 수 있는 경우는 각 Product마다 user-service의 User정보를 가져오는 API를 호출하여 User정보를 가져올 수 있다. 이렇게 생각했을 때 JPA에서의 N+1문제와 비슷한 문제가 발생한다고 생각하여 이 방법이 맞는 것일까? 실무에서는 어떤 방식으로 DB를 구성할까? 의문을 가졌었다.
오늘은 해당 방안 중 한 방법인 CQRS 패턴이라는 키워드를 알게 되어 개념을 알아보고자 한다.
CQRS는 Command and Query Responsibility Segregation의 약자로,
단순히 명령에 해당하는 영역과 조회에 해당하는 영역을 분리한다는 뜻을 가지고 있다.
서비스를 개발할 때 초기에는 단순한 아키텍처로 구성되고, 명령을 수행하는 부분과 고객이 조회하는 부분이 있을 때 비즈니스 로직은 적절히 나누어지지만, 모델은 대체로 하나의 모델이 명령과 조회를 모두 수행하는 경우가 많다.
모델에서는 내부에서만 사용되는 관리용 데이터나 각종 이슈(성능 등)로 실제 조회에 이용되지 않는 여러 데이터들이 생긴다. 노출 측면에서는 외부 API(재고, 배송 등)로 주입받는 정보들이 생기고 도메인과 모델이 복잡해지는 상황이 생긴다.
이런 상황들로 인해 명령과 관련된 로직과 조회와 관련된 로직들이 하나의 모델을 바라보며 서로 의존성을 갖고 영향을 주는 상태를 유지할 수밖에 없게되어 유지보수가 힘들어 질 수 있다.
해당 문제를 해결하기 위해 큰 도메인 안에서 명령과 조회에 해당하는 영역을 나누어 문제를 해결하는 것이 CQRS가 바라는 방향이다.
교집합인 모델을 분리
복잡한 구조를 나누기 위해 기존 명령과 조회를 모두 수행하던 모델을 두 형태로 분리한다.
명령 모델은 기존 도메인 모델, 조회 모델은 전시 광고 등으로 노출해서 이용되는 비정규화된 데이터를 한번 더 정리한다.
조회모델은 Join이나 연산 작업을 극히 제한해야 한다. 가능하면 DB에 있는 값 그대로를 들고 곧바로 이용 가능한 형태로 제공하라고 권장하기에 조회를 위한 새로운 테이블 설계가 필요하다. 즉, 조회 모델을 만드는 작업은 최적화된 스키마를 비정규화한다는 뜻이다. 때문에 포맷을 JSON 포맷이 주로 이용되고 NoSQL을 쓰는 경우도 많다고 한다.
다만, 명령 모델 변경 시 생성하기 때문에 적은 횟수로 명령을 수행하고, 많은 조회가 이루어지는 도메인에서 큰 이점을 얻을 수 있을 것이다.
UX 변경이 작고 비즈니스가 자주 변화하는 서비스에서 이렇게 분리된 영역은 실제 개발하는 입장에서도 부수적으로 실수할 여지를 더욱 줄여준다고 한다.
서로 다른 저장소
데이터가 분리되어 존재한다는 건 서로 다른 저장소를 이용하도록 수정 가능하다는 말이 된다. 향후 조회 모델을 이용하는 형태에 따라 redis, 엘라스틱 서치 등 다양한 데이터 저장소를 선택할 수 있는 확장성에도 큰 장점을 갖게된다.
다만, 저장소가 나뉘게 되면 두 저장소 간 데이터 정합성을 보장할 수 있어야 하고, 관리의 요소가 늘어난 상태이기 때문에 시스템이 안정적으로 안착할 때까지는 모니터링에 좀 더 힘을 써 주어야 한다.
조회 모델을 생성하는 책임 분리
조회 모델을 생성하는 시점이 명령 모델의 변경으로부터 이루어지는 영역의 입장을 생각해보면, 조회 모델을 이용하는 도메인의 성능은 매우 개선될 수 있었는 반면, 생성의 책임을 떠안은 쪽은 손해만 보게 된 상황이다. 조회 모델 생성 자체에 이용되는 리소스가 매우 많은데, 고스란히 떠안아 벌이게 된다. 이때 적용할 수 있는 패턴이 Event Store 패턴이다.
이벤트 소싱 패턴
이벤트 소싱 패턴은 어떠한 애플리케이션으로부터 발생된 이벤트를 이벤트 스토어에 저장하고, 이를 여러 시스템이 소비하여 다룰 수 있는 패턴이다.
CQRS와 결합된 이벤트 소싱 패턴은 데이터를 관리하는 측면과 조회 모델을 생성하는 이 두 작업을 나누어 주는 역할을 한다.
명령 모델에서 변경 감지가 되었을 때, 조회 모델을 생성하기 위한 로직을 그곳에서 작성하는 것이 아닌, 단순 변경된 상태를 전달하고, 전달된 데이터가 스트림에 쌓이면 해당 데이터를 소비하여 조회 모델을 생성하게 된다.
이렇게 되면 명령 모델의 부담을 분산할 수 있다.
느낀점
Product와 User의 조회시 결합도가 많이 높다고 생각이 된다면, CQRS를 활용하여 Product와 User 각각의 명령 서비스와 Prodcut 조회 서비스로 분리하여 작업을 하는 방식을 사용할 수 있을 것 같다.
언제 CQRS?
- UX와 비지니스 요구 사항이 복잡해질 때
- 조회 성능을 보다 높이고 싶을 때
- 데이터를 관리하는 영역과 이를 뷰로 전달하는 영역의 책임이 나뉘어져야 할 때
- 시스템 확장성을 높이고 싶을 때
나의 컨셉? 장점?
나는 어떠한 사람인가.. 매력적인 컨셉, 장점이 필요하고 해당 내용을 한줄로 요약할 수 있는 것이 중요하다는 점을 다시 깨달은 날이다.!
'TIL' 카테고리의 다른 글
[TIL] 2025.02.18 queryDSL 패키지 경로 문제.. (0) | 2025.02.18 |
---|---|
[TIL] 2025.02.17 테이블 네이밍, 식별관계 (0) | 2025.02.17 |
[TIL] 2025.02.14 플로이드 워셜 (0) | 2025.02.14 |
[TIL] 2025.02.13 패키지 구조(계층형/도메인형, Infrastructure 계층) (0) | 2025.02.13 |
[TIL] 2025.02.12 양방향 (0) | 2025.02.12 |