目录:

一、通过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授权

通过Dapr实现一个简单的基于.net的微服务电商系统(九)——一步一步教你如何撸Dapr之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的微服务电商系统(十八)——服务保护之多级缓存

附录:(如果你觉得对你有用,请给个star)
一、电商Demo地址:https://github.com/sd797994/Oxygen-Dapr.EshopSample

二、通讯框架地址:https://github.com/sd797994/Oxygen-Dapr

三、Saga框架地址:https://github.com/sd797994/Oxygen-Saga

一、什么是Saga

在领域驱动设计中,由于领域边界的存在,以往的分层设计中业务会按照其固有的领域知识被切分到不同的限界中,并且引入了领域事件这一概念来降低单个业务的复杂度,通过非耦合的事件驱动来完成复杂的业务。但是事件驱动带来了一些新的问题,由于以往一个原子性极强的逻辑被拆散到了一个一个小的领域中,原子性事务数据的强一致性无法被保证。为了解决这个问题,一般会采用事务补偿的方式来确保最终一致。

当我们采用多个本地事务组合去进行业务处理时,由于业务其本身的复杂性,往往需要在多个事务中协调。而事件协调器(saga)就是一个专门降低其复杂度的设计,开发人员原则上只需要将事件和补偿按照一定顺序注册到协调处理器中,原则上协调器会按照注册的事件依次执行,若出现事件执行失败时,也会按照补偿列表进行相应的回滚。

去年曾经在一篇文章里聊过Saga,链接在此。相比去年的那个小DEMO。我在此基础上基于Dapr的状态管理完成了另外一个开源项目Oxygen-Saga,地址:https://github.com/sd797994/Oxygen-Saga。当然这个项目既可以引入到dapr的环境中完成Saga事务,本身也可以独立的基于rabbitmq+redis来完成非Dapr环境下的Saga事务。今天主要讲解一下如何在Dapr环境下引入Saga来实现一个分布式事务。

  首先我们还是看看目前的一个订单下单逻辑,可以看到基于Actor服务,我们的请求是在订单服务里直连商品服务Actor完成库存减扣的,并通过Actor的周期性持久化机制完成事务落库,所以实际上是把分布式事务的复杂性通过Actor屏蔽掉了,并没有涉及到真正的分布式事务。

  从代码层面也可以看到,整个事务其实是在同一个方法里以同步调用Actor的方式完成的。

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

#region 私有远程服务包装器方法

async Task<List<OrderGoodsSnapshot>> GetGoodsListByIds(IEnumerable<Guid> input)

{

    return (await goodsQueryService.GetGoodsListByIds(new GetGoodsListByIdsDto(input))).GetData<List<OrderGoodsSnapshot>>();

}

async Task<bool> DeductionGoodsStock(CreateOrderDeductionGoodsStockDto input)

{

    var data = input.CopyTo<CreateOrderDeductionGoodsStockDto, DeductionStockDto>();

    data.ActorId = input.GoodsId.ToString();

    return (await goodsActorService.DeductionGoodsStock(data)).GetData<bool>();

}

async Task<bool> UnDeductionGoodsStock(CreateOrderDeductionGoodsStockDto input)

{

    var data = input.CopyTo<CreateOrderDeductionGoodsStockDto, DeductionStockDto>();

    data.ActorId = input.GoodsId.ToString();

    return (await goodsActorService.UnDeductionGoodsStock(data)).GetData<bool>();

}

#endregion

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

public async Task<ApiResult> CreateOrder(OrderCreateDto input)

{

    var mockUser = (await accountQueryService.GetMockAccount()).GetData<CurrentUser>();

    //申明一个创建订单领域服务实例,将远程rpc调用作为匿名函数传递进去

    var createOrderService = new CreateOrderService(GetGoodsListByIds, DeductionGoodsStock, UnDeductionGoodsStock);

    return await ApiResult.Ok("订单创建成功!").RunAsync(async () =>

    {

        var order = await createOrderService.CreateOrder(mockUser.Id, mockUser.UserName, mockUser.Address, mockUser.Tel, input.Items.CopyTo<OrderCreateDto.OrderCreateItemDto, OrderItem>().ToList());//通过订单服务创建订单

        repository.Add(order);

        if (await new CheckOrderCanCreateSpecification(repository).IsSatisfiedBy(order))

            await unitofWork.CommitAsync();

        await eventBus.SendEvent(EventTopicDictionary.Order.CreateOrderSucc, new OperateOrderSuccessEvent(order, mockUser.UserName));//发送订单创建成功事件

    },

    //失败回滚

    createOrderService.UnCreateOrder);

}

  而在Saga方案里就变得不一样了,我们需要借助Saga的流程管理器在多个实例中流转我们的事务,通过事件订阅和发布来最终完成一个分布式事务。具体的调用流程如下:

可以看到整个流程完全依赖于SagaManger来提供对应的调用策略,而作为开发人员只需要为每个策略提供对应的委托函数,对应的具体流程如下:

  一、首先是订单服务和商品服务在系统初始化时需要注册对应的配置文件到本地Saga管理器,并且需要提供对应的流程处理委托(包括业务事件委托+补偿事件委托+异常处理委托)。

  二、在客户发起一个订单时,只需要创建一个Saga流程实例,剩下的就交给Saga,它会自动帮我们流转整个业务逻辑而无需人工插手。

二、talk is cheap, show me the code

