[디자인 패턴] CRUD의 문제점과 CQRS 패턴에 대해서 알아보자!

kyumerican0·2024년 11월 1일

디자인 패턴

목록 보기
1/1
post-thumbnail


우리에게 좌뇌와 우뇌가 있듯이, 컴퓨터에게도 좌뇌와 우뇌가 있다면 어떨까요? 데이터베이스에게 특정한 작업만을 처리하는 뇌가 있어, 작업을 더욱 효율적으로 처리할 수 있다면 어떨까요? 이런 생각을 다들 한번 즈음을 해보셨을거에요! 아니면 저만 그러던가요...

실제로 저러한 아이디어를 구현한 디자인 패턴이 있습니다! 여러분들에게 CQRS를 설명할 수 있게 되어서 영광입니다. :)

1. CRUD

CRQS로 들어가기 전, 간단하게 CRUD가 무엇인지에 대해서 이야기를 하고 갑시다! CRQS에 대한 설명으로 넘어가기 전, 데이터베이스에서 이러한 작업이 어떻게 이루어지며, 각각의 작업이 시스템에 어떠한 영향을 미치는지 이해하는 것이 중요하거든요. :)

CRUD의 정의

CRUD는 Create(생성), Read(조회), Update(갱신), Delete(삭제)의 약어로, 데이터베이스에서 데이터를 관리하기 위해 필요한 기본적인 작업을 의미합니다.

아! 이런 간단한건 이미 알고 있다구요! 그러면, 하단의 배경지식만 간단하게 체크체크 하고 넘어가도록 할게요! :)

간단한 배경지식들

1.읽기(Read) 작업의 특성

  • 읽기 작업은 상대적으로 가벼운 작업으로, 데이터베이스 내에서 데이터를 검색하고 조회하는 작업을 의미합니다.
  • 데이터베이스는 읽기 작업을 효율적으로 처리하기 위해 여러 가지 최적화 기법을 활용합니다. 예를 들어, 캐싱과 인덱싱을 통해 자주 요청되는 데이터를 빠르게 반환하거나, 복잡한 검색 쿼리에 대해 필요한 데이터를 보다 효율적으로 접근할 수 있도록 설계하는 등의 방법으로 말이죠!
  1. 쓰기(Create, Update, Delete) 작업의 특성
  • 쓰기 작업은 데이터베이스에 저장되어있는 데이터에 대한 직접적인 변화를 일으키며, 읽기 작업에 비해 상대적으로 무거운 작업입니다.
  • 쓰기 작업이 발생하면 기본적으로 데이터의 무결성 유지와 관련된 추가 작업이 필요하며, 저장 장치에 데이터를 기록하거나 수정하므로 I/O 작업이 발생하게 됩니다. 이로 인해 대량으로 쓰기 작업이 일어난다면 데이터베이스에 부하가 걸릴 수 있으며, 이는 성능 저하로 이어질 수 있습니다!

이 배경 지식을 머릿 속에 저장하고, CQRS에 대한 설명으로 넘어가볼까요!

2. CQRS (Command Query Responsibility Segregation)

기존 CRUD의 문제점

MSA가 도래한 이후, 기존의 CRUD 모델을 차용한 시스템 설계는 다음과 같은 문제점을 맞이했습니다!

같은 데이터가 작업에 따라서 다른 데이터 모델을 요구하게 되었습니다!

  1. 세분화된 서비스 로직에 따른 데이터 모델의 복잡화
  • 각 서비스 로직이 독립적이고 세분화됨에 따라, 읽기 작업과 쓰기 작업을 위한 데이터 모델 요구 사항이 크게 달라지고 있습니다.
  • 예를 들어서, 학생의 정보를 생성하는 CreateStudentDto는 아이디, 비밀번호, 학번, 이름...등등이 많이 필요하지만, 학생 로그인을 위한 LoginStudentDto는 아이디, 비밀번호만 필요하죠. 필요에 따라서 위 DTO들은 다른 응답값을 반환해야 할 수도 있습니다.
  • 상황에 따라 각 DTO는 다른 응답값을 반환해야 할 수도 있으며, 이러한 데이터 모델의 복잡화는 유효성 검사 및 객체 매핑 과정에서 많은 작업을 요구하게 됩니다. 그 결과, 데이터 모델은 점차 기존 CRUD 모델과의 연결성이 약해지며, 비대하고 복잡한 기능을 수행하는 구조로 변질되게 되죠.
  1. 읽기/쓰기 컨텍스트에 따른 보안 및 권한 관리의 복잡성
  • MSA 환경에서 각 엔터티는 읽기와 쓰기 작업을 수행할 때, 상황에 맞는 데이터 접근 및 노출 수준을 고려해야 합니다.
  • 위와 비슷한 예시를 들어보죠!
    i. 학생의 기본 프로필 정보는 관리자와 교수에게는 모든 항목이 공개될 수 있지만, 학생 자신 또는 학과 사무직원에게는 일부 민감 정보(예: 학번, 개인정보 등)를 비공개로 설정해야 할 수 있습니다.
    ii. 반면, 쓰기 작업에서는 학생이 직접 자신의 일부 정보를 갱신할 수 있는 권한을 가질 수 있습니다.
  • 이러한 분리된 상황에 대한 데이터 모델을 제대로 설계하지 못할 경우, 특정 엔터티가 잘못된 작업에 노출되어 불필요한 보안 위험이 발생할 수 있으며, 데이터 유출의 가능성이 높아집니다.

