为了账号安全,请及时绑定邮箱和手机立即绑定

我怎样错用事件驱动架构的方式?

在我的最近项目中,我旨在使用事件驱动架构重写一个混乱的代码基础。然而,我发现真正实现解耦比我想象的要难得多。我打算在我的博客上分享我的经历和学到的教训。

基于事件驱动架构的承诺

我从一个服务开始,这个服务在一个文件中有超过2000行的代码。这个服务类负责更新多个组件中的多个实体,这些实体内部和外部都有复杂的条件和逻辑。一个组件中的变化可能会以不可预测的方式影响其他组件。当缺乏足够的测试代码来覆盖服务类的各种情况时,这会带来更多麻烦。

这里就是事件驱动模式的概念。这个模式的核心思想是明确地分离关注点,从而不必担心意外的变化。每个用例只需专注于更新一个实体并发布相应的事件。事件监听器监听感兴趣的事件,然后调用相应的用例来更新相关的实体。目标是创建一个松耦合的系统,使各个组件可以独立发展。

瑞典翻译成中文应直接反映标题意思,这里是符合语境的直译:
瑞典原文是英文,所以无需提及从瑞典语翻译,直接给出合适的中文翻译即可:
事情开始出问题了
双向交流面临的难题

事件驱动的方法最初看起来很有前景,但很快就开始出问题了。事件驱动架构的一个主要限制是它不适用于双向通信。事件的发布和订阅本质上是单向的,即从A到B。与直接调用模式不同,其中A向B发送请求,B回应A,事件驱动系统没有内置机制让B能够回传消息给A。

这就会出现问题,当A需要根据B的结果采取行动时。一个常见的例子是订单服务(A)和支付服务(B)。当订单被提交时,A会向B发送OrderPlaced事件。如果B在处理支付过程中遇到问题(例如,用户的信用卡被拒绝),B需要告知A出现问题,这样A可以根据情况采取适当的措施,比如通知用户更换另一张信用卡。

在事件驱动系统中,A向B发送OrderPlaced事件并且B无法轻易地向A反馈,会让用户感到困惑。用户可能无法立即收到关于支付问题的反馈。

要解决这个问题,可以考虑给 B 单独设置一个端点,比如通过 webhook 向 A 传达支付结果。然而,这会增加系统的复杂性。如果 B 是外部服务,通过新的端点同步结果并不总是可行。

A和B之间的互动变得更乱了,A向B发送事件,B需要找到一种办法回复A。这破坏了事件驱动系统最初承诺的简洁和优雅。

交易一致性与最终一致性的挑战

以事务性的方式来思考与以最终一致性的方式来思考是完全不同的。在最终一致性的系统里,服务A假设,在向服务B发布事件后,服务B最终会完成任务。实际上,这比听上去要复杂得多。

例如,比如说服务A(订单服务)和服务B(CRM,客户关系管理服务):
注:句子末尾已加上句号,使句子更加完整。但由于“比如说”和“服务”之间添加句号会导致句子结构混乱,故未在两者之间添加句号。

  • 服务A负责订单处理,并在订单完成后向用户发送通知。
  • 服务B负责管理会员奖励,这些奖励会与商品一起寄送给常客。
  • 要求是服务A需要在订单完成的通知中提及已发出的会员奖励。

在事件驱动的系统中,服务A发送一个orderCompleted事件给服务B,服务B在接收到这个事件后开始其任务。当服务A需要为通知获取会员奖励信息时,它必须向服务B询问与尚未发送的已完成订单相关的奖励信息。而在事务性场景中,当通知发生在完成订单并已发放奖励之后,服务A需要找到已经发送出去的奖励。

在思维上从最终的一致性转换到事务的一致性是很具挑战性的。我们得时刻记得这些实体之间的关系——它们是否是按顺序处理的,还是通过事件来处理的。

管理一系列事件的困难

在事件驱动的架构中,事件订阅者可以确信事件发布者已经完成了其任务。当服务A向服务B发布事件时,服务B就可以确定引发该事件的服务A的任务已经完成。

管理事件链带来了一套新的挑战。在上图所示场景中,当服务D启动其事件监听器时,它能够确定与事件D和E相关的流程已经结束。通过传递性原则,它还可以假设触发事件A和B的用例场景也已完成。

然而,服务 D 无法确定与事件 C 及其相应监听器相关的流程在它开始执行时是否已完成。如果服务 D 需要作为整个事件链的最终环节,例如在它发送邮件通知用户服务 A、B 和 C 所有流程已完成的情况下,这就会成为一个问题。

一种解决方案是为事件分配优先级,确保优先级最低的事件最后被发布。虽然这种方法有助于管理顺序,但同时也,在事件之间创建了隐含的依赖关系。在向系统添加新事件时,需要考虑一些因素。

  • 在这个事件链中,这个事件应该放在哪里?
  • 事件链中哪些事件已经被分配了优先级?

要回答这些问题,这往往需要追踪整个事件链。这比在单一用例中排列服务顺序要难得多。

最后,

到最后,

我决定不再尝试将一切都解耦并通过事件发布/订阅来管理。相反,我将大部分流程保持在一个单一的使用场景中,并将那些没有陷入上述问题的流程移到事件和事件监听器中。理解事件驱动模式的优缺点可以帮助我们做出更好的选择,因此在此总结了一张表格作为本文的重点。

点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消