[MSA] CQRS 패턴 적용하기

나르·2022년 2월 13일
1

Architecture

목록 보기
1/6

CQRS 란?

CQRSCommand and Query Responsibility Segregation의 약자로, 이름과 같이 명령과 쿼리의 역할을 구분 한다는 것입니다. 즉 CRUD에서 CUD(Command)와 R(Query)의 책임을 분리한 것이 CQRS 입니다.

데이터베이스를 사용하면서 트랜젝션 ACID를 보장하기 위해 노력했습니다. 허나 MSA가 대두되고, 도메인별로 개발하고 DB를 분리하며 그 문제가 도드라지게 되었습니다.
이러한 변경 가능성과 동시성의 문제 등을 인정하고, 이를 통해서 R과 CUD를 구분함으로써 얻는 이점을 설명하는 것이 CQRS패턴입니다.

why CQRS?

개발 중이던 SNS 서비스는 쓰기 대비 읽기 요청이 매우 많은 서비스 중 하나입니다. 더불어 MSA 구조로 개발되고 있던 만큼, 그 장점을 활용해보고자 CQRS를 적용하기로 결정했습니다.

CQRS 패턴을 통해 얻을 수 있는 이점은 다음과 같습니다.

  • R과 CUD 각각에 더 최적화된 Database 구성을 통해서 성능을 더 향상시킬 수 있습니다(Polyglot DB)
  • R과 CUD를 분리함으로써 aggregation(집계 함수) 등의 읽기를 위한 도메인 속성들이 생겨나는 것을 방지해, R로 인해 Entity의 구조가 변경되는 것을 막을 수 있습니다.
  • 서비스 운영이 오래되다 보면 하나의 모델이 점점 다양한 요구사항을 녹여내기 위해 초기 모델보다 거대해지거나 변질되는 등 복잡도가 올라가게 되고, 그에 따라 유지보수 비용이 증가합니다. CUD와 단순 R을 분리함으로써 해당 문제를 방지할 수 있습니다.
  • 모델 및 쿼리가 단순화됩니다. 복잡한 비즈니스 로직은 대부분 CUD이므로, R의 모델은 상대적으로 심플하게 정리되게 되며 복잡한 join 쿼리에 대한 부담도 줄일 수 있습니다.

how to CQRS?

낮은 수준의 CQRS는 Read하는 모델을 따로 만들거나, Read Replica를 만든다거나, Read DB에 Cache를 적용하는 등 다양하게 또 간단하게 적용해볼 수 있습니다.
허나 단순 모델의 분리로는 Single DB의 성능 문제를 해결하지 못했고, 읽기 전용 DB 분리는 동기화 방식의 고민이 남아있었습니다.

때문에 더 높은 수준의 CQRS 패턴은 Event Sourcing과 함께, Queue(AWS SQS, RabbitMQ, Kafka와 같은 Message Queue가 일반적)를 이용하여 비동기적으로 데이터를 쓰고 읽어오는 형태를 취합니다.

이벤트 소싱이란 Application 내의 모든 Activity를 이벤트로 전환해서 이벤트 스트림(Event Stream)을 별도의 Database에 저장하는 방식을 의미합니다.
즉, Application 내의 상태 변경을 이력으로 관리하는 패턴의 발전된 형태로 이해하면 됩니다.
기존 ORM은 변경 사항이 업데이트되면 이전의 내역은 사라졌기 때문에, 변경 내역을 관리하는 용도로는 이벤트 소싱이 더욱 적합합니다.

이벤트 소싱을 위한 저장소는 DB나 캐시를 이용해 직접 구현할 수도, Kafka 등의 메세지큐를 이용할 수도 있습니다.
이벤트 소싱의 이벤트 스트림은 오직 추가만 가능하고, 필요로 하는 시점에 구체화 단계를 가지게 되고 이 처리과정이 CQRS의 모델 분리 관점에서 잘 맞기 때문에 주로 선택합니다.
CQRS 패턴에 이벤트 소싱은 필수가 아니지만 이벤트 소싱에는 CQRS가 필요합니다.

To be continue...

CQRS 구조 적용 후 서비스의 아키텍쳐는 다음과 같이 구성되었습니다.

read 가 빈번한 feed 서버는 Document 기반의 DB(MongoDB와 같은 NoSQL 계열)를 사용하기로 했다.

해당 구조에 대해 알게 되고 공부하면서 가장 힘들었던 부분은 그래서 어떻게 적용하는데? 였던 것 같네요...
위에 명시해뒀듯이 저는 단순히 읽기 모델을 분리하거나, DB를 분리하는 것 만으로도 CQRS를 적용했다고 말할 수 있을 것 같습니다.
개념 자체는 크게 어렵지 않으나, 또 하나의 아키텍쳐인 만큼 적용 이후로 CRUD와는 또 다른 관리 요소들이 생겨나게 됩니다.
저 또한 어떻게 두 저장소를 동기화 할 것이고, 데이터의 일관성을 어떻게 보장할 것이며, 변경과 확장에 용이하면서도 비대해지지 않으려면 어디까지가 필요한 정보인지 계속해서 고민해야 했습니다...
때문에 여타 글에서 나오듯 CQRS는 어디까지나 하나의 방법이지, CRUD보다 개선된 구조라고는 생각하지 않고, 각각에 맞는 형태가 있으니 고려해서 적용하면 좋겠습니다.

이벤트 브로커로 kafka를 사용한 이유와 적용 방법은 다른 글에서 작성하겠습니다!

Ref.

소셜 네트워크 서비스의 아키텍처에 대하여
[CQRS] CQRS 어떻게 사용할까?
[Architecture] MSA : CQRS 패턴이란
https://blog.neonkid.xyz/267
CQRS 패턴
https://www.youtube.com/watch?v=BnS6343GTkY
https://june-coder.tistory.com/32
Java의 CQRS 및 이벤트 소싱
웹서비스 백엔드 애플리케이션 아키텍처(2)-CQRS

profile
💻 + ☕ = </>

0개의 댓글