如何正确理解事件溯源架构模式?
在微服务架构盛行的当下,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…...
后进先出(LIFO)详解
LIFO 是 Last In, First Out 的缩写,中文译为后进先出。这是一种数据结构的工作原则,类似于一摞盘子或一叠书本: 最后放进去的元素最先出来 -想象往筒状容器里放盘子: (1)你放进的最后一个盘子(…...
OpenLayers 可视化之热力图
注:当前使用的是 ol 5.3.0 版本,天地图使用的key请到天地图官网申请,并替换为自己的key 热力图(Heatmap)又叫热点图,是一种通过特殊高亮显示事物密度分布、变化趋势的数据可视化技术。采用颜色的深浅来显示…...
反向工程与模型迁移:打造未来商品详情API的可持续创新体系
在电商行业蓬勃发展的当下,商品详情API作为连接电商平台与开发者、商家及用户的关键纽带,其重要性日益凸显。传统商品详情API主要聚焦于商品基本信息(如名称、价格、库存等)的获取与展示,已难以满足市场对个性化、智能…...
逻辑回归:给不确定性划界的分类大师
想象你是一名医生。面对患者的检查报告(肿瘤大小、血液指标),你需要做出一个**决定性判断**:恶性还是良性?这种“非黑即白”的抉择,正是**逻辑回归(Logistic Regression)** 的战场&a…...
2024年赣州旅游投资集团社会招聘笔试真
2024年赣州旅游投资集团社会招聘笔试真 题 ( 满 分 1 0 0 分 时 间 1 2 0 分 钟 ) 一、单选题(每题只有一个正确答案,答错、不答或多答均不得分) 1.纪要的特点不包括()。 A.概括重点 B.指导传达 C. 客观纪实 D.有言必录 【答案】: D 2.1864年,()预言了电磁波的存在,并指出…...

Python爬虫(一):爬虫伪装
一、网站防爬机制概述 在当今互联网环境中,具有一定规模或盈利性质的网站几乎都实施了各种防爬措施。这些措施主要分为两大类: 身份验证机制:直接将未经授权的爬虫阻挡在外反爬技术体系:通过各种技术手段增加爬虫获取数据的难度…...
【Web 进阶篇】优雅的接口设计:统一响应、全局异常处理与参数校验
系列回顾: 在上一篇中,我们成功地为应用集成了数据库,并使用 Spring Data JPA 实现了基本的 CRUD API。我们的应用现在能“记忆”数据了!但是,如果你仔细审视那些 API,会发现它们还很“粗糙”:有…...

Spring数据访问模块设计
前面我们已经完成了IoC和web模块的设计,聪明的码友立马就知道了,该到数据访问模块了,要不就这俩玩个6啊,查库势在必行,至此,它来了。 一、核心设计理念 1、痛点在哪 应用离不开数据(数据库、No…...

有限自动机到正规文法转换器v1.0
1 项目简介 这是一个功能强大的有限自动机(Finite Automaton, FA)到正规文法(Regular Grammar)转换器,它配备了一个直观且完整的图形用户界面,使用户能够轻松地进行操作和观察。该程序基于编译原理中的经典…...

10-Oracle 23 ai Vector Search 概述和参数
一、Oracle AI Vector Search 概述 企业和个人都在尝试各种AI,使用客户端或是内部自己搭建集成大模型的终端,加速与大型语言模型(LLM)的结合,同时使用检索增强生成(Retrieval Augmented Generation &#…...