这个问题主要是出于好奇。我前一段时间阅读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)另一个“解决方案”是引入一个类似这样的流程管理器:
Transfer
命令Transfer
命令转发到帐户子系统SendEmailNotification(recipient)
发送到通知子系统这似乎是DDD规定的解决方案,对吗?但这不会引入更多耦合吗?
您怎么看?
也许根本问题更简单一点:如果您没有确保至少或一次交付的基础设施组件,您如何确保(当您处于最多状态时) -once infrastructure)你的事件会被收到?
并非所有事件都需要传递,但有许多事件是关键的(如发送确认电子邮件的示例)
答案 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多播)变为延迟优化 - 推送消息的到达告诉订户提前拉动。
在极端推送情况下,您可以将推送消息打包到订户可以立即对其进行操作的足够信息,并相信当消息的冗余副本到达时,幂等处理消息将防止出现问题较慢的频道。