본문 바로가기
MSA

[MSA][ES] 이벤트 소싱 에 대한 초보자 가이드

by Real Iron 2023. 12. 22.

 

이벤트 소싱 에 대한 초보자 가이드

최신 이벤트 기반 아키텍처 내에서 이벤트 소스 시스템을 구축하려는 개발자 및 소프트웨어 설계자를 위한 제품입니다.

무료 이벤트 소싱 웹 세미나를 시청하세요

소개


이벤트 소싱(Event Sourcing)에 대해 들어보셨나요?

Java, Dotnet, PHP, Javascript, Python 등 스택이 무엇이든 누군가 이에 대해 이야기하는 것을 본 적이 있을 것입니다. 그럴 만한 이유가 있습니다. 이는 현대적인 분산 시스템을 구축하는 좋은 방법입니다.

하지만 그것은 새로운 것이 아닙니다! 이벤트 소싱은 수년간 세계 최대 기업(Netflix 및 Walmart 포함)의 제작에 사용되어 시스템을 신속하게 확장, 반복 및 발전시킬 수 있는 플랫폼을 제공하고 강력한 경쟁 우위를 제공하는 데이터 모델을 구축했습니다.

새로운 패턴에는 학습 곡선이 있습니다. 이벤트 소싱도 예외는 아니며 어리둥절한 전문 용어 세트( CQRS , 집계 , 프로젝션 …)를 제공합니다.

이 가이드에서는 첫 번째 원칙부터 Event Sourcing이 무엇인지 논의합니다. 패턴을 사용하는 이유 와 패턴이 제공하는 이점의 범위를 살펴보고 전문 용어를 분석합니다 .

이벤트 소싱은 소프트웨어 설계자의 툴킷에 포함된 강력한 도구입니다. 왜, 언제, 어떻게 사용하는지 이해하도록 도와드리겠습니다.

이벤트 소싱이란 무엇입니까?


이벤트 소싱은 데이터를 추가 전용 로그에 이벤트로 저장하는 패턴입니다. 이 단순한 정의는 이벤트를 저장함으로써 이벤트의 컨텍스트도 유지한다는 사실을 간과하고 있습니다. 동일한 정보를 통해 청구서가 전송된 이유와 이유를 알고 있습니다. 다른 스토리지 패턴에서는 비즈니스 운영 컨텍스트가 일반적으로 손실되거나 때로는 다른 곳에 저장됩니다.

이벤트 소싱의 맥락에서 이벤트는 귀하의 비즈니스 내에서 발생한 사실을 나타냅니다. 

모든 변경 사항은 이벤트로 표시되고 이벤트 로그에 추가됩니다. 모든 이벤트를 발생 순서대로 재생하여 엔터티의 현재 상태를 만들 수 있습니다. 시스템 정보는 이벤트에서 가져옵니다. 이벤트가 이미 발생했으므로 항상 과거 시제로 참조됩니다(InvoiceSent와 같은 과거분사 동사 사용). 

많은 사람들이 이벤트 소싱이 주로 감사를 위한 것이라고 가정 하지만 이는 패턴에 대한 제한된 보기입니다. 추가 전용 로그는 감사에 적합하지만 이벤트 소싱은 그 이상입니다. 감사 로그는 컨텍스트 없이 변경된 내용을 시간순으로 기록한 것입니다. 컨텍스트가 이벤트 내에 저장되므로 이벤트의 '이유'와 '언제'가 이벤트 데이터 내에 암시적으로 저장됩니다. 감사 로그를 준비하는 것 외에도 이벤트 소스 시스템에는 비즈니스에 매우 귀중한 정보와 컨텍스트가 저장되어 있습니다.

이벤트 소싱은 금융, 물류, 의료, 소매, 정부, 운송, 비디오 게임 개발 등을 비롯한 다양한 부문에 걸쳐 다양한 애플리케이션을 보유하고 있습니다.

 

더 자세히 알고 싶으십니까? 이벤트 소싱 소개 웹 세미나 보기

 

이벤트 소싱의 이점


