DDD 实战课
欧创新
人保资深架构师
55517 人已学习
新⼈⾸单¥59
登录后,你可以任选2讲全文学习
课程目录
已完结/共 26 讲
开篇词 (1讲)
DDD 实战课
15
15
1.0x
00:00/00:00
登录|注册

06 | 领域事件:解耦微服务的关键

思考题
总结
领域事件运行机制
领域事件总体架构
微服务之间的领域事件
微服务内的领域事件
领域事件的实现机制
领域事件的作用
识别领域事件
领域事件的定义
领域事件

该思维导图由 AI 生成,仅供参考

你好,我是欧创新。今天我们来聊一聊“领域事件(Domain Event)”。
在事件风暴(Event Storming)时,我们发现除了命令和操作等业务行为以外,还有一种非常重要的事件,这种事件发生后通常会导致进一步的业务操作,在 DDD 中这种事件被称为领域事件。
这只是最简单的定义,并不能让我们真正理解它。那到底什么是领域事件?领域事件的技术实现机制是怎样的?这一讲,我们就重点解决这两个大的问题。

领域事件

领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。一个领域事件将导致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环。
举例来说的话,领域事件可以是业务流程的一个步骤,比如投保业务缴费完成后,触发投保单转保单的动作;也可能是定时批处理过程中发生的事件,比如批处理生成季缴保费通知单,触发发送缴费邮件通知操作;或者一个事件发生后触发的后续动作,比如密码连续输错三次,触发锁定账户的动作。
那如何识别领域事件呢?
很简单,和刚才讲的定义是强关联的。在做用户旅程或者场景分析时,我们要捕捉业务、需求人员或领域专家口中的关键词:“如果发生……,则……”“当做完……的时候,请通知……”“发生……时,则……”等。在这些场景中,如果发生某种事件后,会触发进一步的操作,那么这个事件很可能就是领域事件。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