이러한 문제점을 해결하기 위해 개발자들이 머리를 맞대며 고민을 하던 중, 드디어 CQRS 패턴이라는 업그레이드 된 패턴을 제안하게 됩니다!

CQRS의 정의


기존의 CRUD는 데이터를 직접 작업하는 것에 초점이 맞추어져 있었습니다. 이에 반해 CQRS는 명령(Command)쿼리(Query) 의 역할을 분리하여 각 작업이 고유의 데이터 모델 목적(intention)과 흐름을 따르도록 설계하는 아키텍처 패턴입니다. CQRS는 기본적으로 다음과 같은 두 가지 모델로 나누어집니다.

  1. 명령 (Command)
  • 명령 모델은 템에서 사용자의 데이터를 수정하거나 생성하는 명령관리합니다. 이는 쓰기(Write) 작업으로, 데이터의 생성, 수정, 삭제와 같은 상태 변화를 수행하는 요청을 의미합니다.
  1. 쿼리 (Query)
  • 쿼리 모델은 시스템에서 데이터를 검색하고 조회하는 작업을 담당합니다. 이는 읽기(Read) 작업으로, 사용자가 필요한 정보를 조회하는 역할을 합니다.

예시

다음 예시를 보며 한번 CQRS를 이해해볼까요!


1. 명령 (Command)

  • 학생의 데이터를 생성하는 "학생 등록" 작업은 학생의 아이디, 비밀번호, 학번, 이름 등의 정보를 바탕으로CreateStudentCommand를 호출하여 처리됩니다. 이 호출은 데이터에 직접 접근하거나 변경하지 않고, 학생 생성과 관련된 쓰기(Write) 이벤트를 발생시키는 역할을 합니다.
  • 생성된 이벤트는 데이터베이스의 쓰기 모델(Write Model)을 통해 학생 정보가 등록되도록 처리됩니다.
  1. 쿼리 (Query)
  • 학생의 데이터를 호출하는 "학생 로그인" 작업은, 학생의 아이디와 비밀번호를 바탕으로LoginStudentQuery를 통해 처리됩니다. 이 쿼리는 학생의 아이디와 비밀번호를 조회하여 인증 절차를 수행하는 읽기(Read) 이벤트를 발생시킵니다.
  • 생성된 데이터베이스의 읽기 모델(Read Model)을 통해 필요한 학생 정보를 가져오며, 이 과정에서 데이터베이스에 직접적인 쓰기 작업이나 변경을 수행하지 않습니다.
  1. 참고할 점
  • 각 발생된 이벤트는 Command Handler Queue에 저장하여 비동기로 처리가 될 수 있도록 설계할 수 있습니다.
  • 조금 더 고도화된 CQRS의 경우, 읽기와 쓰기의 데이터 모델이 다르다는 점에서 읽기 데이터베이스와 쓰기 데이터베이스를 나누기도 합니다. 다음과 같은 방법으로 말이죠!
  • 쓰기 데이터베이스(Write Database)는 트랜잭션 관리와 데이터 무결성이 중요한 쓰기 작업에 최적화된 관계형 데이터베이스(RDBMS)나, 버킷(Bucket) 방식의 저장소를 사용하기도 합니다. 이를 통해 데이터 일관성과 신뢰성을 보장하면서도 쓰기 작업의 성능을 최대화할 수 있죠!
  • 읽기 데이터베이스(Read Database)는 대량의 읽기 작업에 최적화된 데이터베이스를 사용하며, 주로 NoSQL 데이터베이스캐시 시스템을 활용하여 높은 조회 성능을 제공합니다. 이러한 데이터베이스는 읽기 작업의 효율성을 높이며, MSA 환경에서 대규모 요청을 신속하게 처리할 수 있게 되죠.
  • 쓰기 데이터베이스에서 일어난 데이터 변경 사항은 이벤트 버스를 통해 이벤트로 발행되며, 해당 이벤트가 읽기 데이터베이스에 반영되도록 비동기적으로 업데이트됩니다. 이 과정에서 이벤트 버스는 쓰기와 읽기 데이터베이스 간의 데이터 일관성을 유지하는 데 중요한 역할을 하며, 비동기적 업데이트 방식은 읽기 작업의 성능을 저하시키지 않으면서 데이터가 최신 상태로 유지되도록 합니다!
  • 이와 같은 동기화를 통해 쓰기 데이터베이스와 읽기 데이터베이스가 같은 결과를 갖는, 궁극적 일관성(Eventual Consistency)를 갖게 됩니다.

3. 글을 마치며..

이러한 CQRS를 궁극적으로 발전을 시킨 것이 바로 이벤트 소싱 (Event Sourcing) 패턴이다. 해당 이벤트 소싱 패턴에 대해서는 다음 글에서 다루도록 하겠다. :)

잘못된 정보가 있다면 언제든지 알려주세요!

References

ByteMonk - Mastering CQRS in Just 5 Minutes
CQRS 패턴 - Azure Architecture Center
CQRS 패턴 - AWS 규범적 지침

profile
운동과 음악을 사랑하는 ENFJ 개발자입니다! :)

0개의 댓글