2017-11-15 28 views
4

AWS 람다에서 실행되는 마이크로 서비스 기반 응용 프로그램이 있습니다. 가장 중요한 두 가지 마이크로 서비스는 이벤트 소싱/cqrs를 사용합니다.이벤트 소싱/CQRS 모델 읽기 -

배경 : (내 생각을 정리하는이 또한)

나는 this library를 사용하여 AWS S3에서 DynamoDB의 이벤트 및 전망을 저장하고있다.

쓰기 부분은 매력처럼 작동합니다. 각 명령 호출은 (핸들러를 통해 이벤트를 실행하거나 캐싱 된 집계를로드하여) DynamoDB에서 집계의 현재 상태를로드하고 다음 명령에 따라 명령을 수락하거나 거부합니다. 그런 다음 비즈니스 로직을 적용한 다음 KeyConditionExpression: 'aggregateId = :a AND version >= :v'으로 DynamoDB에 기록합니다. 여기서 버전은 해당 집계에 대해 처리 된 이벤트의 수입니다. 충돌이 있으면 쓰기가 실패합니다. 나에게 좋은 시스템 같아!

각 이벤트는 SNS (주제 이름은 서비스 이름)로 브로드 캐스팅되므로 원하는 경우 다른 서비스가 이벤트에 반응 할 수 있습니다.

내가 정말로 고민하는 부분은 읽음입니다. 프로젝션은 S3에 저장되고 각 이벤트 소스에 대해 처리 된 마지막 commitId로 태그가 지정됩니다. 읽기 쿼리가 들어 오면 S3 (전체 집계의 경우)의 전체 투영 된 상태를로드하고 모든 최신 이벤트를 이벤트 소스에 쿼리하고 모든 집계에 대해 최신 상태를 계산하고 업데이트 된 개체를 S3에 씁니다 새로운 경우) 쿼리 매개 변수를 기반으로하여 상태의 관련 부분을 반환합니다.

내 문제 (또는 그들 중 하나)

나는 내가 잘못 예측을하고 있어요 생각합니다.

대부분의 내 계획에는 중요한 특성에 따라 ID 만 그룹화되므로 파일은 상대적으로 작게 유지됩니다. 그러나 개별 집계를 검색 할 방법이 필요합니다. 투영을 사용하면 미묘한 것처럼 보입니다. 매번 전체 상태 (예 : 모든 예상 집계)를로드해야하므로 새 이벤트가 적용되고 원하는 레코드를 검색합니다 (변경되지 않았을 수도 있음).

이것은 내가 지금하고있는 것으로, 성능이 뛰어나다. (< 100k 레코드)하지만 훨씬 더 오래 지속될 것이라고 상상할 수 없다.

다른 문제는 쿼리입니다. 내가 쿼리 할 필요가있는 모든 속성에 대해 aggregateIds를 일치시키기 위해 프로젝션 매핑 값을 만들어야합니다 !! 더 좋은 방법이 있어야합니다!

이 문제에 대해 어떤 생각을하든 프로젝션은 변경되지 않은 단일 레코드를 반환하기 전에 항상 전체 현재 상태 + 새 이벤트가 필요합니다.

답변

6

나는 잘못된 예측을하고 있다고 생각합니다.

나는 그렇게 생각한다.

읽기 쿼리가 들어 오면 S3에서 전체 집계에 대해 투영 된 전체 상태를로드하고 모든 최신 이벤트를 이벤트 소스에 쿼리하고 최신 쿼리를 계산합니다 상태

그래, 엉망진창 같아.또는 구체적으로 말하자면, 질의가 투영에 의해 수행 될 작업을 트리거하는 것처럼 들립니다.

투영법에서 쿼리를 분리 할 수 ​​있다면 쉽게 얻을 수 있습니다. 귀하의 질문에 현재 상태를 설명하지 않는다는 기본 아이디어는 프로젝션이으로 마지막으로 실행 된 시점에서 상태 을 설명합니다.

같은 생각, 다른 철자 : S3에서 캐시 한 문서의 쿼리에 응답합니다. 새로운 이벤트가 감지되면 프로젝션이 실행되고, 필요에 따라 새 데이터를로드하고, 새 문서를 계산하고 캐시의 항목을 교체합니다.

나는 삼각형의 생각

  • 명령
  • 계획은
  • 쿼리가 캐시에서 정보를 가져 캐시에 기록의 책에서 정보를 가져올 레코드의 책 외부에서 정보를 가져 외부 세계

