其他分享
首页 > 其他分享> > 领域驱动设计(2) 领域事件、DDD分层架构

领域驱动设计(2) 领域事件、DDD分层架构

作者:互联网

领域事件

什么是领域事件

在事件风暴过程中,会识别出命令、业务操作、实体等,此外还有事件。比如当业务人员的描述中出现类似“当完成...后,则...”,“当发生...时,则...”等模式时,往往可将其用领域事件来实现。
领域事件表示在领域中发生的事件,它会导致进一步的业务操作。如电商中,支付完成后触发的事件,会导致生成订单、扣减库存等操作。

为什么需要领域事件

领域事件的最终目的是为了实现聚合之间的解耦。事件模式是一种通用的解耦方法,相比依赖间的直接调用,通过事件方式形成的间接依赖,在扩展、重构时更加灵活。
在上一篇领域驱动设计(1) DDD的一些基础概念中提到设计聚合的原则之一:

在边界之外使用最终一致性。聚合内数据强一致性,聚合之间数据最终一致性。在一次事务中,最多只能更改一个聚合的状态。如何一个业务操作涉及多个聚合状态的更改,可以采用领域事件的方式,实现聚合之间的解耦;

聚合根管理多个实体,可以在单个进程内实现数据的强一致性;将DDD实现为微服务时,聚合间的交互可能需要采用进程间的通信的方式(HTTP,RPC,MQ),此时如果仍然采用强一致性代价太高,且可靠性差,而最终一致性就成了更好的选择。(领域)事件就是实现最终一致性的一种方式。

领域事件可以切断领域模型之间的强依赖关系,发布方发布事件后不需要关注订阅方处理事件是否成功,这样实现领域模型的解耦,保证领域模型间的独立性,同时也能实现数据的最终一致性。

微服务场景下的领域事件

领域事件发生在聚合之间,聚合也是微服务拆分的最小单元。但实践中并不一定每个聚合都拆分为独立的微服务,可能多个关联性高的聚合会被置于同一个微服务中,所以用于聚合间交互的领域事件,在微服务场景下可以细分为微服务内和微服务间的领域事件。

微服务内的领域事件

微服务内的领域事件不是必须的,因为微服务内的操作都发生在同一个进程,可以较方便地控制事务。
假设微服务包含多个聚合,不管是聚合内,还是这些聚合间的交互实际上都发生在进程内,可以做到强一致性。但这不符合DDD在一次事务中,最多只能更改一个聚合的状态的原则,此外聚合间采用同步调用的方式也会带来强耦合。
所以可以考虑采用事件总线的实现方式,但事件驱动本身的复杂度大于同步调用,在微服务内处理聚合间的交互还有另一种选择,那就是在应用层来编排和组合跨聚合的调用。
可以结合具体场景分析各种方式的成本和收益。

微服务间的领域事件

微服务间的领域事件用于在跨聚合甚至跨限界上下文间实现业务协作,其主要目的是实现微服务解耦,用异步的领域事件代替同步调用,可以避免微服务间的弹性依赖。

领域事件的实现

领域事件设计事件的生成和发布、事件持久化、事件总线、消息中间件、事件订阅和处理等。
领域事件

DDD的分层架构

实现DDD的架构有很多种,比如整洁架构(洋葱架构)、六边形架构、DDD分层架构等等。对整洁架构(洋葱架构)、六边形架构不做了解,只focus在DDD分层架构。
DDD分层架构

DDD分层架构如何推动微服务演进

领域模型中对象的层次从下到上依次有值对象、实体、聚合、限界上下文。
其中值对象和实体的功能变化,会影响微服务内部的实现变化;聚合的功能变化、重组则会影响微服务的拆分、合并。
首先,在微服务内部,实体的方法被领域服务组合和封装,而领域服务又被应用服务组合和封装。领域层通常只提供一些原子的方法,这些方法在应用层被组合起来提供完整的功能,比如原先提供了领域服务A、领域服务B、领域服务C,应用层按需组合这些领域服务,但过一段时间后发现领域服务B、领域服务C总是被同时调用,那么就可以将他俩重构为一个领域服务。
然后,在微服务之间,可能会用限界上下文来分割微服务,但实际上聚合才是微服务划分的基本单元,因为聚合是最小的、业务内聚的单元,聚合可以独立完成特定的业务逻辑。所以有的时候会将同一限界上下文的聚合拆分为不同的微服务。假设原先微服务中包含聚合A、聚合B,但实际运行中发现聚合A的访问频次远高于聚合B,导致聚合B的性能受到了影响。此时就可以将聚合A独立为单独的微服务。

PS:徐昊在极客时间《如何落地业务建模》中认为,划分微服务的依据应该是弹性边界。从此处DDD对微服务的处理来看,徐昊老师的观点可谓一针见血。比如这里的聚合A与聚合B拆开的例子,明显两者处于不同的弹性边界。

参考资料: 欧创新 《DDD实战课》

标签:架构,服务,领域,分层,事件,聚合,DDD
来源: https://www.cnblogs.com/zhixin9001/p/16063807.html