enode框架入门:saga的思想与实现

因为enode框架的思想是,一次修改只能新建或修改一个聚合根;那么,如果一个用户请求要涉及多个聚合 根的新建或修改该怎么办呢?本文的目的就是要分析清楚这个问题在enode框架下是如何解决的。如果想直接 通过看代码的朋友,可以直接下载源代码,源码中共有三个例子,BankTransferSagaSample这个例子就是本文 所用的例子。

saga的由来

saga这个术语,可能很多人都还很陌生。saga的提出,最早是为了解 决可能会长时间运行的分布式事务(long-running process)的问题。所谓long-running的分布式事务,是指 那些企业业务流程,需要跨应用、跨企业来完成某个事务,甚至在事务流程中还需要有手工操作的参与,这类 事务的完成时间可能以分计,以小时计,甚至可能以天计。这类事务如果按照事务的ACID的要求去设计,势必 造成系统的可用性大大的降低。试想一个由两台服务器一起参与的事务,服务器A发起事务,服务器B参与事务 ,B的事务需要人工参与,所以处理时间可能很长。如果按照ACID的原则,要保持事务的隔离性、一致性,服 务器A中发起的事务中使用到的事务资源将会被锁定,不允许其他应用访问到事务过程中的中间结果,直到整 个事务被提交或者回滚。这就造成事务A中的资源被长时间锁定,系统的可用性将不可接受。

而saga, 则是一种基于补偿的消息驱动的用于解决long-running process的一种解决方案。目标是为了在确保系统高可 用的前提下尽量确保数据的一致性。还是上面的例子,如果用saga来实现,那就是这样的流程:服务器A的事 务先执行,如果执行顺利,那么事务A就先行提交;如果提交成功,那么就开始执行事务B,如果事务B也执行 顺利,则事务B也提交,整个事务就算完成。但是如果事务B执行失败,那事务B本身需要回滚,这时因为事务A 已经提交,所以需要执行一个补偿操作,将已经提交的事务A执行的操作作反操作,恢复到未执行前事务A的状 态。这样的基于消息驱动的实现思路,就是saga。我们可以看出,saga是牺牲了数据的强一致性,仅仅实现了 最终一致性,但是提高了系统整体的可用性。

CQRS架构下的saga (process manager)

上面一段 ,我们知道了saga的由来,现在我们再看一下CQRS架构下,saga是用来做什么的。虽然都叫saga,但是实际上 在CQRS架构下,人们往往用saga来解决DDD中多个聚合或多个bounded context之间的通信问题。DDD中有 bounded context的概念。一个bounded context代表一个上下文边界,一个bounded context中可能包含一个 或多个聚合。而saga就是用来实现bounded context之间的通信,或者是聚合之间的通信。在经典DDD中,我们 通常用领域服务来实现多个聚合的协调,并最终通过事务的方式来提交所有聚合的修改;这样做的后果是,1 :用到了事务;2.一个事务涉及了多个聚合的更改;这样做没什么不好,在条件允许的情况下(比如不会出现 分布式事务的情况下或者并发修改的请求数不高的情况下),这样做没什么特别大的问题。唯一的问题是,这 样做会增加并发冲突的几率。现在的web应用,往往都是多用户在同时向系统发送各种处理请求,所以我们不 难想到,一个事务中涉及到的聚合越多,那并发冲突的可能性就越高。不仅如此,如果你的聚合很大,包含了 很多的子实体和很多的方法,那该聚合持久化时产生并发冲突的几率也会相对较高;而系统的并发冲突将直接 影响系统的可用性;所以,一般的建议是,我们应该尽量将聚合设计的小,且尽量一次只修改一个聚合;这样 我们就不需要事务,还能把并发冲突的可能性降到最低;当然,单个聚合持久化时也还会存在并发冲突,但这 点相对很容易解决,因为单个聚合是数据一致性的最小单元,所以我们可以完全不需要事务,通过乐观锁就能 解决并发覆盖的问题;关于这个问题的讨论,大家如果还有兴趣或者想了解的更加深入,我推荐看一下 Effective Aggregate Design这篇论文,共三个部分,其作者是《implementing domain-driven design》一 书的作者。

所以,通过上面的分析,我们知道了“聚合应该设计的小,且一次修改只修改一个聚合” 这样一条不成文的原则。当然你一定有很多理由认为不应该这样,欢迎大家讨论。那么如果要遵循这样的原则 ,那我们需要一种机制来解决多个聚合之间的通信的问题。在CQRS的架构下,人们也都把这种机制叫做saga, 但因为这种CQRS架构下的saga的语义已经不是上面一段中介绍的saga了。所以,微软也把cqrs架构下的saga叫 做process manager,具体可以看一下微软的一个CQRS架构的开源项目的例子;process manager这个名字我们 应该很容易理解,即流程管理器。事实上,一个saga所做的事情就是和一个流程一样的事情。只不过传统的流 程,都有一个流程定义,当用户发起一个流程时,就会产生一个流程实例,该流程实例会严格按照流程定义的 流向来进行流转,驱动流程流转的往往是人的操作,比如审批操作。而process manager,也是一个流程,只 不过这个流程是由消息驱动的。一个典型的process manager会响应事件,然后产生新的命令去执行下一步操 作。用过NServiceBus的人应该知道,NServiceBus中就内置了saga的机制,我们可以很轻松的利用它来实现分 布式的消息驱动的long-running process;