이벤트 소싱을 사용하여 시스템을 구축하면 몇 가지 강력한 이점이 있으며, 아래에 상위 12가지 이점을 모아 놓았습니다.
  • 심사이벤트 소스 시스템은 시간이 지남에 따라 데이터를 일련의 불변 이벤트로 저장하여 사용 가능한 가장 강력한 감사 로그 옵션 중 하나를 제공합니다.
  • 시간 여행모든 상태 변경 사항이 유지되므로 시스템을 시간에 따라 앞뒤로 이동할 수 있으며 이는 디버깅 및 "가상" 분석에 매우 유용합니다.
  • 근본 원인 분석비즈니스 이벤트를 원래 이벤트에 다시 연결하여 처음부터 끝까지 전체 워크플로우에 대한 추적성과 가시성을 제공할 수 있습니다.
  • 결함 허용이벤트 스트림은 기본적으로 강력한 백업 및 복구 특성을 지닌 로그일 뿐입니다. 이벤트 스트림에 핵심 "기록 소스" 데이터만 기록하면 다운스트림 예측을 다시 작성할 수 있습니다. EventStoreDB는 리더가 실패할 경우 장애 조치가 가능한 분산 데이터베이스 기술입니다.
  • 이벤트 중심 아키텍처기존 접근 방식은 필요할 때만 호출할 수 있도록 개별 영역에서 데이터를 수집합니다. 이벤트 기반 접근 방식은 새로 게시된 정보에 즉각적으로 반응하므로 더욱 효율적일 수 있습니다. 이벤트 스트림은 새로운 이벤트에 대한 알림을 생성할 수 있으며, 스트림을 구독하면 기업은 이러한 변경 사항에 실시간으로 대응할 수 있습니다. 이를 통해 복잡한 비즈니스 워크플로우를 더 쉽게 모델링하고 구축할 수 있습니다.
  • 비동기식 우선이벤트 소스 시스템은 동기식 상호 작용을 최소화하기 위해 노력합니다. 일관성 경계는 비즈니스 요구 사항이 충족되고 다른 모든 것이 결국 일관성을 갖도록 의식적으로 선택됩니다. 그 결과 응답성이 뛰어나고 성능이 뛰어나며 확장 가능한 시스템이 탄생했습니다.
  • 서비스 자율성서비스가 중단되면 소스가 다시 작동할 때 종속 서비스가 "따라잡을" 수 있습니다. 이벤트는 스트림의 순서대로 저장되므로 각 서비스가 다시 온라인 상태가 되면 동기화가 이루어질 수 있습니다.
  • 재생 및 재구성스트림의 일련의 이벤트를 재생하고 변환하여 새로운 통찰력과 분석을 제공할 수 있습니다. 예를 들어 이벤트 스트림을 특정 시점까지 재생할 수 있고 "가상" 분석을 사용하여 잠재적인 미래 결과를 예측할 수 있습니다.
  • 관찰 가능성이벤트 소스 시스템에서는 이벤트가 대기열과 스트림을 통해 흐르므로 전례 없는 관찰 가능성이 가능합니다. 특히 강력한 점은 이벤트에 실시간 분석이 가능한 비즈니스 컨텍스트가 포함될 수 있다는 것입니다.
  • 가끔 연결됨애플리케이션의 모든 상태 변경에 대한 로그가 있으므로 가끔 연결되는 시스템 시나리오에서 사용할 수 있습니다. 장치의 연결이 끊어져도 로컬에서 자체 데이터에 대해 계속 작업할 수 있으며 연결 시 동기화할 수 있습니다.
  • 단방향 데이터 흐름CQRS/이벤트 소스 시스템의 데이터는 정보를 업데이트하거나 읽기 위해 독립 모델을 통해 단방향으로 흐릅니다. 이는 데이터 흐름의 각 구성 요소가 단일 책임을 갖기 때문에 데이터에 대해 추론하고 디버그하는 능력이 향상됩니다.
  • 레거시 마이그레이션레거시 시스템을 최신 분산 아키텍처로 마이그레이션하는 작업은 점진적으로 수행되어 특정 기능을 이벤트 소스 서비스로 점진적으로 대체할 수 있습니다. 쓰기가 서비스로 전달되는 동안 레거시 시스템의 기존 읽기 경로는 그대로 유지될 수 있습니다.

이벤트 소싱의 핵심 원칙


이벤트 소싱과 함께 사용되는 몇 가지 주요 소프트웨어 아키텍처 개념과 용어가 있으며 블로그와 문서에서 자주 언급합니다. 이러한 주제를 맥락에 맞게 기본적인 수준에서 설명하는 것이 중요하므로 이에 대해 아래에서 설명합니다.

이벤트

이벤트는 도메인에서 발생한 사실을 나타냅니다. 그것들은 진리의 원천입니다. 현재 상태는 이벤트에서 파생됩니다. 이는 불변이며 비즈니스 사실을 나타냅니다. 

