DDD / CQRS / ES 접근 방식을 사용하고 있으며 집계 및 쿼리 모델링에 대해 몇 가지 질문이 있습니다. 예를 들어 다음 시나리오를 고려하십시오.
사용자는 WorkItem을 만들고 제목을 변경하고 다른 사용자를 여기에 연결할 수 있습니다. WorkItem에는 참가자 (관련 사용자)가 있으며 참가자는 WorkItem에 작업을 추가 할 수 있습니다. 참가자는 작업을 실행할 수 있습니다.
사용자가 이미 생성되어 있고 사용자 ID 만 필요하다고 가정하겠습니다.
다음 WorkItem 명령이 있습니다.
이러한 명령은 멱 등성이 있어야하므로 동일한 사용자 또는 작업을 두 번 추가 할 수 없습니다.
그리고 다음 쿼리 :
쿼리는 WorkItem 집계에 의해 발생한 도메인 이벤트를 처리하는 처리기에 의해 업데이트됩니다 (EventStore에 유지 된 후). 이러한 모든 이벤트에는 WorkItemId가 포함됩니다. 필요한 경우 모든 관련 이벤트를로드하고 순서대로 처리하여 쿼리를 즉석에서 다시 작성할 수 있기를 바랍니다. 이는 내 사용자가 일반적으로 1 년 전에 생성 된 WorkItems에 액세스하지 않으므로 이러한 쿼리를 처리 할 필요가 없기 때문입니다. 따라서 존재하지 않는 쿼리를 가져올 때 다시 빌드하고 TTL을 사용하여 키 / 값 저장소에 저장할 수 있습니다.
도메인 이벤트에는 aggregateId (이벤트 streamId 및 샤드 키로 사용됨) 및 sequenceId (이벤트 스트림 내에서 eventId로 사용됨)가 있습니다.
그래서 첫 번째 시도는 참가자 모음과 작업 모음이있는 WorkItem이라는 대규모 집계를 만드는 것이 었습니다. 참가자 및 작업은 WorkItem 내에서만 존재하는 엔터티입니다. 참가자는 userId를 참조하고 작업은 participantId를 참조합니다. 더 많은 정보를 얻을 수 있지만이 연습과는 관련이 없습니다. 이 솔루션을 사용하면 중복 된 참가자 또는 작업을 추가하지 않는지 확인할 수 있으므로 대규모 WorkItem 집계를 통해 명령이 멱 등성을 보장 할 수 있습니다. WorkItemDetails 쿼리를 다시 작성하려면 지정된 이벤트에 대한 모든 이벤트를로드 / 처리하기 만하면됩니다. WorkItemId.
집계가 하나뿐이므로 WorkItemId가 aggregateId가 될 수 있으므로 쿼리를 다시 작성할 때 주어진 WorkItemId에 대한 모든 이벤트를로드하기 만하면됩니다. 그러나이 솔루션에는 대규모 Aggregate의 성능 문제가 있습니다 (왜 ChangeTitle 명령을 처리하기 위해 모든 참가자와 작업을로드합니까?).
그래서 다음 시도는 속성과 동일한 WorkItemId를 가진 서로 다른 집계를 갖는 것입니다. 그러나 WorkItem 집계 만 집계 ID로 가지고 있습니다. 이렇게하면 성능 문제가 해결됩니다. 모든 이벤트에 WorkItemId가 포함되어 있기 때문에 쿼리를 업데이트 할 수 있지만 이제 문제는 다른 집계에 대한 aggregateId를 모르기 때문에 처음부터 다시 작성할 수 없어서로드 할 수 없다는 것입니다. 이벤트 스트림 및 처리. WorkItemId 속성이 있지만 실제 집계 ID는 아닙니다. 또한 각 집계에 자체 이벤트 스트림이 있기 때문에 이벤트를 순차적으로 처리한다고 보장 할 수 없지만 이것이 실제 문제인지 확실하지 않습니다.
내가 생각할 수있는 또 다른 솔루션은 전용 이벤트 스트림을 사용하여 여러 집계에 의해 발생한 모든 WorkItem 이벤트를 통합하는 것입니다. 따라서 Participant 및 Actions에 의해 발생한 이벤트를 ID가 "{workItemId} : allevents"와 같은 이벤트 스트림에 추가하는 이벤트 처리기를 가질 수 있습니다. 이것은 WorkItemDetails 쿼리를 다시 작성하는 데만 사용됩니다. 이것은 해킹처럼 들립니다. 기본적으로 저는 사업 운영이없는 "집계"를 만들고 있습니다.
다른 어떤 솔루션이 있습니까? 즉시 쿼리를 다시 작성하는 것은 드문 일입니까? 여러 집계 (여러 이벤트 스트림)에 대한 이벤트를 사용하여 동일한 쿼리를 작성하는 경우 수행 할 수 있습니까? 이 시나리오를 검색했지만 유용한 것을 찾지 못했습니다. 나는 매우 분명해야 할 무언가를 놓치고 있다고 생각하지만 무엇을 알지 못했습니다.
이에 대한 도움을 주시면 대단히 감사하겠습니다.
감사
쿼리 문제를 염두에두고 집계를 디자인해야한다고 생각하지 않습니다. 읽기 쪽이 여기에 있습니다.
도메인 측면에서는 일관성 문제 (집계가 얼마나 작을 수 있고 도메인이 단일 트랜잭션에서 여전히 일관성을 유지할 수 있는지), 동시성 (동시 액세스 문제 / 경쟁 조건을 겪을 수 있는지 여부) 및 성능에 초점을 맞 춥니 다. 간단한 명령을 수행하기 위해 메모리에 수천 개의 객체를로드합니다.
주문형 읽기 모델에 문제가있는 것은 아닙니다. 필요할 때 스트림을 다시 만드는 것을 제외하고는 기본적으로 실시간 스트림에서 읽는 것과 동일합니다. 그러나 대부분의 경우 엔터티가 수정 된 직후에 쿼리되기 때문에 이것은 특별한 이득은 아니지만 상당히 많은 작업이 될 수 있습니다. 온 디맨드가 "기본적으로 엔터티가 변경 될 때마다"가되는 경우 라이브 변경을 구독하는 것이 좋습니다. "이전"뷰의 경우 "오래된"뷰의 정의는 더 이상 수정되지 않으므로 주문형 또는 지속적인 시스템이 있는지 여부에 관계없이 어쨌든 다시 계산할 필요가 없다는 것입니다.
여러 개의 작은 집계 경로로 이동하고 읽기 모델에 자체 업데이트를 위해 여러 소스의 정보가 필요한 경우 몇 가지 옵션이 있습니다.
추가 데이터로 생성 된 이벤트 강화
여러 이벤트 스트림에서 읽고 데이터를 통합하여 읽기 모델을 만듭니다. 여기에는 마술이 없습니다. 읽기 측은 특정 프로젝션에 어떤 집계가 관련되어 있는지 알아야합니다. 다른 읽기 모델이 최신 상태이고 필요한 데이터 만 제공한다는 것을 알고 있다면 다른 읽기 모델을 쿼리 할 수도 있습니다.
이 기사는 인터넷에서 수집됩니다. 재 인쇄 할 때 출처를 알려주십시오.
침해가 발생한 경우 연락 주시기 바랍니다[email protected] 삭제
몇 마디 만하겠습니다