当前位置: 首页 > news >正文

05.领域驱动设计:认识领域事件,解耦微服务的关键

目录

1、概述

2、领域事件

2.1 如何识别领域事件

1.微服务内的领域事件

2.微服务之间的领域事件

3、领域事件总体架构

3.1 事件构建和发布

3.2 事件数据持久化

3.3 事件总线 (EventBus)

3.4 消息中间件

3.5 事件接收和处理

4、案例

5、总结


1、概述

在事件风暴(Event Storming)时,我们知道除了命令和操作等业务行为以外,还有一种非常重要

的事件,这种事件发生后通常会导致进一步的业务操作,在DDD中这种事件被称为领域事件

那到底什么是领域事件?领域事件的技术实现机制是怎样的?

2、领域事件

领域事件是领域模型中非常重要的一部分,用来表示领域中发生的事件。一个领域事件将导

致进一步的业务操作,在实现业务解耦的同时,还有助于形成完整的业务闭环

举例来说的话,领域事件可以是业务流程的一个步骤,比如投保业务缴费完成后,触发投保

单转保单的动作;也可能是定时批处理过程中发生的事件,比如批处理生成季缴保费通知

单,触发发送缴费邮件通知操作;或者一个事件发生后触发的后续动作,比如密码连续输错

三次,触发锁定账户的动作。

2.1 如何识别领域事件

在做用户旅程或者场景分析时,我们要捕捉业务、需求人员或领域专家口中的关键词:“如果发

生……,则……”“当做完……的时候,请通知……”“发生……时,则……”等。

在这些场景中,如果发生某种事件后,会触发进一步的操作,那么这个事件很可能就是领域事件

领域事件为什么要用最终一致性,而不是传统SOA的直接调用的方式呢?

聚合的一个设计原则:在边界之外使用最终一致性

一次事务最多只能更改一个聚合的状态。如果一次业务操作涉及多个聚合状态的更改,应采用领域

事件的最终一致性。

领域事件驱动设计可以切断领域模型之间的强依赖关系,事件发布完成后,发布方不必关心后续订

阅方事件处理是否成功,这样可以实现领域模型的解耦,维护领域模型的独立性和数据的一致性。

在领域模型映射到微服务系统架构时,领域事件可以解耦微服务,微服务之间的数据不必要求强一

致性,而是基于事件的最终一致性。

1.微服务内的领域事件

当领域事件发生在微服务内的聚合之间,领域事件发生后完成事件实体构建和事件数据持久化,

布方聚合将事件发布到事件总线,订阅方接收事件数据完成后续业务操作。

微服务内大部分事件的集成,都发生在同一个进程内,进程自身可以很好地控制事务,因此不一定

需要引入消息中间件。但一个事件如果同时更新多个聚合,按照DDD“一次事务只更新一个聚合”的

原则,你就要考虑是否引入事件总线。

微服务内应用服务,可以通过跨聚合的服务编排和组合,以服务调用的方式完成跨聚合的访问,这

种方式通常应用于实时性和数据一致性要求高的场景。这个过程会用到分布式事务,以保证发布方

和订阅方的数据同时更新成功。

2.微服务之间的领域事件

跨微服务的领域事件会在不同的限界上下文或领域模型之间实现业务协作,其主要目的是实现微服

务解耦,减轻微服务之间实时服务访问的压力。

跨微服务的事件机制要总体考虑事件构建、发布和订阅、事件数据持久化、消息中间件,甚至事件

数据持久化时还可能需要考虑引入分布式事务机制等。

微服务之间的访问也可以采用应用服务直接调用的方式,实现数据和服务的实时访问,弊端就是跨

微服务的数据同时变更需要引入分布式事务,以确保数据的一致性。分布式事务机制会影响系统性

能,增加微服务之间的耦合,所以我们还是要尽量避免使用分布式事务

总之,通过领域事件驱动的异步化机制,可以推动业务流程和数据在各个不同微服务之间的流转,

实现微服务的解耦,减轻微服务之间服务调用的压力,提升用户体验。

3、领域事件总体架构

领域事件的执行,需要一系列的组件和技术来支撑。领域事件处理包括:事件构建和发布、事件数