이벤트는 과거형으로 언급되며 특정 비즈니스 사실을 나타냅니다. 예를 들어 'InvoiceIssued'는 송장의 상태가 단순히 생성된 것이 아니라 확실히 변경되었음을 나타냅니다. 비즈니스 도메인 언어를 사용하여 해당 사실을 명시적으로 설명한다는 점에서 'InvoiceCreated'보다 더 나은 이름이기도 합니다. 이벤트의 정확한 정의는 비즈니스 사용 사례에 따라 달라지며 비즈니스 데이터를 반영해야 합니다.

이벤트 소싱 측면에서 이벤트에는 일반적으로 이벤트의 타임스탬프, 주체의 고유 식별자 등과 같은 고유한 메타데이터가 포함됩니다. 이벤트 내의 데이터는 쓰기 모델에서 상태를 채우고 결정을 내리는 데 사용됩니다. 읽기 모델을 채울 수도 있습니다.

이벤트 이름 'InvoiceIssued'에 포함된 암시적 정보와 메타데이터 및 이벤트 저장소의 불변성 덕분에 이벤트 저장소는 비즈니스에 대한 보다 유용하고 심층적인 통찰력과 컨텍스트를 추출하기 위한 탁월한 솔루션이 됩니다.

상태 전환 데이터베이스(이벤트 저장소)

도메인에서 발생한 각 변경 사항은 데이터베이스에 기록됩니다. 상태 전환 데이터베이스는 기본적으로 이벤트 저장에 중점을 둡니다. 일반적으로 추가 전용 로그를 중앙 지점으로 사용하여 이를 수행합니다. 

상태 전이 데이터베이스는 기존 데이터베이스(그래프, 문서, 관계형 등)와는 다른 종류의 데이터베이스입니다. 이는 변경 내역을 저장하도록 특별히 설계되었으며 상태는 추가 전용 이벤트 로그로 표시됩니다. 이벤트는 시간순으로 저장되며, 이전 이벤트에 새로운 이벤트가 추가됩니다.

이벤트 는 변경할 수 없습니다 . 즉, 변경할 수 없습니다. 이 잘 알려진 이벤트 스토어 규칙은 대부분의 사람들이 특정 관점에서 듣고 절대적으로 사실인 이벤트 스토어 및 이벤트 소싱의 첫 번째 정의 기능입니다. 

로그의 이벤트는 변경할 수 없지만 그 효과는 이후 이벤트에 의해 변경될 수 있습니다. 예를 들어 어느 날 로그에 'InvoiceIssued' 이벤트가 추가되어 송장이 발행된 주소가 올바르지 않다는 알림이 표시될 수 있습니다. 'InvoiceVoided' 이벤트를 사용하여 새 이벤트를 추가한 다음 수정된 주소와 'InvoiceIssued' 이벤트가 있는 다른 이벤트를 추가할 수 있습니다. 세 가지 이벤트가 모두 저장되고 모두 여전히 변경 불가능하지만 원하는 결과가 달성됩니다. 송장이 올바른 주소로 발행되었습니다. 이벤트는 변경할 수 없지만 이것이 로그를 변경할 수 없다는 의미는 아닙니다. 

이는 비즈니스 컨텍스트가 유지되는 예입니다. 송장이 진행된 모든 단계는 모든 이벤트의 날짜 및 시간과 함께 보관되었습니다. 분명히 이 정보는 감사 목적으로 보관되어야 하지만 이 수준의 정보를 비즈니스의 모든 부분에 적용한다고 상상해 보십시오. 즉, 시스템의 모든 이벤트에 대해 감사 수준의 정보를 보유하는 것입니다. 이벤트 저장소는 정보를 잃지 않으며 올바른 구성을 통해 필요할 때마다 유용한 보고서와 데이터 분석을 가질 수 있습니다.

스트림

이벤트 저장소 내에서 특정 도메인이나 도메인 개체를 참조하는 이벤트는 스트림에 저장됩니다. 이벤트 스트림은 도메인 객체의 정보 소스이며 변경 사항의 전체 기록을 포함합니다. 모든 스트림 이벤트를 읽고 나타나는 순서대로 하나씩 적용하여 상태를 검색할 수 있습니다.

스트림에는 특정 개체를 나타내는 고유 식별자가 있어야 합니다. 각 이벤트는 스트림 내에서 고유한 위치를 갖습니다. 이 위치는 일반적으로 숫자 증분 값으로 표시됩니다. 이 번호는 상태를 검색하는 동안 이벤트의 순서를 정의하는 데 사용할 수 있습니다. 동시성 문제를 감지하는 데에도 사용할 수 있습니다. 

