[클라우드] - CQRS

2024. 10. 22. 16:30현대 오토에버 SW 스쿨 - 클라우드/클라우드

SMALL

1. 개요

  • Command and Query Responsibility Segregation 의 약자로 데이터 저장소로부터 읽기 와 업데이트 작업을 분리하는 패턴
  • CQRS를 사용하면 애플리케이션의 확장성, 퍼포먼스, 보안성을 극대화할 수 있고 여러 요청으로부터 들어온 복수의 업데이트 작업들도 충돌을 방지할 수 있음

2. 전통적인 방식의 문제점

  • 전통적인 아키텍쳐에서는 데이터베이스에서 조회하고 업데이트하는데 같은 데이터 모델을 사용
  • 간단한 CRUD 작업에서는 문제없이 동작을 하지만 복잡한 애플리케이션에서는 유지보수를 어렵게 만들 수 있음
  • 데이터 조회를 할 때는 여러 다른 형태의 DTO를 반환하는 매우 다양한 쿼리들을 수행할 수 있는데 각각 다른 형태의 DTO 들에 객체 매핑 작업은 복잡해 질 가능성이 있으며 데이터를 쓰거나 업데이트 할 때는 복잡한 유효성 검사 와 비지니스 로직이 수행되어야 하는데 이 모든 걸 하나의 데이터 모델이 수행하면 너무 많은 것을 수행하는 복잡한 모델이 됨
  • 읽기 와 쓰기의 트래픽은 일반적으로 같지 않기 때문에 각각에 대해서 다른 성능이 요구되는 경우가 많음
  • 읽기 와 쓰기 작업에서 사용되는 데이터 표현들이 서로 일치하지 않는 경우가 많은데 그로 인해서 일부 작업에서는 필요하지 않은 추가적인 컬럼이나 속성의 업데이트가 이루어 져야 함
  • 동일한 세트에 대해 병렬로 작업이 수행될 때 데이터 경합이 발생할 수 있음
  • 정보 조회를 위해 요구되는 복잡한 쿼리로 인해 성능에 부정적인 영향을 줄 수 있음
  • 하나의 데이터 모델이 읽기 와 쓰기를 모두 수행하기 때문에 보안 관리가 복잡해 질 수 있음

3. 해결책

  • 읽기 와 쓰기를 분리해서 각각 다른 모델로 분리해서 명령을 통해 데이터를 쓰고 쿼리를 통해 데이터를 읽음
  • 명령(Command)은 데이터 중심적이 아니라 수행할 작업 중심이 되어야 하는데 호텔룸의 상태를 예약됨으로 변경한다 가 아니라 호텔 룸 예약 과 같이 생성
  • 조회(Query)는 데이터베이스를 결코 수정하지 않는데 쿼리는 어떠한 도메인 로직도 캡슐화하지 않은 DTO 만을 반환
  • 읽기/쓰기 모델들은 서로 격리될 수 있는데 이렇게 읽기/쓰기 모델을 분리하는 것은 애플리케이션 디자인 과 구현을 더욱 간단하게 만들어주지만 CQRS 코드는 ORM 툴을 이용해서 스키마로부터 자동으로 생성되도록 할 수 없다는 단점이 있음
  • 확실한 격리를 위해서 물리적으로 읽기 와 쓰기를 분리할 수 있음
    • 읽기 DB의 경우 복잡한 조인문이나 ORM 매핑을 방지하기 위해서 Material View를 가지는 조회에 최적화된 별도의 DB 스키마를 가질 수 있도록 만들 수 있는데 단지 다른 DB 스키마가 아니라 아예 다른 타입의 저장소를 사용할 수 있는데 이 때 보통 쓰기의 경우는 RDBMS를 읽기의 경우는 NoSQL을 사용하기도 합니다.
  • 별도의 읽기/쓰기 데이터 저장소가 사용된다면 반드시 동기화가 이루어져야 하는데 쓰기 모델이 DB에 수정 사항이 발생할 때 마다 이벤트를 발행함으로써 이루어지며 이 때 DB 업데이트와 이벤트 발행은 하나의 트랜잭션 안에서 이루어져야 합니다.
  • 읽기 저장소는 단순히 쓰기 저장소의 레플리카(복제본) 일 수 도 있고 완전히 다른 구조를 가질 수 도 있음
  • 읽기 와 쓰기를 분리하게되면 각각의 부하에 맞게 스케일링 하는 것을 가능하게 해줌
  • 읽기 저장소가 쓰기보다 더 많은 부하를 갖음 

4. CQRS 의 장점

  • 독립적인 스케일링
  • 최적화된 데이터 스키마
  • 보안
  • 관심사 분리(AoP): 복잡한 비지니스 로직은 쓰기 모델에만 필요
  • 간단한 쿼리: 읽기 저장소의 material view를 통해서 복잡한 조인문을 사용할 필요가 없음

5. 구현 이슈

  • 복잡성
  • 메세징: 명령을 수행하고 업데이트 이벤트를 발행해서 데이터를 수정해야 하기 때문에 메세지 전송 실패나 중복 메세지에 대한 처리가 필요
  • 데이터 일관성: 명령을 수행하고 이벤트를 발행해서 읽기 모델에 업데이트를 하더라도 어쩔 수 없는 딜레이가 발생

6. CQRS 를 사용해야 하는 경우

  • 많은 사용자가 동일한 데이터에 병렬로 액세스 하는 경우: 읽기가 많은 시스템
  • 복잡한 프로세스나 도메인 모델을 통해 가이드 되는 작업 기반 사용자 인터페이스
  • 데이터의 읽기 성능 과 쓰기 성능이 별도로 조정되어야 할 때
  • 시스템이 시간이 지남에 따라 계속해서 진화하고 여러 버전을 가져야 할 때
  • 다른 시스템 과의 통합

7. 권장하지 않는 경우

  • 도메인 과 비지니스 로직이 간단할 때
  • 단순한 CRUD 작업 인 경우
반응형
LIST