《微服务架构设计模式》第六章 使用事件溯源开发业务逻辑

news2024/10/5 21:16:12

内容总结自《微服务架构设计模式》

使用事件溯源开发业务逻辑

    • 一、传统持久化技术的问题
    • 二、什么是事件溯源
    • 三、好处和弊端
    • 四、实现事件存储库
    • 五、与Saga结合
    • 六、总结



一、传统持久化技术的问题

1、对象与关系的"阻抗失调"

所谓的对象与关系的“阻抗失调”是一个古老的问题。关系型数据的表格结构模式,与领域模型及其复杂关系的图状结构之间,存在基本的概念不匹配问题。

2、缺乏聚合的历史

传统持久化的另一个限制是它只存储聚合的当前状态.聚合更新后,其先前的状态将丢失。如果应用程序必须保留聚合的历史记录(可能是出于监管目的),那么开发人员必须自己实现此机制.实现聚合历史记录机制是非常耗时的一项工作,其中还会涉及复制那些必须与业务逻辑保持同步的代码。

3、实施审计功能将非常烦琐且容易出错

另一个问题是审计功能。许多应用程序必须维护审计日志,用于跟踪哪些用户更改了聚合。某些应用程序需要审计功能,以满足安全性或监管的要求。在一些应用程序中,记录用户操作历史是一个重要的功能。

4、事件发布是凌驾于业务逻辑之上

传统持久化的另一个限制是它通常不支持发布领域事件。领域事件在状态发生变化的时候,是在微服务架构中同步数据和发送通知的有效机制。某些ORM框架(如Hibernate)可以在数据对象更改时调用应用程序提供的回调接口。但是,我们无法把自动发布消息作为更新数据事务的一部分。因此,与操作历史和审计一样,开发人员必须自己处理事件生成的逻辑,这可能会与业务逻辑代码不完全同步。幸运的是,这些问题有一个解决方案:事件溯源




二、什么是事件溯源

事件溯源是一种以事件为中心的技术,用于实现业务逻辑和聚合的持久化。聚合作为一系列事件存储在数据库中。每个事件代表聚合的状态变化。聚合的业务逻辑围绕生成和使用这些事件的要求而构建。


1、事件溯源通过事件来持久化聚合

将聚合的字段映射到数据库表的列,将聚合的实例映射到数据库表的行。事件溯源采用基于领域事件的概念来实现聚合的持久化,这是一种非同寻常的方法。它将每个聚合持久化为数据库中的一系列事件,我们称之为事件存储。
请添加图片描述


2、事件代表状态的改变

使用事件溯源时,事件不再是可有可无的。包括创建在内的每一个聚合状态变化,都由领域事件表示。每当聚合的状态发生变化时,它必须发出一个事件。这是一个比以前更严格的要求,在此之前,聚合只需要发出那些外部接收方感兴趣的事件


3、聚合方法都和事件相关

业务逻辑通过调用聚合根上的命令方法 ( command method)来处理对聚合的更新请求。在传统的应用程序中,命令方法通常会验证其参数,然后更新一个或多个聚合字段。基于事件溯源的应用程序中的命令方法则通过生成事件来起作用。调用聚合命令方法的结果是一系列事件,表示必须进行的状态更改。这些事件将保存在数据库中,并应用于聚合以更新其状态。


4、使用事件溯源的注意事项

  1. 使用乐观锁处理并发:可以使用乐观锁解决并发问题;
  2. 使用轮训发布事件:可以增加事件是否执行列,发布事件时根据event_id和是否执行列共同决定下次执行的事件;
  3. 使用快照提升性能:可以使用JSON序列化聚合的状态,达到快照效果;
  4. 消息需要进行幂等处理(业务层面处理、框架层面处理):消息通病都需要进行幂等处理。业务层面就是在业务逻辑层面先查询,再处理。框架层面则为新增一个消息记录映射,每次接收到消息都进行消息重复判定,判定为重复的消息,直接在框架层面过滤,不再透出给业务接口。





三、好处和弊端

事件溯源好处(就是传统持久化技术的问题):

  1. 可靠地发布领域事件。
  2. 保留聚合的历史。
  3. 最大限度地避免对象与关系的"阻抗失调"问题。
  4. 为开发者提供一个“时光机”

弊端:

  1. 这类编程模式有一定的学习曲线。
  2. 基于消息传递的应用程序的复杂性。处理事件的演化有一定难度。
  3. 删除数据存在一定难度。
  4. 查询事件存储库非常有挑战性。




四、实现事件存储库

1、一种选择是实现自己的事件存储库和事件溯源代码框架。例如,你可以在关系型数据库中执行事件。可以让订阅者轮询EVENT表的方式发布事件,这种发布事件的方法简单但性能低下。其挑战是确保订阅者按顺序处理所有事件;

2、另一种选择是使用专用事件存储库,它通常提供丰富的功能集、更好的性能和可扩展性。如Event Store、Lagom、Axon、Eventuate等


Eventuate Local的事件数据库的结构,主要由三个表组成,具体如下图:

请添加图片描述

Eventuate Local的事件中继把事件从数据库传播到消息代理,事件中继将插入事件数据库的事件传播到事件代理。它尽可能使用事务日志拖尾,或轮询其他数据库。例如,MySQL 版本的事件中继使用MySQL主/从复制协议。事件中继连接到MySQL服务器,就好像它是一个从服务器,通过读取MySQL binlog对数据库进行同步更新。对EVENTS表的插入操作,将作为对应事件发布到相应的Apache Kafka主题。事件中继忽略任何其他类型的更改。

事件中继部署为独立进程。为了正确地重新启动,它会定期将当前在binlog 的位置(文件名和偏移量)保存到一个特殊的Apache Kafka主题中。在启动时,它首先从主题中检索最后记录的位置。事件中继然后开始从该位置读取MySQL的 binlog。

事件数据库、消息代理和事件中继这三个部分构成了事件存储库。




五、与Saga结合

事件溯源的事件驱动属性使得实现基于协同式的Saga非常简单。当聚合被更新时,它会发出一个事件。不同聚合的事件处理程序可以接收该事件,并更新该聚合。事件溯源框架自动使每个事件处理程序具有幂等性。

使用事件进行Saga协同的问题在于,在这样的场景下,事件体现出了双重目的。事件溯源使用事件来表示状态更改,但是使用事件实现Saga协同,需要聚合即使没有状态更改也必须发出事件。例如,如果更新聚合会违反业务规则,则聚合必须发出事件以报告错误。更糟糕的问题是当Saga参与方无法创建聚合时。没有会发布错误事件的聚合。

由于存在这些问题,最好使用编排式来实现复杂的Saga。




六、总结

  1. 事件溯源将聚合作为一系列事件持久化保存。每个事件代表聚合的创建或状态更改。应用程序通过重放事件来重建聚合的当前状态。事件溯源保留领域对象的历史记录,提供准确的审计日志,并可靠地发布领域事件。
  2. 快照通过减少必须重放的事件数来提高性能。
  3. 事件存储在事件存储库中,该存储库是数据库和消息代理的混合。当服务在事件存储库中保存事件时,它会将事件传递给订阅者。
  4. Eventuate Local是一个基于MySQL和Apache Kafka的开源事件存储库。开发人员使用Eventuate Client框架来编写聚合和事件处理程序。
  5. 使用事件溯源的一个挑战是处理事件的演变。应用程序在重放事件时可能必须处理多个事件版本。一个好的解决方案是使用向上转换,当事件从事件存储库加载时,它会将事件升级到最新版本。
  6. 在事件溯源应用程序中删除数据非常棘手。应用程序必须使用加密和假名等技术,以遵守欧盟GDPR等法规,确保在应用程序中彻底清除个人数据。
  7. 事件溯源可以很容易实现基于协同的Saga。服务具有事件处理程序,用于监听基于事件溯源的聚合发布的事件。
  8. 我们也可以使用事件溯源技术实现Saga编排器。你可以编写专门使用事件存储库的应用程序。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/743182.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

ThreadLocal与InheritableThreadLocal及线程池的影响

在web开发中使用了ThreadLocal本地线程存储拦截器解析的用户信息,方便在下文代码中调用,但是在springboot中使用Async开启异步操作时,就会造成,子线程无法拿到父本地线程数据。拿到一些脏数据。 1.InheritableThreadLocal 在这个…

常用技巧总结

本文总结了本人在日常工作学习中遇到的问题及其解决方法,没有固定的涉及领域 目的就是为了在下一次遇到类似问题的时候方便查找,从而快速解决问题 本文不定时更新~ 目录 Windows使用 如何实现桌面图标随意排列 文件资源管理器相关 显示隐藏文件 修改…

深度学习06-深度卷积生成对抗网络(DCGAN)

文章目录 概述原理简介专业术语零填充转置卷积 生成动漫图像算力选择数据集目录规划源代码数据源加载定义配置类定义模型 训练可视化绘制损失绘制生成器图像变化 其他项目CycleGANstargan 概述 GAN(Generative Adversarial Network)是一种生成模型&…

flutter开发实战-日志logger写入文件及print

flutter开发实战-日志logger写入文件及print 在开发中,需要日志logger写入文件,方便日后查看出现的问题。这里记录之前的实现方案。 使用的日志插件是logger 一、引入日志插件 在工程中pubspec.yaml引入logger logger: ^1.4.0二、代码实现 使用比较…

听GPT 讲K8s源代码--pkg(一)

在 Kubernetes 代码仓库中,pkg/api和pkg/apis目录都包含用于定义 Kubernetes API 对象的代码,但它们的作用略有不同。 pkg/api目录包含 Kubernetes 的旧版本 API 对象定义,这些定义在 Kubernetes 1.7 版本之前使用。这些对象定义已经过时&…

第四课:Figma 图标设计

图形绘制小技巧 绘制正圆 O shift 正方体 R shift,右侧属性面板可调整描边显示方向,描边类型; 直线 L shift 带角度的箭头 shift L ,按住 shift 键调整以 45 度角调整箭头方向,右侧属性面板可调节箭头方向和线条…

