如何正确理解事件溯源架构模式?
在微服务架构盛行的当下,DDD(领域驱动设计)也得到了崭新的发展。同时,随着DDD的不断发展,也诞生了一些新的设计思想和开发模式,今天要介绍的事件溯源是其中具有代表性的一种模式。
事件溯源模式是DDD领域中一种新的架构模式,专门用来处理应用程序中的状态变化。事件溯源模式的实现方式与传统的应用程序开发方法有很大不同,表现在对应用程序状态的存储和检索过程。
事件溯源模式设计理念
在对事件溯源进行详细展开之前,我们先来回顾一下传统应用程序中关于“状态”的维护方法。让我们先从一个典型的应用场景开发说起,在日常开发过程中,开发人员经常需要处理与用户相关的操作,例如用户的创建、密码修改、地址更新、权限变更等。
在这个场景中,代表用户概念的User就是核心的领域对象。那么,基于该领域对象,你会怎么处理对应的业务操作呢?
域溯源模式
在传统应用程序中,我们使用常见的数据库(如关系数据库、NoSQL数据库)来创建、修改或查询业务领域对象的状态。另一方面,我们通过把这些状态持久化到一定的数据存储媒介之后,也可以通过领域事件的形式把事件发布到消息中间件。基于以上分析,我们认为这种状态变化的过程是领域对象来驱动的,也就是说只有领域对象主动更新自己的状态并生成领域事件,我们才能获取到应用程序状态的变化。
反过来讲,如果领域对象没有主动更新数据或生成任何领域事件,那么我们也就无法感知到应用程序的状态已经发生了变化。从状态的源头(Source)来讲,我们认为这种处理方式是一种域溯源(Domain Sourcing)的方式。
基于域溯源模式,我们在对领域对象执行一定操作之后会把对象的最新状态持久化到数据库中,也就是说数据库中的数据反映了对象当前最新的状态。
从上图中,我们可以看到针对用户状态更新的各个操作,在数据库中只会存在一条数据记录,反应了该用户的当前的最新信息。至于各个操作的具体执行过程,通常可能会设计一张操作日志表。
显然,域溯源的实现过程比较简单,也符合开发人员的直观认知,因为它们使用了存储和查询应用程序状态的传统实现方案。只要能够正确保存领域对象,我们就能获取应用程序最新的状态信息。
事件溯源模式
接下来,我们要引入的事件溯源机制则采用了另一种设计理念。与域溯源模式不同,事件溯源模式只关注于处理领域对象上发生的领域事件。也就是说,事件溯源模式不是保存对象的最新状态,而是保存这个对象所经历的每个事件,所有由对象产生的事件会按照时间先后顺序有序的存放在数据库中。
当我们需要这个对象的最新状态时,只要先创建一个空的对象,然后把和该对象相关的所有事件按照发生的先后顺序从先到后全部执行一遍。这个过程就是事件溯源,如下图所示。
从上图中可以看到,事件溯源的核心设计思想在于:不保存对象的最新状态,而是保存导致对象状态发生变化的所有事件,这样就可以通过对这些事件进行溯源得到对象的最新状态。
显然,基于事件溯源的设计思想,一个事件就是表示一个事实,事实是不能被磨灭或修改的,所以事件本身是不可修改的(Immutable),我们只能执行新增和查询操作。而对比域溯源模式和事件溯源模式,我们不难发现有两个差异点。
以上两点构成了事件溯源模式的能够得以实施的前置条件。当我们把应用程序的状态变更全部进行持久化之后,接下来我们就可以真正实现所谓的溯源操作了。
实现事件溯源模式
理解了事件溯源的基本概念之后,接下来我们讨论具体的实现过程。
事件存储
实现事件溯源的第一步是确保领域事件都得到持久化。在事件溯源模式中,存储事件的组件被称为事件存储器(Event Store)。下图展示了采用事件溯源机制下各组件的交互示意图。
结合上图,我们来举一个具体的示例。如果我们正在设计一个典型的用户应用程序,那么基于上图中的交互过程,在用户更新密码时,就会生成一个PasswordUpdatedEvent这样一个领域事件。我们只需要对这个领域事件进行持久化,而不需要保存User这个领域对象。PasswordUpdatedEvent事件将被持久化到一个专门构建的事件存储器UserEventStore中。
事件回放
接下来,假设需要获取用户应用程序中User这个领域对象的最新状态,那么基于事件溯源机制,我们将采用一种比较特殊的实现方式。首先,我们会从事件存储器中加载User对象上已经发生的所有领域事件。然后,我们在User对象上依次执行所有领域事件所包含的状态变化信息,从而确保User对象达到当前的最新状态。整个执行过程如下图所示。
有时候,我们把在User对象上重新执行领域事件的这个过程成称为事件回放(Event Replay)。可以看到,基于事件溯源机制,我们采用的是一种纯事件驱动的实现方法。
整合DDD和事件溯源
在DDD中,我们把某一个独立的业务模块划分成一个限界上下文。在每个限界上下文中势必会存在聚合对象。生成领域事件的一般就是这些聚合对象,而聚合的创建常见是在应用服务中。因此,DDD和事件溯源机制的整合效果如下图所示。
另一方面,领域事件一般都具有传播性,如果我们想要把领域事件传播出去,那么可以引入一个事件路由器来实现这一目标。
结合前面介绍的案例场景,那么User就是聚合对象,而我们可以把对应的事件路由器命名为UserEventRouter。PasswordUpdatedEvent这个领域事件被我们发送到事先已经设计好的消息路由通道,从而供其他限界上下文中的事件处理器进行消费。这个过程中,领域事件是否被持久化实际上是没有任何约束的。
在应用程序开发过程中,我们通常使用关系型数据库来维护业务对象的最新状态。这是一种比较传统的实现方案,但如果我们想要进一步明确该业务对象所执行的各种操作,问题就变得没有那么简单。而今天介绍的事件溯源机制为我们提供了另一种完全不同的实现思路。在事件溯源机制中,我们保存的不是数据状态本身,而是引起这些状态发生的各种事件。通过在业务对象上依次执行这些事件,我们就能够获取该业务对象所经历的各种操作过程和结果。在日常开发过程中,针对如何实现事件溯源,我们需要考虑事件的存储、事件的回放等技术组件,同时也需要考虑DDD和事件溯源的整合过程,因为时间溯源的主要应用方式就是在DDD应用程序中。
相关文章:

如何正确理解事件溯源架构模式?
在微服务架构盛行的当下,DDD(领域驱动设计)也得到了崭新的发展。同时,随着DDD的不断发展,也诞生了一些新的设计思想和开发模式,今天要介绍的事件溯源是其中具有代表性的一种模式。 事件溯源模式是DDD领域中…...

【漏洞复现】电信网关配置管理系统 rewrite.php 文件上传漏洞
0x01 产品简介 中国电信集团有限公司(英文名称"China Telecom”、简称“"中国电信”)成立于2000年9月,是中国特大型国有通信企业、上海世博会全球合作伙伴。电信网关配置管理系统是一个用于管理和配置电信网络中网关设备的软件系统。它可以帮助网络管理员…...

线性调整率:LINE REGULATION详解
目录 一、概述 二、 举例 一、概述 LDO(低压差线性稳压器)的LINE REGULATION(线路调整或线性调整)参数是一个衡量稳压器输出稳定性的重要指标。它反映了LDO输出电压对输入电压变化的响应程度。 当输入电压在其规定的工作范围内变…...

Workfine默认首页功能详解
一、基本介绍 Workfine V6.3推出了默认的用户首页功能,这样用户在登入系统后就可以通过默认的首页栏进行一些业务操作。第一版的用户首页功能布局了审批,制单,业务导航,便捷入口,消息和预警六大块内容,后续…...

CSAPP Lab07——Malloc Lab完成思路
等不到天黑 烟火不会太完美 回忆烧成灰 还是等不到结尾 ——她说 完整代码见:CSAPP/malloclab-handout at main SnowLegend-star/CSAPP (github.com) Malloc Lab 按照惯例,我先是上来就把mm.c编译了一番,结果产生如下报错。搜索过后看样子应…...

简单、免费、无广告的高性能多线程文件下载工具
一、简介 1、它是一款免费、无广告的高性能多线程文件下载工具。它界面简洁,简单好用,压缩包大小仅有 0.7MB,目前仅支持 Windows 平台。 2、使用方法:点击程序左上角的【】按钮,将需要的链接输入进去后点击【下载】即…...