이벤트 저장소는 수많은 이벤트를 효율적으로 저장할 수 있도록 구축되었습니다. 많은 스트림을 생성하는 것을 두려워할 필요는 없지만 해당 스트림의 이벤트 수를 관찰해야 합니다. 스트림은 이벤트가 많아 수명이 짧을 수도 있고, 이벤트가 적어 수명이 길어질 수도 있습니다. 수명이 짧은 스트림은 유지 관리에 도움이 되며 버전 관리가 더 쉬워집니다.

예상

이벤트 소싱에서 프로젝션(뷰 모델 또는 쿼리 모델이라고도 함)은 기본 이벤트 기반 데이터 모델에 대한 보기를 제공합니다. 종종 이는 소스 쓰기 모델을 읽기 모델로 변환하는 논리를 나타냅니다. 읽기 모델과 쓰기 모델 모두에 사용됩니다.

읽기 모델의 예측

이 맥락에서 일반적인 시나리오는 쓰기 모델에서 생성된 이벤트(예: InvoiceIssued, OrderPlaced, PaymentSubmitted, OrderItemAdded, InvoicePaid, OrderConfirmed)를 가져와 읽기 모델 보기(예: 지불된 송장 번호, 미결제 송장 항목, 만기가 포함된 주문 요약)를 계산하는 것입니다. 날짜 상태 등). 이러한 유형의 개체는 다른 데이터베이스에 저장되어 쿼리에 사용될 수 있습니다. 

이벤트 세트는 또 다른 이벤트 세트를 생성하기 위한 시작점이 될 수도 있습니다. 예를 들어 주문 이벤트를 받아 가격 요약을 계산하고 새 주문 결제 이벤트를 생성하여 다른 스트림에 배치할 수 있습니다. 이러한 유형의 투영을 변환이라고도 합니다.

쓰기 모델의 예측

또 다른 형태의 투영을 스트림 집계라고 합니다. 스트림 이벤트에서 쓰기 모델의 현재 상태를 구축하는 프로세스입니다. Aggregation 중에는 이벤트가 나타나는 순서대로 하나씩 적용됩니다. 스트림 집계의 주요 목적은 현재 상태를 다시 작성하여 실행된 명령의 유효성을 검사하는 것입니다.

예측은 일시적이고 일회용으로 처리되어야 합니다. 이는 마음대로 파괴하고, 재구성하고, 재창조할 수 있다는 점에서 주요 이점 중 하나입니다. 그것들을 진리의 근원으로 여겨서는 안 됩니다.

프로젝션과 읽기 모델 사이에는 많은 개념적 교차가 있으며 이로 인해 약간의 혼란이 발생할 수 있습니다. 프로젝션과 읽기 모델 간의 관계를 이해하는 가장 간단한 방법은 읽기 모델이 여러 프로젝션으로 구성된다는 것입니다. 예측은 읽기 모델을 채우는 방법이며 전체 읽기 모델의 개별 부분을 나타냅니다. 예를 들어, 예측을 사용하여 송장을 생성하고 다른 예측을 재무 보고서로 사용할 수 있습니다. 둘 다 읽기 모델의 일부입니다. 

이벤트 소싱을 설명할 때 흔히 저지르는 오해는 예측을 상태와 혼동하는 것입니다. 이벤트 소싱에서 정보의 출처는 이벤트이며 애플리케이션의 상태는 이러한 이벤트에서 파생됩니다. 사실은 이벤트에 저장됩니다. 예측은 해당 원시 데이터의 해석입니다.

구독

이벤트 소싱의 가장 중요한 장점 중 하나는 관찰 가능성입니다. 시스템의 각 작업은 이벤트를 트리거하고 이벤트는 작업 결과에 대한 비즈니스 정보를 수집합니다. 이는 복잡한 비즈니스 워크플로우를 구축하고 작업을 더 작은 단위로 분할할 수 있다는 점에서 간단하지만 강력한 기능입니다. 

이벤트 중심 아키텍처에서는 서비스의 책임이 반전됩니다. 게시/구독 접근 방식으로 인해 서비스가 서로 분리됩니다. 예를 들어, 예약 서비스는 송장 서비스를 직접 호출할 필요가 없습니다. 예약 확인에 대한 이벤트를 게시하고, 송장 서비스는 예약 이벤트 스트림을 구독하며, 알림 직후 송장을 발행할 수 있습니다.

