事件驱动系统有各种形状和大小。明显的共性是:;它们都使用事件来传递信息。这些事件有多种形式和大小,确定事件的内容对系统的设计有着巨大的影响。
在这篇帖子里我';I’我想回顾三种不同类型的活动。我希望澄清这些类型将使您能够更好地讨论事件驱动的体系结构和集成。
当我与其他开发人员讨论事件时,我会区分三种类型的事件。每种类型都有其独特的特点、优势和劣势。这些类型的事件都不一定比另一种更好,但在特定情况下,特定类型的事件可能更适合。
让';让我们逐一检查一下,看看它们是什么,什么时候有用。
对于任何对领域驱动设计感兴趣的人来说,这将是最熟悉的活动类型。领域事件是历史的记录,捕捉重要时刻的意图和任何相关背景。领域活动关注";域名";,这意味着他们专注于与业务相关的事情。因为它们记录历史,所以用过去时态表达。
域事件的命名方式应明确表达其意图。建议使用人类语言来命名这些事件,尽量避免";哔哔哔";语言不要将事件命名为OrderStateChanged或OrderEvent,而是使用OrderWasShipped之类的名称。
与其他事件类型不同,域事件非常适合捕获意图。因为域事件只捕捉重要时刻的相关上下文,所以它们对于捕捉变化也很有用。这让活动消费者对正在发生的事情有了深刻的了解。事件源系统更进一步,使域事件成为软件模型的基石。
域事件特别适合用于创建读取模型。在阅读案例需求与决策有用的数据模型非常不同的情况下。无论是在创建读取模型还是在分析数据模型中,以更改和意图为中心的表示都非常适合聚合。
类orderwashipped{public function _构造(private OrderId$OrderId,private MomentOfSchipment$shippedAt,private ShipmentAddresss$shipmentAddress,);公共函数OrderId():OrderId{return$this->;OrderId;}公共函数shippedAt():MomentofChipment{return$this->;skippedAt;}公共函数shipmentAddress():ShipmentAddresss{return$this->;shipmentAddress;}
域事件对于捕捉意图和";改变";。它们允许您构建功能强大的读取模型,比原始数据模型上的复杂查询具有更好的扩展性。领域意图对于创建分析模型非常有用,可以提供对业务中发生的事情的深刻见解。
域事件暴露域内发生的事情。如果消费者依赖这些信息,他们就会与之耦合。如果使用领域事件来创建决策模型,那么这些事件的耦合可能会对开发速度造成压力。耦合增加了变化的成本,因此它';知道你向谁暴露了什么总是好的。作为一个默认的实践,考虑每一个领域事件和34;私人";,只用于内部消费。只有通过故意曝光,消费者才能访问事件,就像使用API而不是直接访问数据库一样。
触发器或信号事件是最小的事件。此事件通常只包含引用聚合或实体的ID,可能还包括时间戳。正如trigger这个名字所暗示的,这些事件被用来触发消费端的反应。触发器最常用于将更改通知其他业务流程。如果你';重新存储敏感数据(看着你,GDPR)触发器的使用有助于防止事件基础设施暴露于具有挑战性的需求。
类orderwashipped{public function__构造(private OrderId$OrderId);public function OrderId():OrderId{return$this->;OrderId;}}
当域事件可能包含敏感数据时,触发器非常有用。在这些情况下,生产者发送一个信号,并期望消费者使用一个安全的API来获取相应的ID。触发器不容易导致信息级耦合,仅仅因为它们不';不要装任何东西。
由于触发器不包含任何信息,消费者总是依赖于API。当许多使用者使用许多事件时,这可能会给系统带来一些意外负载。信息的缺乏也限制了聚合数据的能力。
由于事件是异步处理的,因此从API检索的数据可能处于使用者期望的不同状态。使用者必须始终检查从API检索的资源是否符合预期,并准备好处理资源可能处于的任何状态。例如,如果订单已发货,但商户立即取消发货,消费者可能会检索到一个没有';与事件名称显示的状态不匹配。当事件处理延迟时,可能会产生意外的结果。
最后一个原型是";肥胖"岁;事件我个人更喜欢术语RESTful event,因为它更好地描述了负载中的内容。这种类型的事件包含从RESTful API检索的完整资源表示。这是一次极好的集成活动,对外部消费者最为有用。
与触发器相比,RESTful事件会阻止使用者往返于API。如果您将其与域事件进行比较,它可以防止使用者必须组合多个事件才能获得完整信息。
类orderwashipped{public function _构造(private OrderId$OrderId,private OrderLines$OrderLines,private DiscountCodes$DiscountCodes,private OrderAmount$OrderAmount,private momentofChipment$shippedAt,private ShipmentAddresss$shipmentAddress,);公共函数OrderId():OrderId{return$this->;OrderId;}公共函数orderLines():orderLines{return$this->;orderLines;}公共函数discountCodes():discountCodes{return$this->;discountCodes;}公共函数orderAmount():orderAmount{return$this->;orderAmount;}公共函数shippedAt():MomentofChipment{return$this->;skippedAt;}公共函数shipmentAddress():ShipmentAddresss{return$this->;shipmentAddress;}
RESTful活动有助于将状态推向消费者。在一种情况下,消费者对资源了如指掌。对于每个资源,只需要将最后一个事件备份到最新状态,这对灾难恢复非常有用。在另一个服务依赖于您的服务的状态的情况下,使用RESTful事件是将状态推送到那里的好方法。在最终一致性可以接受的情况下,这样做将消除对服务的直接依赖。
以我的经验,RESTful事件只作为";室外";消费者。它们对于内部建模没有用处。它们体积大,更匿名,传达的意图也更少,因此不太适合内部建模。RESTful事件通常需要构建一个反腐败层,以将其他类型的事件转换为RESTful事件,即";额外";工作
在技术讨论中,它';这很容易让人跳转到解决方案上来。只需添加字段,只需将此内部事件公开给外部使用者,解决问题。我';d希望通过确定几种类型的事件,你可以将这些信息纳入你的讨论中';我们正在吃。试着确定计划中的事件类型,它们有哪些特征,以及这些特征如何影响你应用它们的情况。公开域事件?注意信息级耦合。因为消费者需要而向活动中添加越来越多的信息?也许换成一个安静的活动。最后,请记住,如果在正确的环境中应用不同的沟通方式,效果最好。它';这取决于你意识到这一点并做出正确的选择。
基于事件和消息的设计的优点之一是翻译的可能性。翻译层通常被称为反腐败层,有助于在信息层面上实现解耦。ACL过滤和转换信息。这可以在集成的任何一方、生产者或消费者进行。ACL也可以实现为中继,即消耗和转发(产生)消息的逻辑片段。EventSauce最近附带了一个全面的工具集,用于构建自己的ACL。在文档中阅读所有关于它们的信息。
我希望这对你有用。如果你有任何问题或想跟进帖子中突出显示的某个项目,请在推特上向我提问。