领域事件在微服务架构中扮演着重要角色,通过领域事件驱动设计可以实现业务解耦、数据一致性和微服务之间的解耦,从而提升系统性能和用户体验。文章介绍了领域事件的重要性以及在微服务内和微服务之间的处理方式。微服务内的事件集成通常发生在同一个进程内,而跨微服务的领域事件机制更为复杂,需要考虑事件构建、发布和订阅、事件数据持久化、消息中间件等方面的问题。通过一个保险承保业务过程的案例,展示了领域事件驱动设计在推动业务流程和数据在不同微服务之间流转的作用。最后,文章还介绍了领域事件的总体架构,包括事件构建和发布、事件数据持久化、事件总线、消息中间件等组件和技术的支撑。领域事件驱动机制可以实现一个发布方N个订阅方的模式,这在传统的直接服务调用设计中基本是不可能做到的。整体而言,领域事件驱动设计在分布式架构中得到了大量的使用,对于业务解耦、数据一致性和微服务之间的解耦具有重要意义。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《DDD 实战课》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(123)

  • 最新
  • 精选
  • 阿神
    微服务内的领域事件我建议少用,增加复杂性了

    作者回复: 我跟你的观点一样。

    2019-10-25
    22
    66
  • 兆哲
    在公司与同事沟通微服务之间的关系的时候,DDD提倡服务之间使用领域事件进行解耦, 但是某些同事觉得,rpc调用与通过总线发布事件,在执行的内容上没有本质上减少的东西(RPC 调用失败也可以加入重试机制),并且这种解耦方式可能会导致追踪调用链路更加困难。 如何看待这样的解读呢?

    作者回复: 在微服务设计时,微服务之间尽量通过领域事件的方式来解耦,耦合度过高,在一个微服务出现问题时容易导致整体出现雪崩现象。这种异步方式不仅可以解耦微服务,还可以起到削峰填谷的作用。所以非实时的调用尽量采用领域事件的方式。

    2020-01-31
    12
    29
  • 杨杰
    关于领域事件有几个问题: 1、如果采用了主流的消息队列(如rabbitmq,kafka,rocketmq),是否领域事件还需要持久化? 2、对于领域事件的内容,是否需要把所有变化(或绝大多数)的内容都保存到事件里面(比如保单里面的所有内容)?这样的话这个这个领域事件会不会比较大? 3、关于领域事件还有一种方案就是基于数据库cdc的方式,在系统中有大量领域事件的场景下,是否cdc的形式更加灵活一点?

    作者回复: 第一个问题:虽然这些消息队列自身有持久化的功能,但是中间过程,或者在订阅到数据后,在处理之前出问题,需要进行数据对账,这样就没法找到发布时和处理后的数据版本。关键的业务数据我建议还是落库比较好。 第二个问题:事件实体的业务数据还是按需发布比较好,避免不必要的业务信息泄露。 第三个问题:CDC的设计方式比较简单,属于数据库底层的技术,不会对上层应用产生太多的影响。

    2019-10-28
    11
    24
  • 游泳速度快内裤跟不上
    跨微服务的聚合间的领域事件驱动用消息中间件来衔接,这个比较容易理解,同一微服务内的聚合间的在实现层面如何来衔接呢,不太清楚这里面说的事件总线是一个什么概念,这个落实到代码上的话具体如何实现呢

    作者回复: 事件总线你可以理解为运行在同一个进程内的消息中间件,它是一个很小的技术组件,可以通过配置支持异步或同步的消息机制。具体实现你可以查阅一下Eventbus组件相关的资料。

    2019-10-25
    5
    15
  • 信了
    在领域事件运行机制相关案例中,投保微服务有两个领域服务,createPaymentNotice 和 createPaymentNoticeEvent,createPaymentNoticeEvent是为了创建缴费通知单事件,而createPaymentNotice是做什么的?

    作者回复: createPaymentNotice完成领域模型的业务逻辑:创建缴费通知单,createPaymentNoticeEvent是在领域逻辑完成后,执行领域事件发布逻辑:创建缴费通知单事件。在这个案例中,将业务逻辑处理和事件处理逻辑做了分离,然后在应用层来编排,这样的好处是可以实现事件发布逻辑的复用。如果不需要复用,你也可以直接在统一个领域服务中完成业务逻辑处理和领域事件发布逻辑,不需要上升到应用层来编排。

    2020-10-26
    3
    12
  • 昌南一枝花
    微服务内使用诸如SpringEvent同步方式保证在一个事务在修改多个聚合数据时,数据一致性得到了保证。但和前一讲提到的聚合设计原则跨聚合操作不应放在一个事务中,而应保证最终一致性略有矛盾。 是不是可以理解为Martinflow原本是想按聚合拆分微服务,所以跨聚合的操作不应放在一个事务里,否则没法按聚合拆分了。但实际应用中很少按聚合拆分微服务,为了方便也就允许跨聚合修改放一个本地事务里,后面万一要按聚合拆分微服务再拆分本地事务。

    作者回复: 这是因为聚合是微服务内最小的业务功能单元。为了保证聚合内数据更新时,符合聚合内固定的业务规则,在一次事务提交时通常会将聚合内所有变更的对象数据作为整体,通过聚合领域服务或聚合根方法一次通过仓储完成数据持久化操作。如果在一次交易中需要同时更新多个聚合数据,那么每一个聚合就是一个独立的数据提交单元,我们需要确保多个聚合数据都能在这个交易中提交更新成功,以保证不同聚合数据的一致性。 为什么要做聚合之间的解耦,这是因为微服务的架构演进基本是以聚合为单位来演进的,未来在业务演进时微服务可能会根据聚合功能来重新拆分和组合聚合,所以要提前做好聚合之间的解耦,如果聚合的解耦做的不好,微服务演进时重新拆分和组合的工作量会非常大。

    2020-08-04
    3
    9
  • cup
    老师,您好,有几个问题想请教一下 1、领域事件和一般的微服务之间的rpc调用区别是什么,因为大部分通信还是同步的rpc或者http调用,那每次rpc调用做一次更新操作就是一次领域事件么 2、大家都比较疑惑的问题 “微服务内应用服务,可以通过跨聚合的服务编排和组合,以服务调用的方式完成跨聚合的访问,这种方式通常应用于实时性和数据一致性要求高的场景。这个过程会用到分布式事务,以保证发布方和订阅方的数据同时更新成功。” 老师的答案是:微服务内主要是因为跨聚合了。一个聚合一个仓储,在一次修改多个聚合的时候,可能会存在数据不一致的情况,所以用事件总线或者分布式事务。 您这里说的一个聚合一个仓储是指的不同的聚合使用不同的数据库是么?普通数据库事务无法保证跨库操作的数据一致性,所以使用分布式事务?这样做是为了不同聚合之间解耦,方便以后的微服务拆分? 但如果简化一下,可不可以同一微服务中不同聚合的数据放在一个库里,在应用服务开启数据库事务,操作两个聚合的数据,然后结束事务 3、同一个微服务内为什么不能用消息中间件呢,比如一个聚合生产,扔到rabbitmq,同一微服务里面另一个聚合消费 消息保存到进程内部,如果消费能力较低,会不会内存溢出

    作者回复: 1、领域事件方式主要是采用异步方式,实现数据的最终一致性。 2、一个聚合一个仓储,是指一个聚合与数据库交互的仓储服务是一个,并不是指一个聚合一个数据库。因为在DDD中为了保证聚合内数据和业务规则的一致性,通过聚合根将所有的实体等数据作为一个整体持久化到数据库中,所以一次事务只能修改一个聚合的数据。而如果一个操作跨了多个聚合的话,就需要考虑事务的概念了,其中有两种实现方式:最终一致性的事件总线机制和Saga等分布式事务的方式。这样也是为了聚合之间的解耦。 3、在同一个微服务内采用消息中间件过重了,事件总线属于轻量级的可实现发布订阅基本功能。

    2020-01-06
    4
    7
  • zj
    spring提供的事件机制我感觉也可以啊,可以用在微服务内

    作者回复: 现在的技术路线很多,只要能保证在一个事务在修改多个聚合数据时,能保证数据一致性就可以使用。

    2019-11-21
    2
    7
  • 朱振光
    内容很充实,但还是有两个问题。 1. 在采取最终一致性的情况下,event消费端如果出现错误,消费失败,但是之前的业务都成功了,虽然记录了event dB,但是后续如何处理,是需要人工介入解决吗?如果人工介入再解决,前端用户会不会看到数据不一致,体验不好? 2. 因为event都是异步发送,当最后一个event消费成功后,如何有效的通知前端界面,是用Web Socket吗?还是需要前端轮询到后台看是否都成功

    作者回复: 第一个问题,失败的情况应该比例是很少的。失败的信息可以采用多次重发的方式,如果这个还解决不了,只能将有问题的数据放到一个问题数据区,人工解决。当然要确保一个前提,要保证数据的时序性,不能覆盖已经产生的数据。 第二个问题,一般来说发布方不会等待订阅方反馈结果。发布方有发布的事件表,订阅方有消费事件表,你可以采用每日对账的方式来发现问题数据。

    2019-10-25
    3
    7
  • 堵车
    我看到第一条留言,微服务领域时间建议少用,增加了复杂性。我有这么一个场景,用户入住一个房间后,要修改房态。如果不用领域事件,那么就得将入住和改房态写在同一个事务里。这里面入住是主操作,改房态是副操作。副操所除了问题,导致事务回滚,主操作也将无效,用户入住不成功。

    作者回复: 在微服务内,不是少用领域事件,是少用事件总线。在DDD中是以聚合为单位进行数据管理的,如果一次操作会修改同一个微服务内的多个聚合的数据,你就需要保证多个聚合的数据一致性,为了解耦不同聚合,你需要采用分布式事务或者用事件总线两种方式,用事件总线不太方便管理服务和数据的关系,你可以用类似saga之类的分布式事务技术。总之需要确保你的不同聚合的业务规则和数据一致性,尽量减少系统建设复杂度。

    2019-12-16
    7
    6
收起评论
显示
设置
留言
99+
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部