当前位置: 首页 > 科技观察

EventSourcing的使用方法

时间:2023-03-19 16:16:15 科技观察

作者|苏晓峰我们经常看到,伴随着EventSourcing,还有几个广为人知的概念:CQRS、EDA(Event-drivenArchitecture),当然还有DDD。在经历了一个使用了EventSourcing的项目之后,想和大家探讨一下,当我们提到EventSourcing时,我们在谈论什么?简述这四个概念之间的关系。EventSourcing的概念一提到EventSourcing,我们就会想到生活中一个很相似的例子,就是账本。会计账簿上的会计分录按发生的顺序记录改变账户余额的事件。通过会计账簿的记录,我们可以计算出任意时点的账户余额。如果有一类应用程序需要保留所有改变最终结果的事件,那么EventSourcing就像是对这类应用程序的概念抽象。所以我们看到EventSourcing也有和账本一样的特点:它不是保留当前状态,而是保留所有引起状态变化的事件。事件将按发生的时间顺序记录。状态是通过事件重构得到的。这听起来像是事件溯源的概念。没有那么难懂,比较现实,所有真实事件都有保存。如果有审计相关的需求,显然很容易获得审计所需的数据。EventSourcing并不是一个在Node.js中广泛使用的成熟设计。我们很难在市场上找到成熟的Node.jsEventSourcing框架,这意味着我们可能会面临更多不可预知的问题。除了不可预见的问题,开发团队也面临着巨大的思维转变:系统中的一等公民变成了事件,所有的逻辑都围绕着事件展开,系统状态不再是必须持久化的元素。这听起来很简单,但在实践中却不是三言两语所能概括的那么简单。什么情况下需要使用事件溯源?我理解有些项目会把命令转成事件,把事件持久化到数据库,但同时也会把命令转成快照保存。读模型的构建都是基于快照的。团队确实保留了系统中发生的所有真实事件,但他们实际上并没有通过事件重构状态,所有状态都来自单独处理的快照。严格来说不能算是EventSourcing的使用。事件保留在系统中,但不使用Sourcing。根据一些背景资料,当时在项目中使用EventSourcing的出发点是客户强烈要求将DDD思想和输出模型完全编码,尤其是EventStorming过程中的输出。上面的例子不禁让我们思考一个问题:什么情况下需要使用EventSoucing?要回答这个问题,先来看看EventSourcing中的核心概念:Event:发生的事实,唯一真实的数据源。用过去时表达。系统中的事件是不可变的,不能更改或删除。当前系统状态只能通过添加新事件来改变。Rebuild:我们可以随时完全丢弃系统状态,通过事件日志按时间顺序重新制定当前系统状态。事件回放(Replay):就像浏览视频一样,如果视频总时长是半小时,我们想回到25分钟,直接把进度条拉回25分钟即可。在EventSoucring系统中,我们可以根据重构的系统状态回放后续的事件,获取我们想要的某个时间点的系统状态。又如:我们的账簿保留了过去一年的所有会计分录,现在想获取5月30日的账户余额,之前由于业务需要,我们都是获取每个季度末的账户余额。那么我们可以通过5月31日已知的账户余额,反向重放5月31日发生的所有出入金,得到5月30日的余额。使用EventSourcing的好处是基于EventSourcing的特点。大家可以讨论一下它能给我们的系统或者业务带来什么好处?审计追踪:首先,它保留所有真实事件的设计,自然为后期的审计追踪提供了便利,因为现实中产生的所有痕迹都保留在系统中,这些痕迹是不允许修改的;适应各种查询需求:我们系统的状态来源于事件,这意味着我们可以根据不同的查询需求构建不同的读模型来满足业务需求。这是我们看到事件溯源经常与CQRS一起出现的原因之一。因为在EventSourcing系统中,我们可以利用它的特性来分离读写模型;debugging:这个优势的来源也是为了保存所有的事件,也就是说当我们的线上环境出现问题的时候,我们可以把线上环境的所有事件都保存在一个类似的线上环境中进行测试,找出哪里问题是;可以获取系统任意时间点的状态;系统状态可以在内存中,不一定要持久化到数据库中:当发生任何事情,就会有一个服务崩溃时,我们可以通过事件重建系统状态。这样就不需要考虑持久化到数据库中涉及到的各种数据映射逻辑;领域事件是有价值的,生成的领域事件在不丢失所有现实痕迹的情况下被存储。为支持后期业务扩展,提供业务数据分析的数据源。从它能带来的优势来看,当我们的业务需求包括:能够保留所有事件以满足审计的需要;客户认为系统中发生的事实是有价值的,必须保留下来,以支持后续业务扩展的业务分析;需要在不固定的时间点频繁查询系统状态;当您有基于不同维度的各种查询需求时,请考虑使用事件溯源。当然,在决定使用它之前,我们还是要考虑一下它的缺点:事件版本:不同聚合根下的不同类型或者事件,我们有不同的EventHandlers,随着业务的发展,相应的事件处理也会不同。这意味着我们在扩展业务时需要考虑与旧事件的兼容性;业务发生变化后,我们需要重放以满足业务需求的应用状态也可能发生变化,那么如何兼容旧事件呢?rebuildorreplay新结构的应用状态?让开发团队感到陌生的设计思路;不太成熟的事件溯源框架支持;事件存储中需要事件序列化。EventSourcing与其他架构的关系回到文章开头提到的四个经常一起使用的概念:当我们决定使用EventSourcing作为架构选择时,我们通常会选择DDD来构建领域事件。DDD中提到的Event是指改变系统状态的实际事件。同样,我们在EventSourcing系统中存储的也是一个会引起系统状态变化的事件。看起来这两种不同的软件开发思路对Event有着默契。大多数使用事件溯源的系统都会使用CQRS。因为我们的持久化事件和查询需要的结构有明显的区别,所以我们一般不会通过Rebuild或者Replay每次查询来获取需要的状态,而是构建一个查询需要的方便读取的Model。即便如此,当我们决定选择CQRS时,我们仍然要考虑引入后增加的复杂性。这也意味着并非所有的事件溯源系统都需要采用CQRS。至于EDA,其实是一个与之无关的概念,但是我们在处理服务之间的通信时经常会用到它。当我们的项目刚好是微服务,采用DDD,需要引入EDAwithEventSourcing和CQRS,平时的技术讨论一定要慎重。在什么情况下。如果想了解更多EDA的概念,可以参考MartinFowler的文章《Whatarewetalkingaboutwhenitcomesto"event-driven"?》,其中也提到我们在EventSourcing中经常会混用一些概念,EDA和CQRS。希望本文能给大家带来启发,去思考EventSourcing的设计思路。也希望以后能完成另一篇关于EventSourcing的文章。其实这篇文章还有一些疏漏,比如EventSourcing架构选择决策的不足,但是考虑到EventSourcing架构的实际选择,通常会使用其他的设计和架构,比如反复提到的CQRS和CQRS在文章中。在最终确定的架构下,DDD除了本文提到的缺点之外,还会引入其他问题,但因为我认为这不是EventSourcing架构本身导致的问题,所以没有在文章中深究。但是如果你真的决定将EventSourcing作为系统设计思路的一部分,你还需要对EventSourcing的应用做更多的探索。本文旨在厘清事件溯源的概念,消除大家对事件溯源的一些误解。