首先我们需要为整个订单创建流程设计一组Topic:

接着我们创建一个Saga配置注册这组topic进去,流程比较简单,第一步是扣除库存,下一步是创建订单,补偿事件只有一个就是库存回滚:

再然后我们需要创建这些Topic对应的事件处理器:

订单服务:

商品服务:

接着我们在各自的服务里去实现它们:

商品服务:

订单服务:

然后我们在订单用例里创建一个Action用于启动saga流程(注意是第二个方法):

最后我们在商品和订单服务中引入saga组件并注册事件和异常回调委托(注册代码相似,此处仅展示其中一个服务的):

接着我们修改m站的创建订单接口,修改为新的Saga流程接口,然后编译整个项目,启动并测试一下:

可以看到整个流程被顺利的通过Saga管理器流转完毕。接着我们尝试注入一个故障,看看能否正常的被异常订阅器捕获到:

编译后再测试一下,我们可以看到事件异常订阅器里已经成功捕获到了这个异常:

接着我们在创建订单注入一个异常,让商品库存进行回滚操作,这里由于下单后异常商品补偿所以在界面上是体现不出来的(当然在真实的业务场景中一般是下单5秒等待后查询订单创建情况,或发送一条站内信告知下单失败),这里我们通过打印控制台来演示:

接着我们运行并下单,追踪商品服务的日志:

可以看到由于订单创建失败,saga触发了补偿事件并成功执行了补偿。好了,关于saga的演示就到这里,可尝试拉取最新的商城源码执行即可看到效果。

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

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

    很久没有更新dapr系列了.今天带来的是一个小的组件集成,通过多级缓存框架来实现对服务的缓存保护,依旧是一个简易的演示以及对其设计原理思路的讲解,欢迎大家转发留言和star 目录: 一.通过Dapr实 ...

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

    dapr目前更新到了1.2版本,在之前4月份的时候来自阿里的开发工程师发起了一个dapr集成Alibaba Sentinel的提案,很快被社区加入到了1.2的里程碑中并且在1.2 release 相关 ...

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

    多运行时是一个非常新的概念.在 2020 年,Bilgin Ibryam 提出了 Multi-Runtime(多运行时)的理念,对基于 Sidecar 模式的各种产品形态进行了实践总结和理论升华.那到 ...

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

    如果说Actor是dapr有状态服务的内部体现的话,那绑定应该是dapr对serverless这部分的体现了.我们可以通过绑定极大的扩展应用的能力,甚至未来会成为serverless的基础.最开始接触 ...

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

    在上一篇文章里,我们通过注入sentinel component到apigateway实现了对下游服务的保护,不过受限于目前变更component需要人工的重新注入配置以及重启应用更新componen ...

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

    上一篇我们讲到了dapr提供的bindings,通过绑定可以让我们的程序轻装上阵,在极端情况下几乎不需要集成任何sdk,仅需要通过httpclient+text.json即可完成对外部组件的调用,这样 ...

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

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

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

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

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

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

最新文章

  1. 【全网之最】用JavaScript写一个最简短的语句实现从A数组中去除B数组中相同元素
  2. 配置jdk环境 windows
  3. Python使用matplotlib函数subplot可视化多个不同颜色的折线图、为指定的子图添加图例信息(legend)
  4. 网络标准和OSI模型(1)
  5. distinct作用于后面所有的列吗_InnoDB索引允许NULL对性能有影响吗
  6. linux 硬盘繁忙,icinga2 借助check_iostat.sh抓取linux服务器的diskIO(硬盘繁忙度)
  7. VirtualBox中使用双网卡实现CentOS既能上网(校园网)也能使用SSHclient
  8. java中setStroke_Java调用setStroke()方法设置笔画属性的语法 原创
  9. oracle 各种学习资料
  10. 【SAS系列】SAS入门书籍推荐
  11. Linux命令大全(最详细)Linux操作系统上课笔记整理
  12. 命令行运行coppeliasim(vrep)出现/usr/lib/x86_64-linux-gnu/libQt5Core.so.5: version `Qt_5.12‘ not found
  13. C语言圣诞树(精修版)附图(有初学者版还有进阶版)
  14. java面试题:编写java程序,随机生成n个m以内的加减法算式,形如a±b=c,其中n,m∈N+,a,b,c∈[0,m].请结合自身请款勾选作答的题目,然后在下面写出代(伪)码.
  15. 分析1996~2015年人口数据各个特征的分布与分散情况
  16. 视频驱动之eDP接口LCD调试
  17. (转)慈不掌兵、义不养财
  18. 概率统计D 01.06 伯努利概型
  19. Vue里面使用el-cascader 级联选择器 children为空 和获取value和label问题
  20. 微信小程序之Js修改元素样式

热门文章

  1. OS X 10.11 安装Cocoapods
  2. GDI与OpenGL与DirectX之间的区别
  3. 怎么在matlab中图像中外接矩形,Matlab 最小外接矩形
  4. webjars管理静态资源
  5. JMeter中添加dubbo相关插件异常问题解决
  6. (3)Python3笔记之变量与运算符
  7. Python实现将不规范的英文名字首字母大写
  8. 面向对象——概念(成员变量、静态变量、成员方法、静态方法、垃圾回收机制、重载、包)...
  9. cocos2d-x知识总结
  10. win8下cocos2dx3.2移植android平台及代码打包APK