时间: 2024-08-27 04:50:07

enode框架入门:saga的思想与实现的相关文章

enode框架入门:事件驱动架构(EDA)思想的在框架中如何体现

开源地址:https://github.com/tangxuehua/enode 上一篇文章,我给大家分享了我的一个基于DDD 以及EDA架构的框架enode,但是只是介绍了一个大概.接下来我准备用很多一篇篇详细但不冗长的文章介绍每 个点.尽量争取一次不介绍太多内容,但希望每次介绍完后都能让大家知道这个小点的设计思想,以及为了解 决的问题. 好了,这篇文章,我主要想介绍的是EDA思想在enode框架中如何体现? 经典DDD的基 于领域服务的实现方式 一般的应用程序,如果一个用户动作会涉及多个聚合

enode框架入门:Staged event-driven architecture思想的运用

上一篇文章,简单介绍了enode框架的command service api设计思路.本文介绍一下enode框架对Staged Event-driven architecture思想的运用.通过前一篇文章我们知道command service是会被高并发的访问,我 们除了可以用异步的方式执行command以及集群的方式来提高系统响应性能外.最根本上要解决的问题是尽量 快的处理单个command.这样才能在单位时间内处理更多的command. 先贴一下enode框架的内部实现架 构图,这样对大家理

enode框架入门:开篇

前言 今天是个开心的日子,又是周末,可以安心轻松的写写文章了.经过了大概3年的DDD理论积累 ,以及去年年初的第一个版本的event sourcing框架的开发以及项目实践经验,再通过今年上半年利用业余时 间的设计与开发,我的enode框架终于可以和大家见面了. 自从Eric Evan提出DDD领域驱动设计以来已 经过了很多年了,现在已经有很多人在学习或实践DDD.但是我发现目前能够支持DDD开发的框架还不多,至少 在国内还不多.据我所知道的java和.net平台,国外比较有名的有:基于java

ENode 1.0 - Saga的思想与实现

开源地址:https://github.com/tangxuehua/enode 因为enode框架的思想是,一次修改只能新建或修改一个聚合根:那么,如果一个用户请求要涉及多个聚合根的新建或修改该怎么办呢?本文的目的就是要分析清楚这个问题在enode框架下是如何解决的.如果想直接通过看代码的朋友,可以直接下载源代码,源码中共有三个例子,BankTransferSagaSample这个例子就是本文所用的例子. Saga的由来 saga这个术语,可能很多人都还很陌生.saga的提出,最早是为了解决可

enode框架入门:消息队列的设计思路

上一篇文章,简单介绍了enode框架内部的整体实现思路,用到了staged event-driven architecture的思 想.通过前一篇文章,我们知道了enode内部有两种队列:command queue.event queue:用户发送的command 会进入command queue排队,domain model产生的domain event会进入event queue,然后等待被dispatch到所 有的event handlers.本文介绍一下enode框架中这两种消息队列到底

enode框架入门:消息的重试机制的设计思路

上一篇文章,简单介绍了enode框架中消息队列的设计思路,本文介绍一下enode框架中关系消息的重试机 制的设计思路. 对于一个EDA架构为基础的框架,核心就是消息驱动,然后基于最终一致性的原则.所 以,非常重要的一点是,如果消息一次执行不成功,那该怎么办?我能想到的对策就是消息的重试.我发现, 这篇文章比较难写,因为感觉要把复杂的事情清晰的表达出来,感觉确实不容易.说到重试,那什么是消息的 重试呢?怎么重试呢?我这里提到的重试是指,一个消息,从消息队列取出来后,要处理,但是处理失败了, 然后要

enode框架入门:框架的总体目标

本文想介绍一下enode框架要实现的目标以及部分实现分析思路剖析.总体来说enode框架是一个基于cqrs 架构和消息驱动的应用开发框架.在说实现思路之前,我们先看一下enode框架希望实现的一些目标吧! 框架总体目标 高吞吐量(High Throughput).低延迟(Low Latency).高可用性(High Availability): 需要能充分利用CPU,即要允许方便配置需要使用的并行处理线程数,以提高单台机器的command处理能力 : 支持command的同步和异步处理,同步处理

enode框架入门:框架的物理部署思路

上一篇文章,介绍了enode框架的总体目标,以及如何实现高吞吐.低延迟.高可用.无单点问题的实现思 路.本篇文章,我们再分析一下其他一些需要考虑的问题.我发现写文章挺累的,费时费脑经,但我会坚持下 去.本文主要分析一下enode框架的物理部署: enode框架的物理部署思路:集群的web站点+分布式缓 存和存储 集群的概念:多台机器做相同的业务,对外如一台机器在做事情一样,集群中任意一台机器 挂了没有影响,因为其他机器还在工作:集群的机器要访问的数据的设计,我觉得一般有两种思路: 集群中每台机器

enode框架入门:Command Service API设计思路

上一篇文章,介绍了enode框架的物理部署思路.本文我们再简单分析一下Command Service的API设计: Command Service在enode框架中的地位非常重要,用户使用enode框架的主入口就是command service .UI层如controller会通过发送command给command service,然后框架就开始处理该command.不然看出, command service有可能会被高并发的访问.那么command service该提供什么样的API呢? 首先