EventStoreDB를 포함한 이벤트 저장소는 구독 기능을 통해 이를 가능하게 합니다. 관계형 데이터베이스의 기존 '변경 데이터 캡처'와 유사한 개념입니다. 데이터베이스에 저장된 각 이벤트는 알림을 트리거할 수 있으며 구독자는 해당 알림을 듣고 다음과 같은 후속 작업을 수행할 수 있습니다.

  • 프로젝션을 실행하여 읽기 모델을 업데이트합니다.
  • 비즈니스 프로세스의 다음 단계를 수행합니다.
  • 이벤트를 대기열/스트리밍 시스템으로 전달하여 외부 서비스에 알립니다.

일반적으로 모든 이벤트(추가 전용 로그에서 직접) 또는 분할/필터링된 이벤트 데이터(예: 특정 스트림, 스트림 유형, 이벤트 유형 등의 이벤트)를 구독할 수 있습니다.

이벤트 저장소가 게시/구독 기능을 제공할 수 있더라도 일반적으로 전송이 아닌 저장에 최적화되어 있다는 점을 기억하는 것이 중요합니다. 더 높은 처리량이 필요하거나 서비스 간 통신이 필요한 경우 Kafka 또는 Kinesis와 같은 특수 스트리밍 솔루션을 추가로 사용하는 것을 고려해 볼 가치가 있습니다.

최종 일관성

최종 일관성은 분산 시스템에서 시스템의 모든 다른 부분이 결국 모두 동일한 값을 반환한다는 아이디어입니다. 이는 약한 일관성의 한 형태입니다. 시스템의 모든 부분이 동일한 값을 반환하는 것은 아니며 시스템의 모든 다른 부분이 일관성을 유지하려면 특정 조건을 충족하거나 조치를 취해야 합니다. 

시간 지연으로 인해 최종적으로 일관된 시스템이 부정확해질 것이라는 오해가 있습니다. 동일한 값을 반환하는 데 걸리는 시간은 시스템 내에서 정의되지 않을 수 있지만 시간 프레임은 큰 시간 범위가 아닌 밀리초에서 초 범위 내에 있습니다.     

어떤 종류의 데이터베이스나 구조를 사용하든 최종 일관성은 처리해야 할 문제입니다. 이는 이벤트 소싱에만 국한된 문제가 아닙니다. 입력이 수신되고, 저장 장치에 기록되고, 다시 호출되는 사이에는 항상 지연이 있습니다. 이벤트 소싱에 대한 첫 번째 오해 중 하나는 최종 일관성이 주요 문제가 될 것이라는 것입니다. 데이터를 저장하는 다른 패턴과 마찬가지로 이벤트 소싱의 경우 이는 더 이상 문제가 되지 않으며 이를 처리하는 방법은 사용 사례에 따라 다릅니다. 이벤트 저장소에 따라 구현 변경 사항이 최종적으로 일관될 필요는 없습니다. 대부분의 상점에서는 이벤트를 추가할 때 강력한 일관성을 허용합니다.

모델 작성

쓰기 모델은 비즈니스 로직 처리를 담당합니다. CQRS 를 사용하는 경우 이곳이 명령이 처리되는 곳입니다. 쓰기 모델에는 물리적 측면과 논리적 측면이라는 두 가지 측면이 있습니다. 물리적인 측면은 데이터가 어디에 어떻게 저장되는지와 관련된 것이고, 논리적인 측면은 코드 구조로 재현된 비즈니스 도메인을 반영하며 도메인 모델이라고도 할 수 있습니다. 기존 빈혈 모델과 달리 데이터뿐만 아니라 데이터를 변경하고 검증하는 방법도 포함합니다. 쓰기 모델 내의 논리는 비즈니스 프로세스와 최대한 유사해야 합니다. 코드를 읽고 코드의 비즈니스 요구 사항을 완전히 이해할 수 있어야 합니다. 

송장 발행을 위한 쓰기 모델을 예로 들어보겠습니다. 여기에는 금액, 공급업체 이름, 송장 번호 및 "송장 발행"과 같은 방법 등의 데이터가 있습니다. 여기에는 "각 송장 번호는 고유해야 합니다", "각 송장에는 공급업체 이름이 포함되어야 합니다" 등과 같은 규칙이 있습니다. 도메인에서 파생된 시스템 설계를 가짐으로써 모든 비즈니스 로직과 데이터를 한 곳에 보관할 수 있습니다. 쓰기 모델은 필수적이지만 읽기 모델이 항상 필요한 것은 아닙니다. 