据持久化、事件总线、消息中间件、事件接收和处理等。

3.1 事件构建和发布

事件基本属性至少包括:事件唯一标识、发生时间、事件类型和事件源,其中事件唯一标识应该是

全局唯一的,以便事件能够无歧义地在多个限界上下文中传递。事件基本属性主要记录事件自身以

及事件发生背景的数据

另外事件中还有一项更重要,那就是业务属性,用于记录事件发生那一刻的业务数据,这些数据会

随事件传输到订阅方,以开展下一步的业务操作

事件基本属性和业务属性一起构成事件实体,事件实体依赖聚合根。领域事件发生后,事件中的业

务数据不再修改,因此业务数据可以以序列化值对象的形式保存,这种存储格式在消息中间件中也

比较容易解析和获取。

为了保证事件结构的统一,我们还会创建事件基类DomainEvent,子类可以扩充属性和方法。由

于事件没有太多的业务行为,实现方法一般比较简单。

事件发布之前需要先构建事件实体并持久化。事件发布的方式有很多种,你可以通过应用服务或者

领域服务发布到事件总线或者消息中间件,也可以从事件表中利用定时程序数据库日志捕获技术

获取增量事件数据,发布到消息中间件。

3.2 事件数据持久化

事件数据持久化可用于系统之间的数据对账,或者实现发布方和订阅方事件数据的审计。当遇到消

息中间件、订阅方系统宕机或者网络中断,在问题解决后仍可继续后续业务流转,保证数据的一致

性。

事件数据持久化有两种方案:

  • 持久化到本地业务数据库的事件表中,利用本地事务保证业务和事件数据的一致性。

  • 持久化到共享的事件数据库中

需要注意的是:业务数据库和事件数据库不在一个数据库中,它们的数据持久化操作会跨数据库,

因此需要分布式事务机制来保证业务和事件数据的强一致性,结果就是会对系统性能造成一定的影

3.3 事件总线 (EventBus)

事件总线是实现微服务内聚合之间领域事件的重要组件,它提供事件分发和接收等服务。

事件总线是进程内模型,它会在微服务内聚合之间遍历订阅者列表,采取同步或异步的模式传递数据。

事件分发流程大致如下:

  • 如果是微服务内的订阅者(其它聚合),则直接分发到指定订阅者;

  • 如果是微服务外的订阅者,将事件数据保存到事件库(表)并异步发送到消息中间件;

  • 如果同时存在微服务内和外订阅者,则先分发到内部订阅者,将事件消息保存到事件库(表),再异步发送到消息中间件。

3.4 消息中间件

跨微服务的领域事件大多会用到消息中间件,实现跨微服务的事件发布和订阅

消息中间件的产品非常成熟,市场上可选的技术也非常多,比如:Kafka,RabbitMQ等。

3.5 事件接收和处理

微服务订阅方在应用层采用监听机制,接收消息队列中的事件数据,完成事件数据的持久化后,就

可以开始进一步的业务处理。领域事件处理可在领域服务中实现。

4、案例

发生的领域事件是:缴费通知单已生成。下一步的业务操作是:缴费。

事件起点:出单员生成投保单,核保通过后,发起生成缴费通知单的操作。

  1. 投保微服务应用服务,调用聚合中的领域服务createPaymentNotice 和createPaymentNoticeEvent,分别创建缴费通知单、缴费通知单事件。其中缴费通知单事件类PaymentNoticeEvent继承基类DomainEvent。

  2. 利用仓储服务持久化缴费通知单相关的业务和事件数据。为了避免分布式事务,这些业务和事件数据都持久化。

  3. 到本地投保微服务数据库中。

  4. 通过数据库日志捕获技术或者定时程序,从数据库事件表中获取事件增量数据,发布到消息中间件。这里说明:事件发布也可以通过应用服务或者领域服务完成发布。

  5. 收款微服务在应用层从消息中间件订阅缴费通知单事件消息主题,监听并获取事件数据后,应用服务调用领域层的领域服务将事件数据持久化到本地数据库中。

  6. 收款微服务调用领域层的领域服务PayPremium,完成缴费。

  7. 事件结束。