【退役之重学 SQL】什么是笛卡尔积
一、初识笛卡尔积 概念: 笛卡尔积是指在关系型数据库中,两个表进行 join 操作时,没有指定任何条件,导致生成的结果集,是两个表中所有行的组合。 简单来说: 笛卡尔积是两个表的乘积,结果集中的每…...

Vue3禁止 H5 界面放大与缩小功能
Vue3禁止 H5 界面放大与缩小功能 一、前言1.第一步2.第二部3.总结 一、前言 当涉及到禁止 H5 界面的放大与缩小功能时,Vue 3 提供了一种方便的方式来处理。我们可以使用 <script setup> 语法,将相关代码添加到 App.vue 组件中,以确保在…...

上位机图像处理和嵌入式模块部署(f407 mcu中tf卡读写和fatfs挂载)
【 声明:版权所有,欢迎转载,请勿用于商业用途。 联系信箱:feixiaoxing 163.com】 很早之前,个人对tf卡并不是很重视,觉得它就是一个存储工具而已。后来在移植v3s芯片的时候,才发现很多的soc其实…...

汽车识别项目
窗口设计 这里的代码放在py文件最前面或者最后面都无所谓 # 创建主窗口 window tk.Tk() window.title("图像目标检测系统") window.geometry(1000x650) # 设置窗口大小# 创建背景画布并使用grid布局管理器 canvas_background tk.Canvas(window, width1000, height…...

【面试题-012】什么是Spring 它有哪些优势
文章目录 Spring有哪些优势有哪些优势Spring和Springboot区别在 Spring 框架中,什么是AOP核心概念应用场景 Spring有哪些通知类型 Spring 是一个开源的 Java 平台,由 Rod Johnson 创建,用于简化企业级 Java 应用程序的开发。它于 2003 年首次…...

ImageButton src图片会照成内存泄露吗 会使native内存增加吗?
在Android开发中,ImageButton 是用来显示按钮的视图组件,它通常用于显示图标或图片。对于ImageButton使用的src属性(即按钮上的图片)通常不会导致内存泄漏,但是有几种情况可能会导致内存问题: 1. **不正确…...

负载均衡与容错性:集群模式在分布式系统中的应用
本文作者:小米,一个热爱技术分享的29岁程序员。如果你喜欢我的文章,欢迎关注我的微信公众号“软件求生”,获取更多技术干货! 大家好,我是小米,一个热爱分享技术的29岁程序员。今天我们来聊一聊分布式系统中的一个重要概念:集群(Cluster)模式。相信很多朋友在日常开发…...

【UE5.1 角色练习】09-物体抬升、抛出技能 - part1
前言 在上一篇(【UE5.1 角色练习】08-传送技能)的基础上继续实现控制物体抬升、抛出的功能。 效果 步骤 一、准备技能动画 1. 在项目设置中新建一个操作映射,这里命名为“Skill_GravityControl”,用按键4触发 2. 通过IK重定向…...

最大的游戏交流社区Steam服务器意外宕机 玩家服务受影响
易采游戏网6月3日消息:众多Steam游戏玩家报告称,他们无法访问Steam平台上的个人资料、好友列表和社区市场等服务。同时,社区的讨论功能也无法正常使用。经过第三方网站SteamDB的确认,,这一现象是由于Steam社区服务器突…...

如何手动批准内核扩展 Tuxera NTFS for mac内核扩展需要批准 内核扩展怎么打开
在了解如何手动批准内核扩展之前,我们应该先了解什么叫做内核扩展。内核扩展又被称为KEXT,通过它可以实现macOS系统与软件组件之间的交互,例如磁盘管理、任务管理和内存管理等等。 kext 是内核扩展(Kernel Extension)…...

ffmpeg常用命令
推流 ffmpeg -re -stream_loop -1 -i in.flv -c copy -f flv outurl 推流追加时间戳 ffmpeg -stream_loop -1 -re -i move.flv -vf "settbAVTB,setptstrunc(PTS/1K)*1Kst(1,trunc(RTCTIME/1K))-1K*trunc(ld(1)/1K),drawtextfontfilearial.ttf:text%{localtime}.%{eif\:…...

在MongoDB中,您可以通过以下步骤来创建账号密码,并限制其在特定数据库上的访问权限
在MongoDB中,您可以通过以下步骤来创建账号密码,并限制其在特定数据库上的访问权限: 连接到MongoDB数据库: 使用MongoDB的客户端(如mongo shell或者MongoDB Compass)连接到MongoDB服务器。 切换到admin数…...

