2026年10月9日
DDD与事件消息架构
介绍 DDD 中的事件溯源与事件驱动架构,梳理常见事件消息架构风格、应用场景及高可用风险。
一、DDD的事件溯源模式
1.1 事件溯源模式回顾
摘录:将领域中所发生的活动建模成一系列的离散事件,每个对象都用领域对象来表示。领域事件是领域模型的组成部分,表示领域中所发生的事情。
1.2 事件驱动架构在DDD中的位置
事件驱动架构实际上弥补了从单体服务到分布式服务跃进的一个短板。在单体服务中上下领域服务之间的交互可能非常简单,就是请求和返回。但是随着微服务和分布式的出现,更多的业务场景要求对上下游服务进行解耦。在DDD中也一样,事件驱动架构风格和事件溯源模式弥补了DDD面向微服务和分布式的一个短板。DDD本身的领域事件可以在事件驱动架构中进行整合,具体到项目里就是事件消息。事件驱动架构通过消息来构建上下游之间的关系。这种关系不是直接能看到的,就比如下游到上游的消息,上游发的消息哪些下游能收到。事实上,这种模式解决了两个问题,一个是上下游之间的服务依赖耦合,另一个是对整个业务逻辑的补充。比如,正向业务中的核心系统肯定通过一些服务依赖进行数据传递处理业务,但是有些边缘系统虽然也会收到消息但是却不一定绝对影响核心流程。
在DDD工程或者分布式工程中事件驱动架构中的事件可以分为两类
1.进程内事件
进程内事件可以在不同模块通过线程或者共享内存来实现通信和消息发送订阅等。
2.进程间事件
进程间事件就是在不同机器,不同进程服务之间通过网络来传递消息。
一般情况下企业常见的策略并不是把事件架构作为核心架构去做业务,之前的ESB总线已经证明会导致一些性能和维护问题,但是事件驱动仍然不可或缺,如下是企业架构用到的事件驱动架构图:

1.3 事件驱动实践简述
由于事件驱动架构实现需要依赖一些中间件或者工具jar包,那么技术层面的东西肯定要放在基础设施层中,因此在分层架构中也包括了消息中间件的依赖,并封装了消息发送和消息消费的逻辑。消息发送和消息消费在分层架构中的处理其实有些区别。在DDD代码实践篇会讲到如何利用spring event publish机制来解耦消息消费场景。
二、事件消息架构风格
本小节主要讲述关于事件消息架构的一些风格和行业相关的架构应用。
2.1 事件驱动架构(Event Driven)
事件驱动架构就是经常见到的一种消息架构,一般来说都默认支持事件溯源,因为一旦应用起来那么消息基本上是要求进行存储和备份的。
2.2 LMAX架构
LMAX架构在股票交易系统中得到了经典的应用,这是典型的进程内消息通信的一种实现方案。其产品disruptor已经在很多中间件中应用到了。
2.3 数据驱动型事件架构
一般来说数据驱动指的是基于数据做一些业务逻辑,辅助业务发展,这里的数据驱动型事件指的是类似于审批流事件或者带有一些固定流程模板的方式。当然另外一种体现就是数据变更,比如mysql的binlog等。
2.4 基于事务消息的架构
严格来说基于事务消息的架构其实不算一种架构风格,从全局来看这种支持事务消息的场景只是消息中间件的一个特性。但是在分布式系统中事务消息实际上要做好会难的很多。分布式事务的解决方案也不只这一个,一旦要支持这个特性那么在消息中间件设计的过程中就需要考虑分布式事务的一些问题了。
2.5 基于事件流的架构
事件流实际上算是事件驱动的一个升级版本。在物联网应用,日志分析等场景下事件就像流水一样源源不断,同时在事件消费和处理中还需要考虑更多特性,比如滑动窗口,事件统计分析等。对事件流的处理实际上会比事件驱动架构上的处理更加复杂。如下是事件流架构的图例:

三、事件消息架构应用
3.1 Disruptor
3.2 Kafka,Flink
3.3 rabbitMQ,rocketMq
四、事件驱动架构高可用的风险
4.1 事件数据存储
1.消息丢失
2.消息压缩
4.2 事件消费
1.重复消费
2.消费速度不一致
3.消费不到
4.消息堆积
5.消息幂等
4.3 事务消息
1.事务消息失效
4.4 事件顺序
1.事件乱序
4.5 多租户
1.事件元数据管理混乱
4.6 事件延迟
1.延迟消息失败
因此,如果用到消息架构肯定会有以上的业务需求或者相关问题,那就需要针对消息中间件做专门的维护和迭代,如下是消息事件在整个发布订阅过程中需要的一些技术和特性:

五、参考
在事件驱动架构上也有很多大佬说出了一些自己的见解,这里给出引用链接,方便读者扩展阅读。
https://martinfowler.com/articles/201701-event-driven.html
https://martinfowler.com/articles/lmax.html
评论
评论由 GitHub Discussions 提供,使用 GitHub 账号登录后即可参与讨论。