쓰기 모델을 구현하는 동안 고려해야 할 유용한 패턴은 집계입니다. 이는 데이터 일관성을 유지하는 역할을 하며 이를 사용하여 모든 관련 데이터가 단일 원자 트랜잭션에 저장되도록 합니다. 집계는 필수는 아니지만 매우 일반적입니다. 

Domain Driven Design에서 Eric Evans는 개체의 세분화된 특성에 대해 논의하고 집계에 대한 정의를 제공합니다. Domain Driven Design “blue” 책에서:

집계  데이터 변경을 위해 하나의 단위로 취급되는 연관된 개체의 클러스터입니다.  집계에는 루트와 경계가 있습니다. 경계는 집계 내부에 무엇이 있는지 정의합니다 . 루트는 집계 에 포함된 단일 특정 엔터티 입니다 . 루트는 경계 내의 개체가 서로에 대한 참조를 보유할 수 있지만 외부 개체가 참조할 수 있는 유일한 집합체 멤버입니다. 루트가 아닌 엔터티에는 로컬 ID가 있지만 해당 ID는 집계 내 에서만 구별 가능해야 합니다. 외부 개체는 루트 엔터티 의 컨텍스트에서 이를 볼 수 없기 때문입니다 .

이는 송장 예시에 적용될 수 있습니다. 송장은 도메인 개체 이지만 지불할 금액, 공급업체 이름, 만기일 등 여러 개체 로 구성됩니다 . 각 개체는 송장의 일부이며 송장은 이 개체를 모두 하나로 결합합니다. 따라서 송장 예에서 송장은 집계 입니다 . 송장에 필요한 데이터(예: 발행자 정보)의 각 부분은 엔터티 입니다 . 루트  집계에서 단일의 특정 엔터티여야 하므로 이것이 고유한 송장 번호가 됩니다.

집계는 일관성을 보호하는 역할을 합니다. 현재 상태를 가져와서 특정 작업에 대한 비즈니스 규칙을 확인하고(예: 동일한 번호의 송장이 없는 경우) 새 상태를 반환하는 비즈니스 로직을 적용합니다. 이 프로세스의 중요한 부분은 모두 저장하거나 전혀 저장하지 않는 것입니다. 모든 집계된 데이터는 성공적으로 저장되어야 합니다. 하나의 규칙이나 작업이 실패하면 전체 상태 변경이 거부됩니다.

이벤트 소싱에서 집계에 대해 수행된 각 작업은 새 이벤트 로 이어져야 합니다 . 예를 들어 송장을 발행하면 InvoiceIssued 이벤트가 발생해야 합니다. 이벤트가 발생하면 이벤트 저장소에 기록됩니다.

집계가 있기 때문에 하나의 메가 집계를 가질 수 있다고 가정하기 쉽습니다. 그러나 이는 장기적으로 더 많은 문제를 야기할 것입니다. 한 가지 측면에 초점을 맞춘 더 작고 간결한 집계는 전체적으로 더 효율적인 시스템을 만들고 필요한 경우 비즈니스 컨텍스트를 보존합니다. 예를 들어 송장 집계를 생각해 보세요. VAT 검증 프로세스에는 송장에 포함된 모든 정보가 필요하지 않으므로 이 프로세스는 더 작고 간결하게 집계될 수 있습니다. 이렇게 하면 필요한 비즈니스 컨텍스트가 보존됩니다. 

모델 읽기

CQRS 의 쿼리는 데이터를 얻으려는 의도를 나타냅니다. 읽기 모델에는 특정 정보가 포함되어 있습니다. 예를 들어, 읽기 모델에는 모든 송장 정보(금액, 만기일 등)가 포함되어 있으며 쿼리는 송장 지불 여부 등 송장에 대한 정보를 알고자 하는 의도를 나타냅니다.

읽기 모델은 쓰기 모델에서 파생될 수 있지만 반드시 그럴 필요는 없습니다. 이는 비즈니스 운영 결과를 읽을 수 있는 형식으로 변환하는 것입니다.

투영 섹션 에 설명된 대로 읽기 모델은 투영에 의해 생성됩니다. 이벤트 저장소에 추가된 이벤트는 읽기 모델을 생성하거나 업데이트하는 프로젝션 로직을 트리거합니다.

