假设我要使用服务A
-D
建立事件驱动的体系结构,事件将按如下方式传播
A
/ \
B C
/
D
换句话说,
(1)A
发布事件
(2)订阅者B
和C
收到A
的事件
(3)C
发布事件
(4)订户D
收到C
的事件
一种方法是让服务B
和C
直接侦听A
向其中发布消息的队列。但是我看到的问题是维护。一旦系统变得复杂,需要数千个订阅,就很难了解更新的传播方式。
我为这个问题提出的解决方案是拥有另一个服务X
,该服务知道第一张图片中的树,并负责根据树来指导事件的传播。每个服务都将其事件发布到X
,并将事件发布到侦听服务。所以有点像中间人
A
|
X
/ \
B C
|
X
|
D
这也使跟踪事件传播更加容易。
这有什么缺点(除了与两倍的邮件传输相关的额外费用外)?
答案 0 :(得分:1)
您想到的是事件,例如在Winforms UI中实现的事件,在该事件中,发布者将事件直接发送给订阅者。这不是事件在EDA架构中的工作方式。 “事件”一词具有全新的含义。
在我们开始之前,您需要将消息和事件的想法真正地分开放置。消息是对某些操作的要求,而事件是对已经发生的事情的通知。此讨论的重要区别是消息发布者假定有1个或多个其他进程将接收和处理该消息。如果消息未得到处理,则将发生下游错误。事件没有这样的假设,并且可以在不产生任何不利影响的情况下被忽略。另一个区别是,一旦处理完邮件,通常会将它们丢弃,而将事件保留更长的时间(几天或几周)。
请牢记,您所谈论的“ X”服务已经存在(请不要构建其中一项),并且是该过程不可或缺的-称为总线。巴士有2种类型;消息总线(例如RabbitMQ,MSMQ,ZeroMQ等)或事件总线(Kafka,Kinesis或Azure Event Hub)。无论哪种情况,发布者都会在总线上发送消息,而订阅者则从总线上获取消息。您可以将总线服务器实现为多条物理总线,但是在想象中它们都属于同一逻辑总线。
让您绊倒的关键点是一个微妙的区别,它认为消息总线具有指示消息去向的业务逻辑。谁得到什么消息的业务逻辑由订户决定–消息总线只是消息等待提取的存放地。
在您的示例中,A将消息类型为“ MT1”的事件发布到总线。 B和C都告诉总线,他们对“ MT1”类型的事件感兴趣。当总线从B和C接收到要通知“ MT1”消息的请求时,总线为B创建队列,为C创建队列。当A发布消息时,总线将副本放入“ B-MT1”队列和“ C-MT1”队列中的副本。请注意,公共汽车不知道B和C为什么要接收这些消息,仅是他们已订阅。
这些消息坐在那里,直到被其各自的订户处理(进程可以轮询或总线可以推送消息,但是关键思想是消息一直保留到处理)。处理后,消息将被丢弃。
为使C与D通信,D将订阅“ MT2”类型的消息,而C将其发布到总线。
康斯坦丁(Constantin)的回答是,这是一个单点故障,但是可以使用标准网络体系结构(例如故障转移服务器,本地消息持久性,消息确认等)来管理它。
您担心的一个问题是,有了1000个订阅,就很难走这条路,这是对的。这是EDA固有的缺点,您对此无能为力。最终的一致性也是企业要抱怨的问题,但这是野兽的一部分,并且从技术角度来看实际上是一件好事,因为它可以实现更大的可伸缩性。我用“最终一致性”一词发现的最大问题是,企业认为这意味着数小时或数天,而不是几秒钟。
顺便说一句,整个讨论假设消息发布者和订阅者是不同的应用程序。所有相同的想法都可以在同一地址空间内使用,只是使用不同的总线。如果您是.net商店,请访问Mediatr。对于其他技术堆栈,我确信Google知道类似的解决方案。
答案 1 :(得分:1)
如果主要关注的是事件传播的可见性(这对于分布式系统的调试和长期应用程序维护是非常有效的关注),则可以使用相关标识符来跟踪从初始消息的生成事件贯穿整个链条。您不需要构建另一层业务流程-让您的消息传递平台为您处理。
大多数消息传递平台/库都有内置的概念:例如,NServiceBus在消息头中定义了ConversationId字段,而AMQP在基本消息传递模型中定义了correlation-id字段。
您的系统应该具有某种类型的日志记录,该日志记录可以让您审核消息-相关性ID将使您可以将单个命令/请求产生的所有消息归为一组,从而大大调试分布式逻辑更简单。
如果您在客户端请求中设置了GUID,甚至可以通过递归生成的所有事件,甚至将UI中的操作与后端API相关联。
答案 2 :(得分:0)
可以,但是微服务首先不关心它们如何获取消息。从他们的角度来看,输入消息才刚刚到达。然后,您将被设计为依赖某些全局事件顺序来设计系统,这在分布式可伸缩系统中很难做到。抵制这种诱惑并将您的系统设计为仅在事件的本地顺序上进行中继(即,事件源+ DDD中的汇总所发出的事件流中的顺序)。
我看到的一个缺点是可用性和可伸缩性可能会受到损害。这样,整个系统将只有一个故障点。如果失败,那么一切都会失败。当需要扩大规模时,您将再次遇到问题,因为您将拥有分布式消息传递系统。