前端JS必用工具【js-tool-big-box】学习,检测密码强度
js-tool-big-box 前端工具库,实用的公共方法越来越多了,这一小节,我们带来的是检测密码强度。 我们在日常开发中,为了便于测试,自己总是想一个简单的密码,赶紧输入。但到了正式环境,我们都应该…...

PHP精度处理
一、问题缘由 PHP 服务接收前端传过来的单价(字符串形式)和数量,把单价转成分(单价*100),然后传给下游的 Golang 服务,不过最后从两个服务日志中发现金额相差 1。 以下为前端传的 {"amount": 4,"price": "9.2&qu…...

618电商大战开启!2024淘宝京东618满减规则与优惠力度大比拼
2024年淘宝和京东的618电商大战即将打响。作为一年一度的购物狂欢节日,今年618的满减规则和优惠力度再次成为消费者关注的焦点。在这场激烈的电商角逐中,究竟哪家平台能更胜一筹?让我们一起来揭晓答案! 淘宝京东满减规则大揭秘 淘…...

【全开源】种草分享|动态朋友圈|瀑布流|uniapp
一款基于FastadminThinkPHP和Uniapp开发的种草分享评论点赞消息提醒系统,发布动态,分享种草生活,可以收藏关注点赞,消息提醒,同时支持H5/小程序/app多端。 让每一次互动都不再错过🔔 🌱 种草…...

HDTune和CrystalDiskInfo硬盘检测S.M.A.R.T.参数当前值最差值阈值
高亮颜色说明:突出重点 个人觉得,:待核准个人观点是否有误 高亮颜色超链接 文章目录 S.M.A.R.T.监控技术磁盘健康状态监测,硬盘检测硬盘检测工具 HD Tune硬盘检测工具 CrystalDiskInfo 当前值最差值阈值原始值的含义二级标题待补充待补充 开头…...

Homebrew、RVM、ruby、cocoapods
安装Homebrewe 方式1:公司源安装 方式2:国内源安装 /bin/ssh -c “$(curl -fsSL https://gitee.com/cunkai/HomebrewCN/raw/master/Homebrev.sh)” 方式3:官网源安装(有可能443): ruby -e “$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install)…...

Flutter 中的 SliverConstrainedCrossAxis 小部件:全面指南
Flutter 中的 SliverConstrainedCrossAxis 小部件:全面指南 Flutter 是一个功能强大的 UI 框架,由 Google 开发,允许开发者使用 Dart 语言来构建高性能、美观的跨平台应用。在 Flutter 的丰富组件库中,SliverConstrainedCrossAxi…...

Vue.js:渐进式JavaScript框架-前端开发
1.介绍-What is Vue? An approachable, performant and versatile framework for building web user interfaces. [一个平易近人、高性能和多功能的框架,用于构建 Web 用户界面。] --来自官网Vue.js - The Progressive JavaScript Framework | Vue.js (vuejs.org) …...

代码随想录算法训练营Day55 | 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇
代码随想录算法训练营Day55 | 583. 两个字符串的删除操作 72. 编辑距离 编辑距离总结篇 LeetCode 583. 两个字符串的删除操作 题目链接:LeetCode 583. 两个字符串的删除操作 思路: 分别删除 class Solution { public:int minDistance(string word1, …...

【Python网络爬虫】详解python爬虫中正则表达式、BeautifulSoup和lxml数据解析
🔗 运行环境:PYTHON 🚩 撰写作者:左手の明天 🥇 精选专栏:《python》 🔥 推荐专栏:《算法研究》 #### 防伪水印——左手の明天 #### 💗 大家好🤗ᾑ…...

树莓派串口无法使用(排除硬件错误后)
1、串口 进入/boot文件夹下,打开cmdline.txt文件 cd /boot/sudo vi cmdline.txt 删除下方红框内字段...

JavaEE IO流(1)
1.什么是IO流 (1)input输入 Output输出 这两个的首字母就是IO的组成 (2)比如你的电脑可以通过网络上传文件和下载文件 这个上传文件就是Output 这个下载翁建就是input (3)这个输入和输出的标准是以CPU为参照物为基准的 其中通…...