개발은 개념싸움이야🫠

CQRS 란 무엇인가

hyunki.Dev 2023. 3. 11. 23:19

📌 들어가며

 현재 개발 중인 쿠폰 도메인에는 CQRS 패턴이 구현되어 있습니다. 이러한 CQRS 패턴이 무엇인지에 대해 경력직 채용시 면접 질문으로 질문 했다는 얘기를 점심시간에 듣게 되었습니다. 그리하여 이번 포스팅을 통해 애매하게 알고 있던 개념을 정리하고자 합니다. 

 

 

📌 CQRS 패턴을 사용하게 되는 이유

 만약 주문 내역 조회 기능을 구현하게 된다면 여러 애그리거트에 접근하여 데이터를 조회해 와야 합니다. Order에서 주문정보를, Product 에서는 상품에 대한 정보를 Member에서는 회원 관련 정보를 불러와야 합니다. 그런데 조회 화면은 그 특성상 api 의 응답 속도가 빠를 수록 좋은데 이러한 상황에서는 한 번의 select 쿼리 조회로 필요한 데이터를 읽을 수 없어 조회 속도에 문제가 생길 수 있습니다.

 

 이러한 문제가 생기는 근본적인 이유는 시스템의 상태를 변경할 때와 조회할 때 동일한 단일 도메인 모델을 사용하기 때문입니다. 도메인의 상태를 변경할 때는 크게 문제 되지 않지만 여러 애그리거트의 데이터를 가져와 정보를 출력하는 기능을 개발할 때에는 구현 시 고려해야 하는 것들이 많아 구현을 복잡하게 만듭니다. 

 

이러한 구현 복잡도를 낮추는 데 사용되는 방법이 바로 상태 변경을 위한 모델과 조회를 위한 모델을 분리하는 CQRS패턴을 사용하는 것입니다. 

 

📌 CQRS

 CQRS는 Command Query Responsibility Segregation의 약자로 상태를 변경하는 명령(Command)을 위한 모델과 상태를 제공하는 조회(Query)를 위한 모델으 분리하는 패턴입니다. 이러한 CQRS는 복잡한 도메인에 적합한 패턴입니다. 도메인이 복잡할 수록 명령 기능과 조회 기능이 다루는 데이터의 범위가 다르게 되는데 이 두 기능을 단일 모델에서 처리하게 되면 조회 기능의 로딩 속도를 위해 모델 구현이 필요 이상으로 복잡해 질 수 있습니다. 

 

 CQRS를 사용하면 각 모델에 맞는 구현 기술을 따로 가져갈 수 있습니다. 명령 모델은 객체 지향에 기반해서 도메인 모델의 상태를 변경하기에 적당한 JPA를 사용해서 구현하고, 조회 모델은 DB 테이블에서 SQL로 데이터를 조회할 때 좋은 MyBatis를 사용해서 구현할 수 있습니다. 

 

CQRS 모델이 적용된 패키지의 구조

현재 개발 중인 도메인은 위의 패키지 구조 이미지와 같이 쿼리 service 와 명령 service 가 구분되어 있습니다. 그런데 이는 엄밀히 말하면 조회 서비스와 명령에 관련된 응용 서비스를 구분해 놓았을 뿐 모델을 구분해서 사용하고 있지는 않습니다. 물론 queryservice 에 조회 성능을 높이기 위한 redis cache 등이 적용되어 조회 성능을 높이기 위한 기법이 사용되어 CQRS를 적요하는 것과 같은 효과를 보이고 있지만 모델은 구분되어 있지 않습니다. 

 

CQRS 구현 방식의 예

 

 위의 그림은 DDD-START 책에 제시된 CQRS 구현 방식의 예입니다. 해당 그림을 보면 조회 모델에는 응용 서비스가 존재하지 않습니다. 단순히 데이터를 읽어와 조회하는 기능은 응용 로직이 복잡하지 않기 때문에 컨트롤러에서 바로 DAO를 실행해도 무방합니다. 물론 데이터를 표현 영역에 전달하는 과정에서 몇 가지 로직이 필요하다면 응용 서비스에 로직을 구현할 수 있습니다.

 

 이렇게 명령 모델과 조회 모델이 서로 다른 데이터 저장소를 사용할 경우 데이터 동기화의 시점에 따라 구현 방식이 달라질 수 있습니다. 명령 모델에서 데이터가 바뀌자마자 변경 내역이 조회 모델에 반영되어 야 한다면 동기 이벤트와 글로벌 트랜잭션을 사용해서 실시간으로 동기화 할 수 있습니다. 하지만 동기 이벤트와 글로벌 트랜잭션은 전반적인 성능(응답 속도와 처리량) 저하의 주 원인이 되므로 사용에 주의를 해야 합니다.

 

📌 CQRS의 장단점 

CQRS 패턴을 적용할 때의 장점은

  • 명령 모델을 구현할 때 도메인 자체에 집중 할 수 있습니다.
    • 규모가 큰 도메인은 주로 상태 변경 로직이 복잡한데 조회 성능을 위한 코드가 명령 모델에 없으므로 도메인 로직 구현에 집중이 가능합니다. 
  • 조회 성능을 향상시키는데 유리합니다.
    • 조회 단위로 캐시 기술 적용이 가능합니다.
    • 조회 전용 저장소를 사용하면 조회 처리량을 대폭 늘릴 수 있습니다.

 

CQRS 패턴을 적용할 때의 단점은

  • 구현해야 할 코드가 단일 모델에 비해 증가합니다.
    • 단일 모델을 사용할 때 발생하는 복잡함 대문에 발생하는 구현 비용과 
    • 조회 전용 모델을 만들 때 발생하는 구현 비용을 따져야 합니다.
  • 더 많은 구현 기술이 필요합니다.
    • 명령 모델과 조회 모델을 다른 기술을 사용해서 구현하기도 하고  경우에 따라 다른 저장소를 사용하기도 합니다.

 

 

이러한 장단점을 모두 고려하여 현재 도메인에 가장 적합한 구조를 채택해야 합니다. 도메인이 그닥 복잡하지 않은데 CQRS 패턴을 도입하게 되면 두 모델을 유지하는 비용만 높아지고 이점이 없을 수 있습니다.

 

 

참고 : DDD-START! 도메인 주도 설계 구현과 핵심 개념 익히기