如果没有人需要在传输级别上发送可靠的消息,那么如何在业务级别实现可靠的PubSub?

时间:2017-04-15 08:40:08

标签: events architecture domain-driven-design publish-subscribe

这个问题主要是出于好奇。我前一段时间阅读this article about WS-ReliableMessaging by Marc de Graauw并同意应尽可能在业务级别应用可靠的消息传递。

现在,问题是,他清楚地解释了他的方法是以点对点的方式。但是,我没有看到如何在发布/订阅情况下在业务级别实现可靠的消息传递。

我将尝试通过显示命令(点对点)与事件(发布/订阅)来展示差异。请注意,这些示例非常简化。

命令:转移(uniqueId,amount,sourceAccount,recipientAccount)

如果帐户持有人发送此转帐,他可以等待确认MoneyTransferred(假设此事件将包含对uniqueId命令中Transfer的引用。

如果帐户持有人在给定的超时期限内未收到MoneyTransferred,他可以再次发送相同的命令。 (当然假设命令处理器是幂等的)

因此,我看到可靠的消息传递如何以点对点的方式在业务级别上运行。

现在,假设我们上一个命令成功并产生了MoneyTransferred事件。在系统的某个地方,我们有一个处理MoneyTransferEmailNotifier事件的事件处理器(MoneyTransferred),并会向转移的接收者发送电子邮件通知。

MoneyTransferEmailNotifier订阅MoneyTransferred个事件。但请注意,发送MoneyTransferred事件的系统并不真正关心此事件的监听者数量或数量。重点是这里的脱钩。我提出了一个事件,并不关心是否有零个或20个听众订阅此事件。

此时,如果基础架构没有提供可靠的消息传递(最少至少一次传递),我们如何防止MoneyTransferred事件的丢失?我确实希望收件人收到他的电子邮件通知。

我没有看到任何真正的“业务级”解决方案如何解决这个问题。

(1)我能想到的解决方案之一是明确订阅“业务级别”上的事件,从而绕过任何基础架构组件。但是,那时我们不是在我们的业务中引入基础设施吗?

(2)另一个“解决方案”是引入一个类似这样的流程管理器:

  1. PM收到Transfer命令
  2. PM将Transfer命令转发到帐户子系统
  3. 如果成功,请将命令SendEmailNotification(recipient)发送到通知子系统
  4. 这似乎是DDD规定的解决方案,对吗?但这不会引入更多耦合吗?

    您怎么看?

    编辑2016-04-16

    也许根本问题更简单一点:如果您没有确保至少或一次交付的基础设施组件,您如何确保(当您处于最多状态时) -once infrastructure)你的事件会被收到?

    并非所有事件都需要传递,但有许多事件是关键的(如发送确认电子邮件的示例)

2 个答案:

答案 0 :(得分:1)

  

如果没有人需要在传输级别上发送可靠的消息,那么如何在业务级别实现可靠的PubSub

原始文章没有声明“没有人需要在传输级别上发送可靠的消息”,它指出应该在业务级别强制执行消息的排序,因为在某些情况下如果这种排序是业务的一个重要特征。

在任何情况下,PubSub都处于基础架构级别,您不能说您在业务级别实施PubSub。这没有意义。

但是,如何才能确保在业务层面只交付一次?使用Saga/Process manager。关于他们的重要责任正是如此。您可以将它与幂等Aggregates结合使用。此外,您可以从Ubiquitous language transaction phase中找出强调排序的字词,并将其包含在您的域模型中(例如,作为事件的属性)。

  

如果您没有基本确保的基础设施组件   或者恰好一次交付,你怎么能确保(当你在   您的事件发出的最多一次基础设施   收到?   如果你没有至少一次,那么你可以使用它启动空洞过程的第一个事件。我会使用事件轮询和Saga来确保在适当的时刻达到流程中的每个重要步骤。

在您的情况下,由于发送电子邮件是一项重要的业务方面,我会将其作为此过程中的一个步骤。

答案 1 :(得分:1)

  

此MoneyTransferEmailNotifier订阅了MoneyTransferred事件。但请注意,发送MoneyTransferred事件的系统并不真正关心此事件的监听者数量或数量。重点是这里的脱钩。如果有零个或20个听众订阅此活动,我会举办活动而不在乎。

我相信你的纠结在这里 - 只有发布订阅中间件可以将事件传递到他们需要去的地方。

Greg Young在polyglot data (slides)的演讲中介绍了这一点。

总结:发布/订阅中间件的方式是。基于拉取的模型,消费者从持久事件存储中检索数据,为您提供从商店检索消息的可靠方法。因此,您从商店中提取数据,然后使用业务级别数据像以前一样识别以前的工作。

例如,在使用其业务数据检索MoneyTransferred事件时,流程管理器会查找具有匹配业务数据的EmailSent事件。如果找到第二个事件,则进程管理器知道至少有一个电子邮件副本已成功传递,并且不再需要进行任何工作。

基于推送的模型(发布/订阅,UDP多播)变为延迟优化 - 推送消息的到达告诉订户提前拉动。

在极端推送情况下,您可以将推送消息打包到订户可以立即对其进行操作的足够信息,并相信当消息的冗余副本到达时,幂等处理消息将防止出现问题较慢的频道。