提示:缴费完成后,后续流程的微服务还会产生很多新的领域事件,比如缴费已完成、保单已保存

等等。这些后续的事件处理基本上跟1~6的处理机制类似。

5、总结

今天我们主要学习领域事件以及领域事件的处理机制

领域事件驱动是很成熟的技术,在很多分布式架构中得到了大量的使用。领域事件是DDD的一个

重要概念,在设计时我们要重点关注领域事件,用领域事件来驱动业务的流转,尽量采用基于事件

的最终一致,降低微服务之间直接访问的压力,实现微服务之间的解耦,维护领域模型的独立性和

数据一致性。

除此之外,领域事件驱动机制可以实现一个发布方N个订阅方的模式,这在传统的直接服务调用设

计中基本是不可能做到的。

相关文章:

05.领域驱动设计:认识领域事件,解耦微服务的关键

目录 1、概述 2、领域事件 2.1 如何识别领域事件 1.微服务内的领域事件 2.微服务之间的领域事件 3、领域事件总体架构 3.1 事件构建和发布 3.2 事件数据持久化 3.3 事件总线 (EventBus) 3.4 消息中间件 3.5 事件接收和处理 4、案例 5、总结 1、概述 在事件风暴&a…...

「仙逆」王麻子结丹救下老婆,极识斩杀金丹修士,元婴期下第一人

Hello,小伙伴们,我是拾荒君。 国漫《仙逆》第21期超前爆料,据透露王麻子因急需天离丹来突破至金丹期,购买了被斗邪派预定的百兽灵炉,却遭其宗派追杀。虽然王麻子已触及结丹边缘,但面对五名邪派长老,他毫无…...

GoogleNet Inception v2 和 Inception v3详解

1 GoogleNet Inception v2 v1具体结构: v2具体结构: 1 引入Batch Normalization(BN): Inception v2在每个卷积层之后引入了BN。这有助于解决深层网络中的梯度消失问题,同时加快训练过程并提高模型的收敛速度。BN通过…...

在虚拟机上安装ubuntu

记得看目录哦! 软件自取1. 新建虚拟机2. Ubuntu的汉化 软件自取 链接:百度网盘自取哦!!! 提取码:8888 1. 新建虚拟机 文件–新建虚拟机 完成完会自动启动,等待一段时间,我等了一个…...

nav02 学习03 机器人传感器

机器人传感器 移动机器人配备了大量传感器,使它们能够看到和感知周围的环境。这些传感器获取的信息可用于构建和维护环境地图、在地图上定位机器人以及查看环境中的障碍物。这些任务对于能够安全有效地在动态环境中导航机器人至关重要。 机器人的传感器类似人的感官…...

Mysql-InnoDB-数据落盘

概念 1 什么是脏页? 对于数据库中页的修改操作,则首先修改在缓冲区中的页,缓冲区中的页与磁盘中的页数据不一致,所以称缓冲区中的页为脏页。 2 脏页什么时候写入磁盘? 脏页以一定的频率将脏页刷新到磁盘上。页从缓冲区…...

<el-date-picker>时间戳单位

神级操作&#xff0c;搞了半天&#xff0c;秒是大X&#xff0c;毫秒是小x&#xff0c;yue了。 // 秒 <el-date-pickerv-model"timestamp"value-format"X" ></el-date-picker>// 毫秒 <el-date-pickerv-model"timestamp"value-fo…...

如何搭建Nextcloud云存储网盘并实现无公网ip访问本地文件【内网穿透】

&#x1f49d;&#x1f49d;&#x1f49d;欢迎来到我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:kwan 的首页,持续学…...

力扣hot100 子集 回溯 超简洁

Problem: 78. 子集 文章目录 思路复杂度Code 思路 &#x1f468;‍&#x1f3eb; 参考题解 复杂度 时间复杂度: 添加时间复杂度, 示例&#xff1a; O ( n ) O(n) O(n) 空间复杂度: 添加空间复杂度, 示例&#xff1a; O ( n ) O(n) O(n) Code class Solution {List<Li…...

Linux系统Shell脚本编程之条件语句

