可以使用事件采购来解决迟到的事件

时间:2016-01-04 07:33:30

标签: cqrs azureservicebus event-sourcing

我们正在开发一个应用程序,它将通过消息队列(Azure)从各种系统接收事件,但有些事件(消息)可能不会按照它们发送的顺序到达。这些事件将由基于CQRS / ES的中央系统接收和处理,但我担心如果事件以错误的顺序放入事件存储中,我们将得到垃圾(例如“添加订单项后”的“订单创建”) “)。

典型的ES系统是否意味着解决此问题,还是我们打算确保在推入事件存储之前将这些消息按正确的顺序排列?如果您有链接到备份任一视图的文章,那将有所帮助。

编辑:我认为我的描述显然过于模糊,所以回复虽然有助于理解CQRS / ES,但并没有完全回答我的问题所以我会添加更多细节,希望有人会认识到这个问题。 / p>

首先是球员。

  • 前端网站(实际上与此问题无关)向管理系统下达订单。
  • 我们的管理系统从网站接收订单并将其传递到仓库并在现场托管。
  • 接受订单的仓库,如果可能的话履行订单,并在订单履行或无法部分或完全履行时通知我们。

将仓库链接到管理系统是一种相当薄的基于Azure云的耦合。来自仓库的消息被发送到云中的WCF / Soap层,解析并通过消息总线发送。通过消息总线发送到仓库的消息,然后再次在云中,将Soap调用转换为仓库中的服务器。

仓库非常小心,以确保它发送的消息具有无间隙递增的标识符,以便我们知道何时错过消息。然而,当我们接收这些消息并将它们转发到管理系统时,它们通过消息总线传输,理论上可能以错误的顺序到达。

现在假设消息中有序列号,我们可以确保消息在发送到CQRS / ES系统之前以正确的顺序放回,但我的问题是,是否必要,ES实际上是否可以用于将事件重新排序为他们想要的逻辑顺序?

5 个答案:

答案 0 :(得分:1)

到达服务总线的每条消息都标有SequenceNumber。 SequenceNumber是一个单调递增的无间隙64位整数序列,其范围限定为Queue(或Topic),它通过到达队列提供绝对订单标准。由于错误/中止而该订单可能与交货订单不同,因此您可以重新组合到货订单。

Service Bus中用于管理队列内部订单的两个功能是:

  1. 会话。 sessionful queue对具有相同SessionId属性的所有消息进行锁定,这意味着该序列保证FIFO,因为序列中的后续消息不会被传递,直到“当前”消息被处理或放弃为止
  2. 延期。如果此时无法处理消息,Defer method会将消息放在一边。该消息可以稍后be retrieved by its SequenceNumber,它从隐藏的延迟队列中提取。如果您需要一个位置来跟踪会话延迟的消息,则可以使用包含该会话队列的数据结构保存该信息right into the message session。例如,如果您将处理故障转移到另一台计算机上,则可以pick up that state again elsewhere on an accepted session
  3. 这些功能专为Office 365中的文档工作流而构建,其中顺序显然非常重要。

答案 1 :(得分:1)

我会对KarlM的答案发表评论但是stackoverflow不会允许它,所以这里有...

听起来您希望传输机制在聚合上提供事务锁定。对我来说这听起来本身就是错误的。

听起来好像提出的设计存在缺陷。在过去遇到这个问题时,我会看看你的约束。您要么为网站提供交易保证,要么想要将它们提供给仓库。你不能两者都做,总是赢。

完全分发:如果您想将它们提供给网站,那么仓库必须询问它是否可以开始履行订单。如果您想将它们提供给仓库,那么网站必须询问是否可以取消订单。

希望这很有用。

答案 2 :(得分:0)

对于从"乐观锁定中的单个命令处理程序/聚合生成的事件"方案,我假设您将在事件中包含聚合版本,因此这些事件是隐式排序的。

来自多个聚合的事件不应该关心订单,因为聚合的事务保证。

查看http://cqrs.nu/Faq/aggregateshttp://cqrs.nu/Faq/command-handlers及相关常见问题解答

有关ES和乐观锁定的介绍,请查看http://www.jayway.com/2013/03/08/aggregates-event-sourcing-distilled/

答案 3 :(得分:0)

你说: “这些事件将由基于CQRS / ES的中央系统接收和处理,但我担心的是,如果事件以错误的顺序放入事件存储中,我们将被垃圾输出(例如”添加订单后“订单创建”项目”)。” 关于事件采购的CQRS模式似乎存在误解。 简单地说,事件源是指您通过内部生成的事件更改聚合(根据DDD术语),聚合持久性由事件表示,聚合可以通过重放事件来恢复。这意味着范围非常小,即Aggregate本身。 现在,具有事件源的CQRS意味着来自聚合的这些事件被发布并用于创建读取投影或具有不同目的的其他域模型。 鉴于上述解释,我并没有真正得到你的问题。

与订购相关:

  • 已经有一个答案提到乐观锁定,因此必须对单个Aggregate中生成的事件进行排序,并且乐观锁定是一种解决方案
  • 按顺序读取投影处理事件。我过去使用的解决方案是在RabbitMQ上发布事件并使用Storm处理它们。 RabbitMQ对订购有一些保证,Storm有一些处理亲和功能。对于Storm,(据我记得),允许您指定对于给定ID(例如聚合ID)将使用相同的处理程序,因此事件的处理顺序与从RabbitMQ接收的顺序相同。

答案 4 :(得分:0)

MSDN https://msdn.microsoft.com/en-us/library/jj591559.aspx上的文章指出“存储事件应该是不可变的,并且始终按照”性能,可伸缩性和一致性“中的保存顺序读取。这显然意味着不能容忍无序附加事件。同一篇文章还多次声明,虽然事件无法改变,但可以进行纠正事件。这将再次暗示事件按接收顺序处理以确定当前事实(聚合的状态)。我的结论是,我们应该在将事件发布到事件存储之前修复消息传递顺序问题。