今天这篇博文的主要目的是分享一下我设计Saga的实现思路来抛砖引玉,其实Saga本身非常的类似于一个简单的工作流体系,相比工作流不一样的部分在于它没有工作流的复杂逻辑处理机制(比如会签),没有条件分支机制,相对工作流不同的部分在于工作流流程阻塞结束后它多了一个反向补偿的流程。同时相对于工作流通过灵活的配置来实现运行时来讲他的逻辑流转比较固化基本在代码编写阶段就已经完成了流程的配置,编译后运行时一般是不会更改的。下面就从配置、流转、传递模型和异常处理几个方面来讲一下我的实现思路是什么权当抛砖引玉,希望大家留言评论。

目录:
一、通过Dapr实现一个简单的基于.net的微服务电商系统

二、通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解

三、通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr

四、通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布

五、通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理

六、通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务

七、通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流

八、通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪

九、通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权 && 百度版Oauth2

十、通过Dapr实现一个简单的基于.net的微服务电商系统(十)——一步一步教你如何撸Dapr之绑定

十一、通过Dapr实现一个简单的基于.net的微服务电商系统(十一)——一步一步教你如何撸Dapr之自动扩/缩容

十二、通过Dapr实现一个简单的基于.net的微服务电商系统(十二)——istio+dapr构建多运行时服务网格

十三、通过Dapr实现一个简单的基于.net的微服务电商系统(十三)——istio+dapr构建多运行时服务网格之生产环境部署

十四、通过Dapr实现一个简单的基于.net的微服务电商系统(十四)——开发环境容器调试小技巧

十五、通过Dapr实现一个简单的基于.net的微服务电商系统(十五)——集中式接口文档实现

十六、通过Dapr实现一个简单的基于.net的微服务电商系统(十六)——dapr+sentinel中间件实现服务保护

十七、通过Dapr实现一个简单的基于.net的微服务电商系统(十七)——服务保护之动态配置与热重载

十八、通过Dapr实现一个简单的基于.net的微服务电商系统(十八)——服务保护之多级缓存

十九、通过Dapr实现一个简单的基于.net的微服务电商系统(十九)——分布式事务之Saga模式

二十、通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享

附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址

二、通讯框架地址

三、Saga框架地址

一、整体流程

  首先我们通过一个讲的比较烂的业务模型(库存-余额-订单)来简述一下saga是如何实现分布式事务的。然后再讲解一下saga实现这套流程都做了哪些工作来让大家对分布式事务有一个清晰的认知。首先来讲一下为什么要实现一个分布式事务。当我们的应用通过业务拆解后以物理隔离的模式运行在不同的物理机/虚拟机/容器上并且我们的数据库也做了相应的隔离后,我们没有办法通过发布一个单一的原子的ACID事务来达到事务的一致性。单个数据库在运行事务时通过对应的机制(诸如主流的MVCC多版本并发控制)来确保ACID。但是在跨多个数据库的情况下,各家数据库厂商就只能通过二阶段提交的XA协议来实现分布式事务。这种方案确实在一定程度上降低了分布式事务的复杂性不过性能上却无法做到很好的平衡。而更加常见的办法是通过应用自身调用各自的数据库原子事务以链条的形式来完成分布式事务,而saga作为其中的一种方案已经在各大企业的业务场景中被广泛的实践过了。

  下面我们就看看一个比较典型电商下单的场景,当电商注册用户在电商平台完成内用金充值后可以直接在平台上下单购买商品。下单的流程如下:点击购物车下订单->预扣库存->预扣内用金->创建订单,流程如下:

  在理想情况下当我们下订单顺利时,每一个服务只需要包裹各自的事务(扣库存/扣余额/创建订单),通过调用链即可完成一个完整的订单创建业务。然而由于数据库存在物理隔离,很多时候我们需要面对这种情况:

  这个时候saga的作用就体现出来了,它可以通过事件订阅/发布的形式帮你完成1-8的自动化的调用或者补偿调用,你需要做的只是一个配置和把对应的订阅/补偿方法给注册到这个配置的主题上即可。接下来我们就讲讲saga是如何一步一步来实现这套逻辑的。

二、配置

  *下面的所有实现均以Dapr实现集成为例,即(Oxygen-Saga.PubSub.Dapr + Oxygen-Saga.Store.Dapr),但是整体集成逻辑和(Oxygen-Saga.PubSub.Rabbitmq + Oxygen-Saga.Store.Redis) 区别不大,只有部分队列和持久化实现的区别。

  首先我们需要一个管理所有分布式事务配置的管理包项目,这个包会作为一个通用的nuget or 项目被其他具体的业务服务继承。然后所有的Saga配置都应该在这个包中编写对应的配置文件。同时每个服务会引入这个包并且创建自己的SagaConfiguration配置文件用于向saga服务申明自己需要创建Saga服务