一、条件测试 Shell 环境根据命令执行后的返回状态值 " $? " 来判断是否执行成功&#xff0c;当返回值为0时表示成功&#xff0c;否则表示失败或异常&#xff08;非0值&#xff09;。使用专门的测试工具 test 命令&#xff0c;可以对特定条件进行测试&#xff0c;并…...

Jmeter连接数据库报错Cannot load JDBC driver class‘com.mysql.jdbc.Driver’解决

问题产生: 我在用jmeter连接数据库查询我的接口是否添加数据成功时,结果树响应Cannot load JDBC driver class com.mysql.jdbc.Driver 产生原因: 1、连接数据库的用户密码等信息使用的变量我放在了下面,导致没有取到用户名密码IP等信息,导致连接失败 2、jmeter没有JDB…...

C# 获取计算机信息

目录 一、本机信息 1、本机名 2、获得本机MAC地址 3、获得计算机名 4、显示器分辨率 5、主显示器分辨率 6、系统路径 二、操作系统信息 1、操作系统类型 2、获得操作系统位数 3、获得操作系统版本 三、处理器信息 1 、处理器个数 四、CPU信息 1、CPU的个数 2、…...

第4章 python深度学习——(波斯美女)

第4章 机器学习基础 本章包括以下内容&#xff1a; 除分类和回归之外的机器学习形式 评估机器学习模型的规范流程 为深度学习准备数据 特征工程 解决过拟合 处理机器学习问题的通用工作流程 学完第 3 章的三个实例&#xff0c;你应该已经知道如何用神经网络解决分类问题和回归…...

[UI5 常用控件] 03.Icon, Avatar,Image

文章目录 前言1. Icon2. Avatar2.1 displayShape2.2 initials2.3 backgroundColor2.4 Size2.5 fallbackIcon2.6 badgeIcon2.7 badgeValueState2.8 active 3. Image 前言 本章节记录常用控件Title,Link,Label。 其路径分别是&#xff1a; sap.m.Iconsap.m.Avatarsap.m.Image 1…...

python爬虫demo——爬取历史平均房价

简单爬取历史房价 需求 爬取的网站汇聚数据的城市房价 https://fangjia.gotohui.com/ 功能 选择城市 https://fangjia.gotohui.com/fjdata-3 需要爬取年份的数据&#xff0c;等等 https://fangjia.gotohui.com/years/3/2018/ 使用bs4模块 使用bs4模块快速定义需要爬取的…...

力扣0100——相同的树

相同的树 难度&#xff1a;简单 题目描述 给你两棵二叉树的根节点 p 和 q &#xff0c;编写一个函数来检验这两棵树是否相同。 如果两个树在结构上相同&#xff0c;并且节点具有相同的值&#xff0c;则认为它们是相同的。 示例1 输入&#xff1a; p [1,2,3], q [1,2,3]…...

Vue-40、Vue中TodoList案例

1、MyHeader.vue <template><div class"todo-header"><input type"text" placeholder"请输入你的任务名称&#xff0c;按回车键确认" v-model"title" keyup.enter"add"></div> </template>&…...

dvwa靶场文件上传high

dvwa upload high 第一次尝试&#xff08;查看是否是前端验证&#xff09;第二次尝试我的上传思路最后发现是图片码上传修改配置文件尝试蚁&#x1f5e1;连接菜刀连接 第一次尝试&#xff08;查看是否是前端验证&#xff09; 因为我是初学者&#xff0c;所以无法从代码审计角度…...

​ PaddleHub 首页图像 - 文字识别chinese_ocr_db_crnn_server​

PaddleHub 便捷地获取PaddlePaddle生态下的预训练模型&#xff0c;完成模型的管理和一键预测。配合使用Fine-tune API&#xff0c;可以基于大规模预训练模型快速完成迁移学习&#xff0c;让预训练模型能更好地服务于用户特定场景的应用 零基础快速开始WindowsLinuxMac Paddle…...

如何在Win系统安装Jupyter Notbook并实现无公网ip远程访问本地笔记

文章目录 1.前言2.Jupyter Notebook的安装2.1 Jupyter Notebook下载安装2.2 Jupyter Notebook的配置2.3 Cpolar下载安装 3.Cpolar端口设置3.1 Cpolar云端设置3.2.Cpolar本地设置 4.公网访问测试5.结语 1.前言 在数据分析工作中&#xff0c;使用最多的无疑就是各种函数、图表、…...