文献里的分子对接方法2

珍珠贝肉水解物中的新型抗氧化肽以及它们的抗氧化活性机制。 关于摘要: 自由基和衰老以及很多疾病都有关联。 抗氧化肽具有良好的抗氧化活性和吸收性,是抗氧化剂研究的热点之一。 这篇文献的研究中,纯化珍珠贝肉水解液、经过蛋白质组学鉴定…

大模型与端到端会成为城市自动驾驶新范式吗?

摘要: 最近可以明显看到或者感受到第一梯队的城市自动驾驶量产已经进入快车道,他们背后所依靠的正是当下最热的大模型和端到端的技术。 近期,城市自动驾驶量产在产品和技术上都出现了新的变化。 在产品层面,出现了记性行车或者称…

【python】逻辑中断(and or)

今天学习javascript的时候竟然有一个额外收获:逻辑中断。而且我实验了一下,逻辑中断同样适用于python。 0 and 2返回: 0 1 and 2返回: 2 0 and 2返回的是0,而1 and 2返回的是2。就是因为在0那里出现了逻辑中断。 解…

Git的使用以及在IDEA2022中使用Git

目录 前言 一、Git下载与安装 二、Git常用命令 1.全局设置 2.获取Git仓库-在本地初始化Git仓库 3.获取Git 仓库-从远程仓库克隆 4.Git工作区、暂存区、版本库 概念以及工作区中文件状态 (1)工作区、暂存区、版本库 (2) G…

centos7.9 rc.local启动失败

最近在虚拟机上整个centos7.9,想要把程序设置成开机自启动,发现rc.local状态是failed,重启服务器也没用。 自己之前写过两篇相关的博客 centos7重启后/etc/rc.local中的脚本没有执行_lanren312的博客-CSDN博客 centos7开机运行java的sh脚本…

Sui 8192:如何使用Sui对象撼动游戏领域

Ethos通过其Sui 8192游戏不仅展示了对象在Sui上的力量,还展示了基于对象的游戏如何有力地撼动游戏行业。每个玩家在移动游戏中的方块时都会铸造一个新的对象,类似于铸造NFT,这为每个独立玩过的游戏提供了永久上链的机会。 Sui 8192游戏的规则…

10.4.4 终端机的环境设置: stty, set

在 tty1 ~ tty6 这六个命令行的终端机(terminal) 环境中登陆,登陆的时候我们可以取得一些字符设置的功能。举例来说,我们可以利用倒退键 (backspace,就是那个←符号的按键) 来删除命令列上的字符…

强化学习模型

目录 引言 1 强化学习的理论基础 2 强化学习的实践 3实战案例:自动驾驶

【InnoDB 存储引擎】InnoDB 数据页格式(详细版,数据页格式对于理解索引详细的原理很重要)

文章目录 1 InnoDB 数据页结构1.1 File Header2.2 Page Header2.3 Infimum 和 Supremum Record2.4 User Record 和 Free Space2.5 Page Directory(InnoDB 数据页结构最重要的部分)2.6 File Trailer 2 参考资料 1 InnoDB 数据页结构 我们已经知道页是 In…

PS 2023 24.7 Beta Ai 如何解决橙色错误弹窗问题?

距离Adobe软件公司首次将图像编辑及数字绘画软件Photoshop推出到大众面前已经过去35年,最近该公司又再次书写了属于Photoshop的历史新篇章。 Adobe 发布的 Photoshop(Beta)新增「创意填充(Generative Fill)」功能&…

jmter连接mysql数据库取值

测试情况下需要大量的测试数据进行模拟测试,如何使用接口插入大量数据,使用jmter进行插入 步骤如下: 第一步:\lib\ext导入mysql-connector-java-5.1.44-bin.jar驱动 F:\TOOLS\apache-jmeter-5.4.1\apache-jmeter-5.4.1\lib\ext …

Vue的入门学习

Vue 1 Vue概述 通过我们学习的htmlcssjs已经能够开发美观的页面了,但是开发的效率还有待提高,那么如何提高呢?我们先来分析下页面的组成。一个完整的html页面包括了视图和数据,数据是通过请求 从后台获取的,那么意味…

SpringBoot中集成阿里开源缓存访问框架JetCache实现声明式实例和方法缓存

场景 SpringBoot中通过自定义缓存注解(AOP切面拦截)实现数据库数据缓存到Redis: SpringBoot中通过自定义缓存注解(AOP切面拦截)实现数据库数据缓存到Redis_霸道流氓气质的博客-CSDN博客 上面讲的通过自定义注解的方式实现查询数据库数据缓存,除此之外…

数据结构--哈夫曼树

数据结构–哈夫曼树 带权路径长度 结点的 权 \color{red}权 权:有某种现实含义的数值(如:表示结点的重要性等) 结点的带权路径长度 \color{red}结点的带权路径长度 结点的带权路径长度:从树的根到该结点的路径长度(经过的边数)与该结点上权值的乘积 树的…