三、注册

  注册的过程主要分为三个部分,一个部分就是需要把之前Topic配置文件引入到本地并形成我们的Saga配置,一部分是引入我们需要的第三方的组件来支持整个saga运行起来,另一部分是创建对应的订阅服务代理来支持对事件的订阅和分发。

四、流转

  当整个注册工作完成后启动项目会按照上图所示进行相关的注册和构造代理的工作,接下来就是具体业务的流转过程,所有的订阅会被一个SagaSubscribe(由上一步的RegisterSagaHandler触发并注入ISagaEventHandler后创建所得)接受到,并通过该Hub完成对应的路由投递到具体的方法函数进行业务流转。整个Hub结构如下所示,可以看到其实Saga是在每个服务注册了一个订阅器,通过订阅器接收到其他业务发布的Saga事件后通过代理的方式路由到具体的业务实现上来实现流程代理的。

  那Saga又是怎么实现自动化的发布下一个事件或者根据代理调用目标函数抛出异常后自动进行补偿事件的呢,这就要看Saga的传递模型结构了,整个模型结构如下图,可以看到这里的Topic其实就是对应到的上图的TopicName,所以当Proxy收到事件解析出Topic后即可路由到具体的函数进行处理,当函数处理完毕后,Proxy即可根据链表当前所在的节点获取Next,如果Next不为空,则发送当前函数回调的Result封装成一个消息包投递到Next所属的服务,如果Next为空则说明整个流程结束,不再执行任何操作。

五、异常

  同样的由于不能确保所有的业务能够完完全全的处理完毕自己业务比如当库存不足时,余额不足时,这时候就需要业务端自行通过触发异常的方式回调上一步的补偿,这样代理就会尝试从链表中获取Previous,如果Previous不为空,则发送当前函数抛出异常(SagaException<T>)回调的Result封装成一个消息包投递到Previous所属的服务,如果Previous为空则说明整个补偿流程结束,不再执行任何操作。不过还有一种情况,就是当前目标函数触发的是非SagaException异常,这种情况下Saga没有办法获取到上一步补偿所需的数据,所以这个时候就只能交给人工处理,也就是在注册部分第三步RegisterSagaHandler可以注入一个异常处理程序,当发生异常Saga无法处理时我们会尝试向Func<IServiceProvider, ErrorModel, Task> errorHandle 函数投递ErrorModel,由客户端自行决定如何处理异常。

六、持久化

  所有的消息在流转过程中会被包装为一个SagaData类型持久化到Store中,并根据流转类型被赋予三个状态,分别是Processing,Done,Error。这部分数据会在Store中保存24小时。未来扩展中会提供相应的接口获取这部分数据用于框架扩展。

好了,整个Saga的设计思路就到此讲解完毕了。在设计中肯定还有很多不足和有缺陷的部分,希望小伙伴们留言评论。最后再次附上系列开源地址,欢迎star fork issues 一键三连

一、电商Demo地址

二、通讯框架地址

三、Saga框架地址