腾讯云轻量应用Windows服务器如何搭建幻兽帕鲁Palworld私服?

幻兽帕鲁/Palworld是一款2024年Pocketpair开发的开放世界生存制作游戏&#xff0c;在帕鲁的世界&#xff0c;玩家可以选择与神奇的生物“帕鲁”一同享受悠闲的生活&#xff0c;也可以投身于与偷猎者进行生死搏斗的冒险。而帕鲁可以进行战斗、繁殖、协助玩家做农活&#xff0c;也…...

AR眼镜_ar智能眼镜显示方案|光学方案

AR眼镜是一种智能眼镜&#xff0c;能够将虚拟现实和现实世界相结合&#xff0c;使人们能够在日常生活中体验和参与虚拟现实。然而&#xff0c;AR智能眼镜的制造成本高&#xff0c;开发周期长。要实现AR眼镜的各项功能&#xff0c;需要良好的硬件条件&#xff0c;而AR智能眼镜的…...

C语言之猜凶手

一、题目 日本某地发生了一件谋杀案&#xff0c;警察通过排查确定杀人凶手必为4个嫌疑犯的一个。 以下为4个嫌疑犯的供词: A说&#xff1a;不是我。B说&#xff1a;是C。C说&#xff1a;是D。D说&#xff1a;C在胡说 已知3个人说了真话&#xff0c;1个人说的是假话。 现在…...

#Uniapp: uni.previewImage(OBJECT) 预览图片

uni.previewImage(OBJECT) 预览图片。 api地址 媒体-图片 示例 handlePreviewImg(current) {const urls this.rightList.map(x > x.icon)uni.previewImage({urls,current})}OBJECT 参数说明 参数名类型必填说明平台差异说明countNumber否最多可以选择的图片张数&#…...

SpringCloud-高级篇(十六)

前面学习了Lua的语法&#xff0c;就可以在nginx去做编程&#xff0c;去实现nginx类里面的业务&#xff0c;查询Redis&#xff0c;查询tomcat等 &#xff0c;业务逻辑的编写依赖于其他组件&#xff0c;这些组件会用到OpenResty的工具去实现 &#xff08;1&#xff09;安装OpenRe…...

【C++基础】C++内存处理机制面试题(以面促学 )

&#x1f308;欢迎来到C基础专栏 &#x1f64b;&#x1f3fe;‍♀️作者介绍&#xff1a;前PLA队员 目前是一名普通本科大三的软件工程专业学生 &#x1f30f;IP坐标&#xff1a;湖北武汉 &#x1f349; 目前技术栈&#xff1a;C/C、Linux系统编程、计算机网络、数据结构、Mysq…...

arcgis 批量删除字段

一、打开ArcToolbox-数据管理工具-字段-删除字段。 二、在输入表中选择要删除字段的要素&#xff0c;在删除字段栏中选择要删除的字段&#xff0c;点击确认即可。...

尚无忧球馆助教系统源码,助教小程序源码,助教源码,陪练系统源码

特色功能&#xff1a; 不同助教服务类型选择 助教申请&#xff0c;接单&#xff0c;陪练师入住&#xff0c;赚取外快 线下场馆入住 设置自己服务 城市代理 分销商入住 优惠券 技术栈&#xff1a;前端uniapp后端thinkphp 独立全开源...

Spring-集成Junit

一、引子 我们在Spring概念中提到&#xff1a;Spring的一大优势在于可以集成众多优秀的框架。毫无疑问&#xff0c;我首先向读者推荐的就是Junti框架。因为我们在前期的学习中&#xff0c;写一些小的demo&#xff0c;用Junit来进行小测试是非常合适的。下面让我们来具体看看如…...

DS:经典算法OJ题(1)

创作不易&#xff0c;友友们给个三连呗&#xff01;&#xff01; 本文为经典算法OJ题练习&#xff0c;大部分题型都有多种思路&#xff0c;每种思路的解法博主都试过了&#xff08;去网站那里验证&#xff09;是正确的&#xff0c;大家可以参考&#xff01;&#xff01; 一、移…...