CQRS는 Command Query Responsibility Segregation(명령과 조회의 책임 분리)의 약자로 이름처럼 명령을 처리하는 책임과 조회를 처리하는 책임을 분리하는 것이 CQRS의 핵심입니다.
CQRS는 초기 CQS에서 시작되어 확장되었습니다.
CQS는 Command Query Separation의 약자로 시스템에서 처리되는 명령과 조회, 이 두 작업을 정의하는 핵심 개념이자, 이 둘을 분리시키는 디자인 패턴입니다.
그렇다면 명령과 조회에 대해서 정의를 내릴 필요가 있습니다. CQRS에서 명령은 상태를 변경하는 작업을 의미하며 조회는 상태를 반환하는 작업을 의미합니다.
CQRS 패턴을 마이크로서비스에 적용하여 살펴보겠습니다. 마이크로서비스의 핵심은 서비스별 데이터 저장소를 각기 다르게 채택한다는 점입니다.
이때 서비스 성능 향상을 위해서 인스턴스를 스케일 아웃하여 여러 개로 실행할 경우 빈번한 명령과 조회 작업으로 리소스 교착상태가 발생할 수 있습니다.
뿐만 아니라, 통상적으로 명령보다 조회 요청이 훨씬 많이 사용되기 때문에, 하나의 서비스 내에 이러한 모든 기능을 넣어두면, 조회 요청 빈도가 증가함에 따라 명령기능도 함께 확장해야 하기 때문에 도메인의 복잡도가 높아집니다.
이러한 문제점을 해결하기 위한 방법 중 하나로, CQRS 패턴을 사용합니다. 기존에 하나의 데이터 저장소에 CRUD 작업을 모두 처리했다면, CQRS는 요청을 크게 명령(Create, Update, Delete)과 조회(Read)로 나누어 처리합니다.
도식으로 살펴보면, 먼저 단순히 모델을 나누는 형태로 명령과 조회를 분리할 수 있습니다. 하지만 하나의 데이터 저장소를 사용한다는 면에서 완벽하게 마이크로서비스 설계 철학과 부합하는 것은 아닙니다.
또는 아예 물리적으로 명령 작업과 조회 작업을 위한 저장소를 따로 준비할 수 있습니다. 이처럼 명령과 조회를 각각 분리하면 명령(쓰기) 요청의 부하를 줄이고, 조회 대기 시간을 줄이는 등 다양한 이점을 누릴 수 있습니다.
CQRS 패턴은 이벤트 소싱 패턴과 함께 사용되기도 합니다. 기본적으로 앞서 살펴본 메시지 브로커를 이용한 이벤트 주도의 아키텍처의 경우, 이벤트로 인해 상태가 변경된 경우, 이를 데이터 모델로 처리하고 최종값을 반영하는 형태를 의미합니다. 하지만 이벤트 소싱 패턴의 경우, 이를 데이터로 저장하는 것이 아니라 상태 변경 이벤트 자체를 저장하는 기법을 의미합니다.
이렇게 하면 메시지 브로커와 데이터 저장소를 분리하지 않아도 될 뿐만 아니라, 데이터로 변경하는 복잡한 과정이 없어 쓰기 속도도 빠르고, 이벤트에 따른 CRUD를 전부 처리할 필요 없이, 이벤트 발생/조회만 처리하면 되어 서비스 확장을 조금 더 용이하게 할 수 있습니다. 다시 말해, 이벤트는 한 번 발생한 후에 수정되지 않고 업데이트나 삭제 없이 입력만 되는 개념이기 때문에 저장소에 이러한 이벤트를 저장(쓰기)해두고, 필요한 데이터가 생기는 시점에 축적된 이벤트를 조회(읽기) 하기만 하면 되는 형태로, CQRS와 같은 맥락의 패턴을 가집니다. 따라서 이벤트 소싱과 CQRS는 함께 사용하기 좋은 패턴입니다.
이벤트 소싱이란 영속 데이터를 어떤 식으로 저장할 것인지에 관한 것으로,
기존에 저희가 대중적으로 사용하고 있는 데이터 저장 방법은 현실 세계의 것들을 직접적으로 표현하고 있는 도메인 객체를 DB에 담는 방식이었습니다.
이러한 방식은 직관적이어서 이해하기 쉽다는 장점이 있지만, 항상 도메인 객체의 최종 상태만을 담고 있기 때문에 변경된 기록을 정확하게 추적할 수 없고, 한 데이터에 대해 검색 및 변경 요청이 빈번하게 발생하기 때문에 동시성 문제를 갖고 있다는 단점이 존재합니다.
반면 이벤트 소싱 방식은 도메인 객체를 생성하고, 상태를 변경하기 위해 발생하는 이벤트(Event)들을 DB에 저장함으로써 위에 언급한 문제들의 해결을 시도합니다.
이벤트 소싱 방식에서는 도메인 객체에 대한 변경 이벤트를 모두 추적할 수 있으며,
이벤트는 한 번 발생한 이후 수정되지 않기 때문에 UPDATE나 DELETE 없이 항상 INSERT 작업만 일어납니다. 따라서 동시성 문제로부터 비교적 자유롭습니다.
즉 기존에 데이터 결과물만 저장하는 것이 아닌 데이터의 모든 이벤트들을 기록하여 그 이벤트들의 최종 결과를 조회한다고 보시면 될것 같습니다. (저희가 일반적으로 이해하는 데이터랑 느낌이 다르네요!)