읽기 모델은 쿼리에 특화되어 있습니다. 다양한 독자가 소화할 수 있는 간단한 출력으로 모델링되었습니다. 모니터 디스플레이, API, 다른 종속 서비스, 송장 PDF 생성 등 다양한 방법으로 표시될 수 있습니다. 간단히 말해서, 읽기 모델은 어떤 유형의 스토리지에도 얽매이지 않는 일반적인 개념입니다.

그러나 읽기 모델은 영구적일 필요는 없습니다. 기존 읽기 모델에 영향을 주지 않고 새로운 읽기 모델을 시스템에 도입할 수 있습니다. 읽기 모델은 쓰기 모델에 저장되므로 비즈니스 논리나 정보 손실 없이 삭제하고 다시 생성할 수 있습니다.

이벤트 소싱 아키텍처

이벤트 소싱은 추가 전용 로그에 데이터를 저장하는 아키텍처 디자인 패턴입니다. 이는 개발자가 자신의 요구에 가장 효과적인 아키텍처를 만들 수 있도록 다양한 방식으로 함께 작동하는 광범위한 디자인 패턴 생태계의 일부입니다. 

 

더 넓은 아키텍처 내에서 이벤트 저장소를 디자인 패턴으로 배포함으로써 도메인의 요구 사항에 가장 적합한 시스템에 다른 디자인 패턴을 포함할 수 있습니다. 예를 들어 이벤트 소스 시스템은 CQRS 아키텍처 내에서 잘 작동하지만 함께 사용할 필요는 없습니다. 이벤트 소싱은 이벤트 기반 아키텍처와 함께 배포하거나 CQRS , 집계 패턴, 명령 처리기 패턴 또는 기타 여러 패턴 중 하나와 함께 배포할 수 있습니다 . 각 개별 패턴은 그 자체로 유용한 도구이며, 다른 관련 패턴과 함께 작동하여 특정 사용 사례에 대해 더 강력하고 구체적인 패턴을 만들 수 있습니다.

이벤트 저장소는 시스템의 핵심 요소가 될 수 있으며 해당 시스템은 비즈니스 도메인에서 요구하는 만큼 간단할 수도 있고 복잡할 수도 있습니다. 이벤트 소싱이 가장 효과적인 곳이므로 모든 이벤트에 대한 컨텍스트 보존이 필요한 아키텍처의 일부에 이벤트 소스 시스템을 배치하는 것을 고려하는 것이 유용합니다. 

 

도메인 중심 설계

DDD(도메인 중심 설계)는 문제 공간에 대한 팀의 이해와 해당 공간에서 작업하는 방법을 최적화하는 방법입니다. 핵심은 비즈니스 사용자와 개발 팀이 사용하는 용어 사이에 유비쿼터스 언어를 갖는 것입니다. 이러한 언어 통일은 문제 개념을 작동하는 소프트웨어로 변환할 때 매우 유용할 수 있습니다.

도메인 기반 디자인은 Eric Evans가 그의 저서인 Domain-Driven Design: Tackling Complexity in the Heart of Software 에서 처음으로 만들어졌습니다 . Evans는 자신의 경험을 바탕으로 디자인 프로세스의 첫 번째 단계로 비즈니스 프로세스와 구현을 융합한 다음, 그 첫 단계를 기반으로 유비쿼터스 언어를 만들었습니다. 그는 프로젝트에서 효율적으로 협업하기 위해 공통 언어를 사용하는 것이 중요하다는 것을 깨달았습니다.

도메인 중심 설계는 설계자와 제품 소유자 간의 의미 있고 지속적인 협업이 필요하기 때문에 중요합니다. 이는 개발자를 순전히 기술적이고 이론적인 세계에서 벗어나 개발 기술에 현실감을 부여합니다. 또한 제품 소유자(또는 고객)가 시스템에서 요구하는 것이 무엇인지 깊이 생각하고 시스템의 기능을 인식하도록 강요합니다. 모든 이해관계자가 협력함으로써 공유된 이해가 형성되고 진행이 더욱 효율적이 됩니다.

유비쿼터스 언어의 생성에는 비즈니스 및 개발에서 관련 없는 용어를 가져와서 흩어져 있는 용어에서 무언가를 생성하는 프로세스인 Knowledge Crunching이 포함됩니다. 협력적이며 지저분할 수도 있지만 아름다운 우정의 시작이 될 수도 있습니다.