삼각형의 각 다리는 다른 것들과 비동기 적으로 실행됩니다.

각 쿼리를 뒷받침하는 데 필요한 문서는 무엇입니까? 대기 시간 목표는 무엇입니까? 그런 다음 균형을 유지하기 시작합니다.이 새로운 쿼리의 경우 기존 문서에서 결과를 만들거나 더 미세한 입자로 새 문서를 만들어야합니까?

제대로 이해하면 쿼리가 생성 될 때 집계 대신 이벤트가 입력 될 때 프로젝션 업데이트를 트리거해야합니다. 이렇게하면 모든 쿼리의 새 이벤트에 대해 이벤트 저장소에 쿼리하지 않습니다.

예 및 이벤트는 트리거하는 한 가지 방법 일뿐입니다. 당신은 시계에 의해 촉발 된 프로젝션 프로세스를 가질 수도 있습니다 (업데이트가 필요한지를보기 위해 15 분마다 확인하십시오) 또는 휴먼 오퍼레이터의 호기심으로 볼 수 있습니다 (흠, 귀하의 계정 잔액이 부실한 것처럼 보입니다. 당신을 위해). 두 가지 이상의 방법으로 전략을 혼합하고 일치시킬 수 있습니다.

프로젝션을 업데이트 할 때와 단일 집계를로드 할 때 모두 전체 상태를로드해야합니다.

반드시 그렇지는 않습니다. 이전에 캐싱 된 표현을 시작점으로 사용할 수 없다는 규칙은 없으며 필요한 변경 사항 만 기록부에서 가져올 수 있습니다.

예를 들어 집계 A{id:7}B{id:9}을 결합하는보기를 작성한다고 가정합니다. 캐시 된 복사본을 가져 와서 메타 데이터 (이전 쓰기에 넣은 위치)를보고 metadata:{A:{id:7, version:21}, B:{id:9, version:19}}과 같은 내용을 찾습니다. 이제는 마지막으로 사용한 이벤트 다음에 이벤트를로드하고, 메모리에서 로컬 복사본을 업데이트하고, 메타 데이터의 로컬 복사본을 업데이트하고, 캐시로 로트를 밀어 넣기 만하면됩니다.

+0

답장을 보내 주셔서 감사합니다. 따라서 올바르게 이해한다면 쿼리가 생성 될 때 집계가 아닌 이벤트가 들어올 때 프로젝션 업데이트를 트리거해야합니다. 이렇게하면 모든 쿼리에서 이벤트 저장소에 대한 새 이벤트를 쿼리하지 않아도되지만 프로젝션을 업데이트 할 때와 단일 집계를로드 할 때 전체 상태를로드해야합니다. 권리? 또는 나는 무엇인가 놓쳤다. – joshblour

4

나는 당신의 기술 인프라에 익숙하지 않아요하지만 다음과 같이 내가 예측을 구현하는 방법은 다음과 같습니다

각 도메인 이벤트가 모두 집계 뿌리를 걸쳐 글로벌 일련 번호가 있습니다.투영은 임의의 이름을 가진 읽기 모델이며 전역 순서 번호로 표시되는 마지막으로 처리 된 위치입니다. 이벤트 처리기와 함께 언제든지 새 프로젝션을 추가 할 수 있으며 위치 0에서 시작됩니다. 언제든지 투영을 취소하고 위치를 0으로 설정할 수 있습니다. 새 기존 프로젝션을 대체 할 프로젝션, 며칠이 지난 후에도 빌드 한 다음 이전 인스턴스를 제거하십시오.

프로젝션을 모니터하고 거의 큐와 같은 이벤트 저장소를 사용하는 서비스가 있습니다. 프로젝션 서비스는 현재 위치 인 이후에 전역 ID가 인 이벤트를 확인한 다음이를 처리기로 전달한 다음 위치를 업데이트합니다. 이것은 투영이 이벤트 유형을 필터링하여 성능을 향상시킬 수있는 곳입니다.

기본 아이디어입니다. 귀하의 투영은 귀하가 조회하는 것입니다. 투영법이 이벤트 저장소의 "머리"에 닿았 으면 이벤트 저장소의 이벤트가 프로젝션에 조금씩 흐르게됩니다.

기술적 공간으로 어떻게 변환 할 것인지는 잘 모르겠습니다.이라는 실험을 약간하고 있는데 C#을 사용하면 아이디어를 얻고 싶습니다.