CQRS 패턴이란?
주말동안 우리가 진행하는 프로젝트에서 난 백엔드 팀원으로서 ERD 설계를 하던 중이였다. ERD 설계를 다 하고 다이어 그램을 확인해보니...
위의 사진과 같이 루트 테이블을 기반으로 JOIN 문이 많아질 것 같았다. 이는 곧 DB의 성능 저하가 발생한다.
(왜냐하면 여러 테이블을 참조하는 경우가 많아지면 쿼리의 복잡성이 증가하고, DB성능에 영향을 줌)
그래서 이를 나중에 어떻게 해결하는게 좋을까 머리를 싸매다가 CQRS 라는것을 우연히 찾게 되었다.
그래서 CQRS란?
CQRS (Command Query Responsibility Segregation) 패턴은 명령(Command) 과 쿼리(Query)를 분리하여 시스템의 읽기 성능과 쓰기 성능을 각각 최적화하는 아키텍처 패턴이다. 이를 통해 JOIN 쿼리가 많아져 복잡성이 증가하는 문제를 해결할 수도 있겠다 생각하여 블로그에 간단히 공부하고 작성해본다.
CQRS 패턴 개념
- Command (쓰기 작업) :
- 데이터베이스에 변경(삽입, 수정, 삭제)를 발생시키는 작업이다.
- Command는 데이터를 쓰는 작업에 집중하며, 데이터 일관성을 보장하기 위해 트랜잭션이나 복잡한 데이터 처리 로직을 사용한다. - Query (읽기 작업) :
- 데이터베이스에서 조회하는 작업이다.
- Query는 빠른 읽기 성능을 제공하도록 최적화되며, 읽기 전용 데이터를 관리한다.
- JOIN을 최소화하거나, 역정규화된 데이터를 사용하여 성능을 개선할 수 있다.
CQRS가 왜 필요한가?
전통적인 CRUD 아키텍처 기반에서 Applicationd을 개발 및 운영하다 보면, 자연스럽게 Domain Model의 복잡도가 증가하고 그에 따라 유지보수의 비용이 증가하고 Domain model은 설계의 방향과 다르게 변질된다. 특히 요즘처럼 고급화된 UI, 어려워진 Business, 자주 변하는 요구사항에서 이러한 Model을 설계하는 것은 어렵다.
이러한 흐름에서 대부분의 정책이나 제약은 데이터 변경 (C, U, D)에서 처리되고, 데이터 조회(R) 작업은 단순 데이터 조회인데, 동일 Domain Model로 처리하면 필요하지 않은 Domain 속성들로 인해 복잡도가 증가한다.
따라서 위와 같은 문제를 해결하기 위해 명령을 처리하는 책임과 조회를 처리하는 책임을 분리하는 해법을 찾았고 이 방법이 CQRS이다.
전통적인 CRUD 시스템
기본적인 CRUD 시스템은 다음 그림과 같이 계층 구조를 지니고 있다. 이에 CQRS 패턴을 적용하기 위한 방법으로 크게 최소 3가지 방법이 있다.
1. Simple CQRS architecture
이는 단일 Data Store에 Command Query Model을 분리된 계층으로 나누는 방식이다.
위의 그림처럼 Database(RDBMS)는 분리하지 않고 기존 구조를 유지하고 Model Layer 부분과 Command와 Query Model 로 분리하는 수준으로 간단하게 적용할 수 있다.
이는 Application Layer에서 Command Model과 Query Model을 분리하는 방식이다. 이 구조는 데이터 저장소를 분리하지 않고도, 읽기 작업과 쓰기 작업을 각각 다른 모델로 분리함으로써, 두 가지 요구사항을 독립적으로 처리할 수 있다.
장점 : 단순하게 구현 및 적용가능
단점 : 동일한 Database 사용에 따른 성능상 문제점 개선X
2. CQRS with seperated persistance mechanisms (분리된 지속성 메커니즘을 갖춘 CQRS)
해당 방법은 Command 용 Database와 Query용 Database를 분리하고 별도의 Broker를 통해서 이 둘간의 Data를 동기화 처리하는 방식이다. 이 경우에는 데이터를 조회하려는 서비스들은 서비스를 맞는 저장소를 선택할 수 있기 때문에, polyglot 구조로 구성할 수도 있다. 이 경우에는 각각의 Model에 맞게 저장소(RDBMS, NOSQL, Cache)를 튜닝해서 사용할 수도 있다.
Command Model:
- 쓰기 작업을 처리하며, 데이터베이스에 변경(삽입, 수정, 삭제)을 발생. 주로 RDBMS 같은 트랜잭션을 보장할 수 있는 데이터베이스를 사용하여 데이터 일관성을 보장
- 예시: MySQL, PostgreSQL 등
Query Model:
- 읽기 작업에 최적화된 별도의 데이터베이스를 사용. 빠른 조회를 위해 NoSQL, Cache와 같은 데이터 저장소를 선택할 수 있습니다. 이 모델은 읽기 성능을 극대화하는 데 초점을 맞춤.
- 예시: Redis, MongoDB, Elasticsearch 등
위의 구조는 성능 최적화를 위해 쓰기 작업과 읽기 작업을 각가 다른 데이터 저장소로 처리하고, 다양한 데이터베이스(RDBMS, NoSQL, Cache)를 혼용하여 사용하는 방식이다. 이는 단순한 CQRS 패턴보다 복잡하지만, 대규모 시스템에서 성능 문제를 해결하고 확장성을 높이는 데 매우 유용하다.
참고 : polyglot 란 다수의 Database를 혼용하여 사용하는 것, Command와 Query 작업에 각각 가장 적합한 데이터베이스를 선택할 수 있으며, 이를 통해 성능을 최적화
장점 : Simple CQRS에서 거론되는 Database 사용에 발생하는 성능 관점의 문제를 해결할 수 있다.
단점 : 동기화 처리를 위한 Broker의 가용성과 신뢰도가 보장이 되어야 한다.
---------- ---------- ---------- ---------- ---------- ---------- 정리 ---------- ---------- ---------- ---------- ---------- ----------
CQRS의 이점
- 독립적인 크기 조정 : CQRS를 통해 읽기 및 쓰기의 워크로드를 독립적으로 확장가능
- 최적화된 데이터 스키마 : 읽기 쪽에서는 쿼리에 최적화된 스키마를 사용하고, 쓰기에서는 업데이트에 최적화된 스키마를 사용
- 보안 : 올바른 도메인 엔티티만 데이터를 쓰기를 수행할 수 있는지 쉽게 확인 가능
- 유연한 모델 생성 : 대부분의 복잡한 비즈니스 논리는 쓰기 모델로 이동시키고 읽기모델은 상대적으로 간단하게 정리하여 유지가능하고 유연한 모델을 만들 수 있음
- 단순한 쿼리 : 읽기 데이터베이스에서 구체화된 뷰를 저장하여 쿼리 시 복잡한 조인을 방지할 수 있음.
'백엔드' 카테고리의 다른 글
OAuth2 (1) | 2024.10.19 |
---|---|
소셜로그인 어떻게 도입할까? (1) | 2024.09.22 |
ERD 설계? 어떻게 진행할까? (0) | 2024.09.18 |
관계형 데이터베이스 (1) | 2024.09.10 |
SSR? CSR? 렌더링 방식의 차이와 이해 (2) | 2024.09.06 |