이벤트 소싱과 함께 도메인 기반 디자인을 사용하는 것은 필수는 아닙니다. 그러나 비즈니스와 동일한 언어를 사용하고 적절한 비즈니스 프로세스 모델링과 같은 주요 개념도 이벤트 소싱 시스템을 구축하기 위한 좋은 기반입니다. 처리된 비즈니스에 대해 더 잘 이해할수록 이벤트에 포함되는 비즈니스 정보가 더 정확해집니다.

CQRS

CQRS는 아키텍처 패턴인 CQS를 개발한 것으로 Command Query Separation의 약어입니다. CQS는 시스템에서 처리되는 두 가지 유형의 작업, 즉 작업을 실행하는 명령, 정보를 반환하는 쿼리를 정의하는 핵심 개념이며, 이 두 작업을 모두 수행하는 하나의 함수가 있어서는 안 됩니다. 이 용어는 Bertrand Meyer가 그의 저서 '객체 지향 소프트웨어 구성'(1988, Prentice Hall)에서 만들었습니다. 

CQRS는 Command Query Responsibility Segregation을 나타내는 또 다른 아키텍처 패턴 약어입니다. 시스템의 작업을 명령과 쿼리로 나눕니다. 둘은 비슷하지만 동일하지는 않습니다. Oskar Dudycz는 “CQRS는 CQS보다 더 높은 수준, 더 일반적으로 해석될 수 있습니다. 건축 수준에서. CQS는 행동의 일반적인 원칙을 정의합니다. CQRS는 구현에 대해 보다 구체적으로 설명합니다.”

CQRS는 Greg Young이 정의했으며 다음과 같이 설명했습니다.

이전에는 하나만 있던 개체를 두 개만 만드는 것입니다. 분리는 메소드가 명령인지 쿼리인지에 따라 발생합니다(Meyer가 명령 및 쿼리 분리에서 사용하는 것과 동일한 정의, 명령은 상태를 변경하는 모든 메소드이고 쿼리는 값을 반환하는 모든 메소드입니다). 

CQRS를 사용하면 쓰기 모델과 읽기 모델을 엄격하게 구분해야 합니다. 이 두 모델은 별도의 객체로 처리되어야 하며 개념적으로 서로 연결되어서는 안 됩니다. 이러한 개체는 물리적 저장 구조가 아니지만 예를 들어 명령 처리기 및 쿼리 처리기입니다. 데이터가 저장되는 위치와 방법과는 관련이 없습니다. 이는 처리 동작과 연결되어 있습니다. 명령 처리기는 명령 처리, 상태 변경 또는 기타 부작용 수행을 담당합니다. 쿼리 핸들러는 요청된 쿼리의 결과를 반환하는 역할을 담당합니다.

CQRS에 대한 일반적인 오해 중 하나는 명령과 쿼리가 별도의 데이터베이스에서 실행되어야 한다는 것입니다. 이것이 반드시 사실은 아닙니다. 단지 두 가지 모두에 대한 행동과 책임이 분리되어야 한다는 것입니다. 이는 코드 내, 데이터베이스 구조 내 또는 (상황에 따라 필요한 경우) 다른 데이터베이스 내일 수 있습니다.

이 개념을 확장하면 CQRS는 데이터베이스를 사용할 필요조차 없습니다. Excel 스프레드시트나 데이터가 포함된 다른 모든 것에서 실행할 수 있습니다. Oskar Dudycz는 그의 기사에서 이에 대해 다음과 같이 설명했습니다 .

그러면 관계형 데이터베이스를 사용하는 것을 막을 수 없습니다. 동일한 테이블을 읽고 쓰는 경우에도 마찬가지입니다. 원하는 경우 ORM을 계속 사용할 수 있습니다. 명령이 레코드를 추가/수정하고 동일한 테이블에서 데이터를 검색하는 것을 방해하는 것은 없습니다. 아키텍처에서 이들을 분리된 상태로 유지하는 한.

이벤트 소싱과 CQRS는 새롭고 흥미로운 디자인 패턴처럼 보이지만 꽤 오랫동안 사용되어 왔습니다. CQRS는 특히 CRUD 기반 기반으로 수년간 학습한 후에는 이상하고 새로운 기술처럼 느껴질 수 있습니다. CQRS는 Greg Young에 의해 ' 이벤트 소싱을 향한 디딤돌 ' 로 설명되었습니다 . 이벤트 소싱과 CQRS가 서로 의존하지 않는다는 것을 이해하는 것이 중요합니다. CQRS 없이 이벤트 소스 시스템을 가질 수 있고 이벤트 소싱 없이 CQRS를 사용할 수 있습니다. 두 사람이 함께 가장 잘 작동한다는 것입니다.