为什么事件源是微服务交互的反模式

再一次问好。OTUS在三月启动了Software Architect课程的下一阶段预期课程的开始,我们已为您准备了有用材料的翻译。




最近,事件驱动的体系结构(事件驱动的体系结构),尤其是事件源(事件的生成)已经变得很普遍。这是由创建可持续且可扩展的模块化系统的愿望所驱动的。在这种情况下,经常使用术语“微服务”。我认为,微服务只是实现“ 绑定上下文 ”的一种方式。正确定义模块的边界非常重要,Eric Evans在“域驱动设计”中描述的战略设计可以帮助实现这一点。它可以帮助您识别/检测模块,边界(“受限上下文”)并描述这些上下文之间的相互关系(上下文映射,ContextMap)。

域事件作为一种语言的基础


尽管在Eric Evans的书中没有明确指出,但是领域事件对DDD概念的贡献很大。诸如Event Storming Alberto Brandolini之类的做法将事件的重点从技术层面转移到组织和业务层面。在这里,我们不是在讨论用户界面事件,例如单击按钮(ButtonClickedEvent),而是在主题区域中讨论域事件。主题领域的专家对它们进行了讨论和理解。这些事件是主要概念,有助于形成一种统一的语言(普遍存在的语言),所有参与者(主题专家,开发人员等)都将同意。

用于在上下文之间进行通信的域事件


域事件可用于在受限上下文之间进行交互。假设我们有一个具有三个上下文的在线商店:订单(交付),交付(交付),发票(帐户)。

订单上下文中考虑事件“订单已接受”发票上下文以及传递上下文都希望跟踪此事件,因为此事件会触发这些上下文中的一些内部流程。

弱连接的神话


使用域事件有助于开发松散耦合的模块。各个模块可能暂时不可用。但是对于域事件,是否可以使用它们绝对不重要,因为事件仅描述了过去发生的事情。其他模块决定何时处理事件。默认情况下,您将获得一个灵活的系统。

除了时间上的脱钩外,域事件还为您提供了另一项优势:订单上下文不需要知道发票和交货的上下文会侦听其事件。实际上,他甚至不需要知道这些上下文的存在。

很好,但是困难在于决定在事件中存储哪些数据?

简单的答案:事件源!


事件很有用,所以为什么不最大限度地使用它们呢?这是事件源的主要思想您存储单元的状态不是通过更新其数据(CRUD),而是通过使用事件流。
除了可以播放事件并获得状态之外,事件搜索还有另一个功能:免费获得完整的审核日志。因此,当需要此类日志时,在选择存储策略时,请务必注意“事件源”。

事件源只是存储层


我立即从域事件切换到存储,对您来说似乎很奇怪,因为很明显,这些是不同级别的概念。

...这是我的观点:事件源是仅在一个有限的上下文中使用的本地解决方案!事件采购事件不应被带到外界!其他受限制的上下文不需要了解彼此的数据是如何存储的,因此某些上下文是否使用事件源也无关紧要。

如果您在全局范围内使用“事件来源”,那么您将披露存储级别。

数据存储方法成为您的公共API。每次更改存储层时,都必须处理公共API中的更改。

我相信每个人都会同意,由于所产生的连接性,当各种有限的上下文在(关系)数据库共享数据时,这是不好的但这与事件来源有何不同?没有。在数据库中使用共享事件或共享表都没关系。在这两种情况下,您都共享存储详细信息。

有出口


我仍然认为领域事件是在有限的上下文之间进行交互的理想选择,但是这些事件不应与用于事件源的事件相关。

提议的解决方案非常简单:无论您使用哪种存储数据的方法(CRUD或事件源),都可以在全局事件存储中发布域事件。这些事件代表您上下文的公共API。使用事件搜索时,您将事件搜索事件存储在本地存储中,仅在此受限上下文中可以访问。

选择自由


在公共API中具有单独的域事件,可以灵活地对其进行建模。您不仅限于事件来源预定义的模型。

处理“真实事件”有两种选择:开放协议服务和公共语言(开放主机服务,发布的语言)或客户/供应商。

具有开放协议和公共语言的服务(开放主机服务,已发布语言)


仅发布一个域事件,其中包含其他有限上下文可能需要的所有数据。在DDD术语中,这可以称为开放主机服务和发布语言。



实际事件“订单已接受”的发生导致一个OrderAccepted域事件的发布此事件的有效负载包含其他受限上下文可能需要的所有订单数据...因此希望发票和交货上下文可以找到他们需要的所有信息。

客户/供应商


对于每个消费者,将发布单独的事件。只需要与一个使用者协调每个事件的模型;没有必要确定一个公共的共享模型。 DDD将此关系称为客户/供应商。



发生“接受订单”的现实事件会导致为每个消费者发布个别事件:InvoiceOrderAcceptedDeliveryOrderAccepted。每个域事件仅包含收件人上下文所需的数据。

我现在不想讨论这些方法的利弊。我只想提请您选择域事件的数目及其存储的数据这一事实。

这是您不应该低估的优点,因为您可以决定如何开发受限上下文的API,而不必绑定到Event Sourcing事件。

结论


暴露存储部件是一种众所周知的反模式。说到存储,我们主要考虑数据库表,但是我们看到用于事件源的事件只是存储数据的另一种方式。因此,将它们分发出去也是一种反模式。


翻译:“像狼人一样的好开发商害怕银弹。”

如果正确(在本地)使用事件源,则是一种强大的方法。乍一看,对于面向事件的体系结构来说,这似乎是灵丹妙药,但是如果仔细观察,您会发现这种方法可以建立牢固的连接……这当然是您所不希望的。

参考文献


除了个人经历,我还从各种文章和会议中获得了很多启发。我想提到Eberhard Wolff的演讲“使用Kafka和Atom的基于事件的体系结构和实现”(使用Kafka和Atom的事件体系结构和实现)。特别是关于事件源以及什么是事件,这在本文中非常重要。在线商店的例子也受到了这次演讲的启发。

如果您需要更多信息,可以参考以下资源:


: « : ».

All Articles