当前位置: 首页 > 知识库问答 >
问题:

事件源/CQRS读取模型-预测

夏侯野
2023-03-14

我有一个在AWS Lambda上运行的基于微服务的应用程序。其中两个微服务,最关键的,使用事件源/cqrs。

背景:(这也是我整理思想的地方)

我正在使用这个库并将事件存储在DynamoDB中,并将预测存储在AWS S3中。

写入部分的工作方式很有魅力:每个命令调用都从DynamoDB加载聚合的当前状态(通过处理程序运行事件和/或加载缓存的聚合),它根据一些业务逻辑决定接受或拒绝命令,然后使用键条件表达式(“aggregateId=:a和version”)写入DynamoDB

然后将每个事件广播到SNS(主题名称是服务名称),以便其他服务可以根据需要对事件做出反应。

我真正纠结的部分是读取。投影存储在S3中,并用为每个事件源处理的最后一次提交标记。当读取查询进来时,它会从S3加载整个投影状态(对于所有聚合),查询所有较新事件的事件源,计算最新状态(同样,对于所有聚合——如果更新,则将更新的对象写入S3),并根据查询参数返回状态的相关部分。

我的问题:(或其中之一)

我认为我做的预测是错的。

我的大多数投影只按重要属性对ID进行分组,因此文件相对较小。但我还需要一种检索单个聚合的方法。使用投影似乎很疯狂,因为每次(即每个投影聚合)向其应用新事件时,我都需要加载整个状态,然后检索我想要的记录(它可能甚至没有更改)。

这就是我现在正在做的,它的表现很好(

另一个问题是查询。我需要为我需要查询的每个属性构建一个投影映射值,以匹配AggregateID!!一定有更好的办法!

无论我如何看待这个问题,投影总是需要整个当前状态任何新事件才能返回甚至是一条没有改变的记录。

共有2个答案

贾俊喆
2023-03-14

我不熟悉你们的技术基础设施,但我实施预测的方式如下:

每个域事件都有一个全局序列号,该序列号跨越所有聚合根。投影是一种读取模型,具有任意名称和由该全局序列号表示的最后处理位置。我可以随时添加一个新的投影及其事件处理程序,它将从位置0开始。我可以随时清除投影并将位置设置回0。我还可以结合使用添加一个新的投影来替换现有的投影,即使需要几天的时间也要进行构建,然后删除旧的投影。

有一个服务可以监视投影,并像队列一样使用事件存储。投影服务检查当前位置后是否有全局ID的事件,并将其交给处理程序,然后更新位置。这是您的投影甚至可以过滤事件类型以提高性能的地方。

这是基本思想。你的预测就是你所质疑的。一旦投影到达事件存储的“头部”,事件存储中的事件将被滴入投影。

我不太确定这将如何转化为您的技术空间。我有一个叫穿梭机的实验。如果你想看一看得到一些想法,记得上C。

南门向荣
2023-03-14

我认为我做的预测是错的。

我也这么认为;听起来你把你的疑问和你的预测联系在一起

当读取查询进来时,它从S3加载整个投影状态(对于所有聚合),查询所有较新事件的事件源,计算最新状态

是的,听起来像一团糟。或者更具体地说,这听起来像是查询触发了投影要完成的工作。

如果可以将查询与投影解耦,那么事情就会变得更容易。基本思想是,您的查询不描述当前状态,而是描述截至上次运行投影时的状态。

相同的想法,不同的拼写:您回答来自您在S3中缓存的文档的查询。当检测到新事件时,您的投影运行,根据需要加载新数据,计算新文档,并替换缓存中的条目。

我想到一个三角形

  • 命令将外部信息带入记录簿
  • 投影将记录簿中的信息带入缓存
  • 查询将信息从缓存带到外部世界

其中三角形的每条腿与其他腿异步运行。

我建议您从查询开始反向工作-您需要哪些文档来支持每个查询?您必须达到的延迟目标是什么?然后开始权衡权衡——对于这个新查询,我是从现有文档创建结果,还是需要用更精细的粒度构建新文档?

如果我理解正确,我应该在事件发生时触发投影更新,而不是在查询时进行聚合。这使我不用在每次查询时查询事件存储中的新事件

是的,而且...事件只是触发的一种方式;你也可以让时钟触发投影过程(每15分钟检查一次,看看我们是否需要更新),或者由人工操作员一时兴起(嗯,看起来你的账户余额已经过期了,让我试着为你更新一下)。不止一种方法可以做到这一点,你可以混合和匹配策略。

在更新投影和加载单个聚合时,我仍然需要加载整个状态。

不一定。没有规则说你不能使用以前缓存的表示作为起点,然后只从记录簿中提取你需要的更改。

例如,假设您正在构建一个视图,该视图将聚合a{id:7}和B{id:9}组合在一起。您抓取缓存的副本,并查看其元数据(您将其放在上一次写入时的位置),然后在其中找到类似元数据:{A:{id:7,版本:21},B:{id:9,版本:19}}。现在,您只需要加载上次使用的事件之后的事件,更新内存中的本地副本,更新元数据的本地副本,并将该批推送到缓存中。

 类似资料:
  • 在CQRS ES和DDD中,聚合中的小读模型从其他聚合或有界上下文中获取数据是件好事吗? 例如,在订单验证(订单聚合)中,有一个业务规则,该规则仅在未标记客户时验证订单。标志信息通过同步域事件放入读取模型(特定于聚合)。 你怎么看?

  • 现在,每当在我的数据库中的表上发生插入/更新/删除时,我需要向其他系统发送消息,这些系统需要了解我的系统中的更改,因为我的数据库是主数据,所以这里发生的任何更改都需要投射到下游系统,以便它们获得最新的数据并在其系统中维护这些数据。为此,我可以使用MQ或Kafka,所以每当有变化时,我可以生成关键消息并将其放入MQ或使用Kafka进行消息传递。 到目前为止,我还没有像我想的那样使用事件源,因为我没有

  • 我在CQRS/ES设计中有一个计时案例。为了便于讨论,让我们以Microsoft关于这个主题的示例会议管理为基础(https://msdn.microsoft.com/en-us/library/jj554200.aspx)。 假设在第1分钟创建会议(最大座位数为20)。 在第4分钟,事件到达order mgmt上下文,因此创建了一个座位可用性。 在第7分钟,用户下了一个订单(通过订单管理),购买

  • 很明显,基于这些模式的系统是易于扩展的。但我想问你,具体怎么做?关于可伸缩性,我没有什么问题: 如何缩放聚合体?如果我将创建

  • 我想创建一个CQRS和事件源架构,非常便宜,非常灵活,非常简单。 我想确保事件永远不会失败,至少到达发布者/事件存储,永远,因为这是业务所在。 天蓝 有了azure,我似乎不知道该用什么。 Azure服务总线 蔚蓝函数 Azure webjob(我想这可以用Azure函数代替) ??(还有什么我忘了或者不知道的?) null 你的经验说明了什么? 其他替代方案呢?(例如:)?

  • 在一个集合中对业务规则的验证是通过一致性问题的AR进行的。如何验证需要订单集合之外的数据的业务规则? 我也在使用CQRS方法,我认为使用ReadModel来获取验证业务规则所需的数据并不是一个糟糕的选择...您认为呢?