通过Dapr实现一个简单的基于.net的微服务电商系统(二十)——Saga框架实现思路分享的更多相关文章

  1. 通过Dapr实现一个简单的基于.net的微服务电商系统(二)——通讯框架讲解

    首先感谢张队@geffzhang公众号转发了上一篇文章,希望广大.neter多多推广dapr,让云原生更快更好的在.net这片土地上落地生根. 目录:一.通过Dapr实现一个简单的基于.net的微服务 ...

  2. 通过Dapr实现一个简单的基于.net的微服务电商系统(四)——一步一步教你如何撸Dapr之订阅发布

    之前的章节我们介绍了如何通过dapr发起一个服务调用,相信看过前几章的小伙伴已经对dapr有一个基本的了解了,今天我们来聊一聊dapr的另外一个功能--订阅发布 目录:一.通过Dapr实现一个简单的基 ...

  3. 通过Dapr实现一个简单的基于.net的微服务电商系统

    本来想在Dpar 1.0GA时发布这篇文章,由于其他事情耽搁了放到现在.时下微服务和云原生技术如何如荼,微软也不甘示弱的和阿里一起适时推出了Dapr(https://dapr.io/),园子里关于da ...

  4. 通过Dapr实现一个简单的基于.net的微服务电商系统(三)——一步一步教你如何撸Dapr

    目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实现一个简单的基于.net的微服务电商系统(二)--通讯框架讲解 三.通过Dapr实现一个简单的基于.net的微服务电 ...

  5. 通过Dapr实现一个简单的基于.net的微服务电商系统(五)——一步一步教你如何撸Dapr之状态管理

    状态管理和上一章的订阅发布都算是Dapr相较于其他服务网格框架来讲提供的比较特异性的内容,今天我们来讲讲状态管理. 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系统 二.通过Dapr实 ...

  6. 通过Dapr实现一个简单的基于.net的微服务电商系统(六)——一步一步教你如何撸Dapr之Actor服务

    我个人认为Actor应该是Dapr里比较重头的部分也是Dapr一直在讲的所谓"stateful applications"真正具体的一个实现(个人认为),上一章讲到有状态服务可能很 ...

  7. 通过Dapr实现一个简单的基于.net的微服务电商系统(七)——一步一步教你如何撸Dapr之服务限流

    在一般的互联网应用中限流是一个比较常见的场景,也有很多常见的方式可以实现对应用的限流比如通过令牌桶通过滑动窗口等等方式都可以实现,也可以在整个请求流程中进行限流比如客户端限流就是在客户端通过随机数直接 ...

  8. 通过Dapr实现一个简单的基于.net的微服务电商系统(八)——一步一步教你如何撸Dapr之链路追踪

    Dapr提供了一些开箱即用的分布式链路追踪解决方案,今天我们来讲一讲如何通过dapr的configuration来实现非侵入式链路追踪的 目录:一.通过Dapr实现一个简单的基于.net的微服务电商系 ...

  9. 通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之OAuth2授权

    Oauth2授权,熟悉微信开发的同学对这个东西应该不陌生吧.当我们的应用系统需要集成第三方授权时一般都会做oauth集成,今天就来看看在Dapr的语境下我们如何仅通过配置无需修改应用程序的方式让第三方 ...

随机推荐

  1. js获取相邻节点的value值

    document.getElementById('id').nextElementSibling.value或者document.getElementById('id').previousElemen ...

  2. 使用.NET 6开发TodoList应用(24)——实现基于JWT的Identity功能

    系列导航及源代码 使用.NET 6开发TodoList应用文章索引 需求 在.NET Web API开发中还有一个很重要的需求是关于身份认证和授权的,这个主题非常大,所以本文不打算面面俱到地介绍整个主 ...

  3. kibana7.x安装配置操作elasticsearch

    什么是Kibana? Kibana是一个基于Node.js的Elasticsearch索引库数据统计工具,可以利用Elasticsearch的聚合功能,生成各种图表,如柱形图,线状图,饼图等. 而且还 ...

  4. linux服务器之间传输文件的四种方式

    linux文件传输在内网渗透中至关重要,所以我在此总结一下几种Linux服务器之间传输文件的四种方式 1. scp [优点]简单方便,安全可靠:支持限速参数[缺点]不支持排除目录[用法]scp就是se ...

  5. 一次神奇的Azure speech to text rest api之旅

    错误Max retries exceeded with url: requests.exceptions.ConnectionError: HTTPSConnectionPool(host='%20e ...

  6. 嵌入式硬件之ADC/DAC

    嵌入式硬件之ADC/DAC 写在前面 这几天在做一个寒假练项目,其中涉及到了音频的处理,ADC.DAC再次进入到了我的视野,并引起了我新的思考. 1.初次相识 记得去年七月份,本科毕业刚离校,就到研究 ...

  7. golang中GPM模型原理与调度器设计策略

    一.GMP模型原理first: 1. 全局队列:存放待运行的G2. P的本地队列:同全局队列类似,存放待运行的G,存储的数量有限:256个,当创建新的G'时,G'优先加入到P的本地队列,如果队列已满, ...

  8. linux中wc命令

    目录 一:linux中wc命令 1.wc命令介绍 2.wc命令作用 3.wc命令格式 4.参数 5.解析案例 一:linux中wc命令 1.wc命令介绍 Linux wc命令用于计算字数. 利用wc指 ...

  9. 日志模块详细介绍 hashlib模块 动态加盐

    目录 一:hashlib模块 二:logging 一:hashlib模块 加密: 将明文数据通过一系列算法变成密文数据(目的就是为了数据的安全) 能够做文件一系列校验 python的hashlib提供 ...

  10. Working hard to know your neighbor's margins:Local descriptor learning loss论文笔记

    Abstract 论文提出了一种新的训练方法,受到了 Lowe's matching criterion for SIFT的启发.这种新的loss,要比负责的正则方法更好.把这个新的loss方法结合L ...