티스토리 뷰
도메인 주도 개발 시작하기라는 책에서 CQRS 패턴에 대해 잠깐 얘기가 나오는데 이를 조금 더 알고 싶어 정리하게 되었습니다. 정리한 내용은 필자의 생각을 토대로 진행되었으므로 틀린 부분이 있을 수 있습니다.
CQRS 패턴
CQRS는 명령과 조회의 책임을 분리하자는 것입니다. 명령과 조회가 무엇을 의미하는 건지 살펴볼 필요가 있을거 같습니다.
🤔 명령이란 무엇인가?
명령이란 애플리케이션에서 데이터를 저장(Create), 수정(Update), 삭제(Delete)를 하는 행위를 말합니다. 조금 더 쉽게 얘기해 보자면
어떠한 명령을 통해 객체의 상태가 변한다면 명령이라 생각할 수 있을거 같습니다.
🤔 조회란 무엇인가?
조회란 데이터 베이스 등에서 값을 읽어오는 행위를 말합니다.
🤔 왜 분리가 필요할까?
예전에 트위터에서 R과 CUD의 비율이 8:2 정도라는 글을 본적이 있는데(기억이 가물가물하기에 정확하진 않을 수 있습니다.) 조회의 비율이 엄청 높았던걸로 기억을 합니다.
여기서 각각의 성능에 더욱 더 잘 맞는 데이터 베이스를 선택할 수 있습니다. 또한 R과 CUD를 분리함으로써 복잡성을 낮출 수 있습니다.
다만 R과 CUD를 분리함으로써 코드 부분에서는 복잡성을 낮출 수 있으나 시스템 아키텍처 부분에서는 복잡성이 올라갈 거라 생각합니다.
하나의 데이터 베이스를 사용하는 경우
가장 간단하게 구현할 수 있는 방법은 데이터 베이스를 분리하지 않고 코드 수준에서 Command 역할과 Query 역할을 나눌 수 있는 방법입니다. 이렇게 분리를 한다면 코드상에서의 복잡도는 낮출 수 있습니다. 다만 동일한 데이터 베이스를 사용하므로 성능상의 이점은 없습니다.
데이터 베이스를 분리하는 경우
두번째 방법은 Command용 데이터 베이스와 Query용 데이터 베이스를 분리하여 사용하는 것입니다. 또한 데이터 베이스를 분리하였으므로 데이터 동기화를 맞추는 별도의 작업 또한 필요하게 됩니다. 이렇게 데이터 베이스를 나누게 된다면 시스템에 맞는 저장소를 선택할 수 있으므로 상황에 맞는 튜닝과 성능을 개선할 수 있습니다. 다만 데이터 베이스를 분리하였기 때문에 어떻게 데이터 싱크를 맞출것인가에 대한 고민이 필요하게 됩니다.
🤔 동기화를 어떻게 해야할까?
Command용 데이터 베이스와 Query용 데이터 베이스를 분리함에 따라 데이터를 동기화해야하는 문제가 생겼습니다. 어떻게 동기화를 할 수 있을까요?
구글링을 통해서 Command 모델의 저장에 의한 이벤트를 사용하여 Query 모델에 데이터를 동기화하는 방법이 있다는 것을 알게 되었는데 하지만 이벤트가 누락되는 경우 데이터 손실이 발생하게 되는 문제점을 가지고 있습니다.
이러한 문제를 해결하기 위해서는 트랜잭션 아웃 박스 패턴을 적용해야 한다고 합니다.
장점과 단점
💡 장점
- Command와 Query를 분리함으로써 코드상에서의 복잡성을 낮출 수 있습니다.
- 데이터 소스의 독립적인 크기를 조정할 수 있습니다. 위에서 언급한거처럼 R과 CUD의 비율이 8:2라면 데이터 베이스 인스턴스를 물리적인 설정을 할 수 있지 않을까 합니다.
- Query 모델에서 집계 함수나 NoSQL에 관련된 특화 기능을 사용하여 성능을 개선할 수 있습니다.
💡 단점
- 전반적인 시스템 아키텍처에 대한 복잡성이 올라갑니다.
- Command 데이터 베이스와 Query 데이터 베이스에 대한 동기화 이슈가 발생할 수 있으며 이에 대해 고민해볼 필요가 있습니다.
마무리
CQRS 패턴은 시스템적인 아키텍처에서만 가져갈 수 있는게 아니라는 것을 알게되었습니다. 흔히 우리가 Spring Boot를 사용하여 개발을 진행할 때 하나의 Service 영역에서 모든 것을 책임질려고 하지 않고 QueryService, CommnadService 클래스를 만들어 책임을 나눌 수 있다는 것을 알게되었으며 CQRS의 본질적인 핵심은 CUD의 행위가 이루어지는 비지니스 로직에 R과 관련된 행위가 내포되는 것을 분리하는 것이라 생각합니다. 또한 명령 쿼리 분리 원칙을 준수하면 사이드 이펙트를 방지하고 더 좋은 코드를 짤 수 있을거 같습니다.
참고 자료
'Architecture' 카테고리의 다른 글
Event Driven Architecture (0) | 2023.09.16 |
---|---|
Service Based Architecture (0) | 2023.09.13 |
Microkernel Architecture (0) | 2023.09.09 |
PipeLine Architecture (0) | 2023.09.07 |
Layered Architecture (1) | 2023.09.06 |
- Total
- Today
- Yesterday
- @ControllerAdvice
- 트랜잭셔널 아웃박스 패턴 스프링부트
- service based architecture
- redis 대기열 구현
- spring boot redisson 분산락 구현
- spring boot poi excel download
- spring boot redisson sorted set
- spring boot excel download paging
- 자바 백엔드 개발자 추천 도서
- 서비스 기반 아키텍처
- space based architecture
- polling publisher spring boot
- transactional outbox pattern spring boot
- JDK Dynamic Proxy와 CGLIB의 차이
- pipeline architecture
- java userThread와 DaemonThread
- 람다 표현식
- 트랜잭셔널 아웃박스 패턴 스프링 부트 예제
- spring boot redisson destributed lock
- microkernel architecture
- spring boot 엑셀 다운로드
- transactional outbox pattern
- redis sorted set으로 대기열 구현
- java ThreadLocal
- 레이어드 아키텍처란
- redis sorted set
- 공간 기반 아키텍처
- spring boot redis 대기열 구현
- pipe and filter architecture
- spring boot excel download oom
일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | |||||
3 | 4 | 5 | 6 | 7 | 8 | 9 |
10 | 11 | 12 | 13 | 14 | 15 | 16 |
17 | 18 | 19 | 20 | 21 | 22 | 23 |
24 | 25 | 26 | 27 | 28 | 29 | 30 |