.Net微服务实战之必须得面对的分布式问题(二)

本文涉及的产品
注册配置 MSE Nacos/ZooKeeper,118元/月
服务治理 MSE Sentinel/OpenSergo,Agent数量 不受限
云原生网关 MSE Higress,422元/月
简介: .Net微服务实战之必须得面对的分布式问题(二)

分布式事务

  

分布式事务分刚性事务与柔性事务,刚性事务对应ACID理论,而柔性事务也就是最终一致性,对应BASE理论。最终一致性指如果数据再一段时间内没有被另外的数据操作所更改,那它最终会达到与强一致性过程相同的结果。

  

分布式系统场景下很少使用xa事务,主要原因是xa事务是基于基础设施层面的强一致性事务,场景主要在一个服务多个数据源,追求强一致性,复杂度高,吞吐量低。

  

而最终一致性方案更多是基于服务应用层的弱一致性事务,场景主要是多服务多数据源与多服务单数据源,满足了BASE理论的三个特点:基本可用软状态最终一致性

  

以订单支付为例讲述下BASE理论,客户在A平台发起了订单支付,订单支付时状态为支付中,完成后支付后,等待支付系统的回调,但是这个时候,A平台的回调API接口异常了,订单状态无法同步为已支付状态,这个时候客户看到订单的金额支付出去了,但是去搜索订单模块的时候发现还是未支付,于是反馈给了客服,开发部经过一段时间的问题定位与排查,发现是回调API挂了于是重启后,数分钟订单状态就同步成已完成了。


BASE理论
基本可用(Basically Available) 分布式系统在出现不可预知故障时,允许损失部分可用性
软状态(Soft state) 允许系统中的数据存在中间状态,并认为该中间状态的存在不会影响系统的整体可用性
最终一致性(Eventually consistent) 系统中所有的数据副本,在经过一段时间的同步后,最终能够达到一个一致的状态

  

从上面的例子来看,支付中就是软状态,回调API服务虽然挂了,但是前台系统还是可以提供给客户端查询使用就是基本可用,只不过订单状态不对,当然最后服务也恢复后达成数据最终一致性

 

分布式数据一致性方案

名称

场景

优点

缺点

异步请求/回调

跨网络环境、同网络环境

实现简单

强业务

TCC

跨网络环境、同网络环境

有现成的框架、实现简单

强业务

基于消息可靠的最终一致性

同网络环境

有现成的框架、通用性强

中间件依赖

  

分布式事务方案常见的主要有这几种:异步请求/回调、TCC、基于消息可靠的最终一致性,TCC与基于消息可靠的最终一致性在Java和.Net都是有现成的框架,而异步请求/回调更多是与支付机构对接的场景会比较多,实现简单、通用性强,如果团队技术能力不足也可以使用该方案代替。

  

异步请求/回调更多是应对并发处理的异步解决方案,查过相关资料并没有纳入相关分布式事务方案中,但是在我的实际工作经验中该方案也是可以达成最终一致性。


异步请求/回调


image.png

该方案在与支付机构对接的场景比较常见,其核心以业务发起请求,被调用端以数据优先入库,稍后异步处理,处理完成后则回调请求业务端提供的API。

  

这种异步处理方式一般获取结果的方式推拉结合,外部系统主动回调给本地称之为推,本地系统每隔一段时间主动查询外部系统结果称为拉,两者可以按照业务的时效性结合策略使用。

     

公司内部系统之间也可以这么做,业务系统请求对接系统,被请求后数据库直接入库,然后通过定时调度任务异步做业务处理,业务处理成功还是失败都修改状态,最后由回调调度任务把业务处理的状态、处理信息回调给业务系统的回调API,为了避免回调调度任务因故障无法回调,可以设置策略由业务系统主动查询对接系统提供的查询API,推拉结合保证了系统可用性和数据时效性。


TCC


image.png

  

TCC是Try、Comfirm、Cancel三个单词的缩写,Try是资源预留、锁定,Comfirm是确认提交,Cancel是指撤销。 一个资源的处理需要提供三个接口,从业务侵入性来看是比较强的。

  

TCC的执行步骤与2PC有点相似,先进入预提交阶段,对A、B、C三个资源的分别进行try处理,如果try请求成功,相应的资源就会被修改成中间状态,可以理解成被冻结。接下来就会根据每个资源try后的情况判断如何执行。如果全部try成功,则会进入Comfirm处理,只要能try成功就能Comfirm成功。如果其中一个资源try失败了,则会对所有进行Cancel处理。

  

TCC与2PC看起来相似,但还是有区别的,TCC是应用服务层面的,而2PC则是基础设施层,而2PC因为是强一致性基于遵守ACID,在事务未提交时处于阻塞状态,如果失败则会事务回滚,而TCC是没有事务回滚的,每个阶段处理都穿透到数据库都是Commit操作。


基于消息的最终一致性


image.png


该方案其实是ebay多年前提出的本地消息表的解决方案,该方案的核心点在于,执行本地事务后再提交队列消息,这两步骤操作因为非原子性的跨进程操作,因为需要保证发送到消息队列的消息能正常发布与正常的消费,这就是我们常说的保证消息可靠,那么在执行本地事务的时候,本地业务表与消息凭据表会作为一个原子性事务提交到数据库,消息凭据表会记录着消息队列的消息序列化数据,如果本地事务提交成功了,但是发送消息队列的时候失败了,就会通过后台线程(进程)查询消息凭据表,把未发送成功的消息反序列化出来重新发起。

  

无论再消息发布端还是消息消费端都会因为与消息队列交互后,修改消息凭据表状态的情况,如果与消息队列交互是正常的,但是修改消息凭据状态失败了,补偿服务仍然会进行不必要的重发,那么这个场景容易导致数据重复创建与覆盖,因此需要关注幂等性的处理了。

  

该方案在.Net有CAP这个分布式事务框架,无需开发人员自己自己实现。


幂等性

  

幂等性的定义,相同的参数在同一个方法里,无论执行一次还是多次都会响应相同的结果

  

举个例子银行转行,A银行账户扣了100元,B银行账户加100元,这样数据一致的。但是在给B账户加100元的时候,B银行系统处理超时,但是其实这个时候B银行是已经处理成功了,只不过没响应回去,那么A银行系统就会重发,如果没有幂等性处理的话,A重试了3次,B账户就会加3次100。一边扣100,一边加300,那么数据就不一致了。

  

对于查询和删除数据的场景都有天然的幂等性,那么我们考虑幂等性处理更多是关注于新建数据更新数据。

  

新建数据的场景,如果没有处理好幂等性,那么就会导致数据重复创建,原因有可能是用户连续点击后发起请求,也有可能是API网关的retry请求。解决方案也相对比较简单,API提供主键参数(流水号)传入,就是由调用端预生成主键(流水号)传入API进行请求,API端生成流水与余额扣减作为同一个事务处理。此时如果因为某个原因进行了两次调用,因为第一次创建成功了,第二次则会因为主键的唯一性抛出了异常,这里需要注意的是得捕获到的唯一键异常应处理成执行成功的响应。

  

更新数据的场景,如果没处理号幂等性,可能会因为RPC框架或者API网关的Retry机制导致重复请求,这样就会造成了ABA数据覆盖问题,所谓的ABA就是,第一次请求A数据已经进行写处理了,接着到了第二次请求B数据进行对A数据进行了修改成功了,但是因为第一次请求因为某个原因导致客户端无法接收到响应,因此API网关或者RPC框架进行了重发,所以第三次把A数据又对已有的B数据进行修改覆盖。针对该问题解决方案主要是使用数据版本判断。

 

幂等性处理方案

场景

问题

方案

新建数据

重复创建

由调用端预生成订单号,唯一键约束

更新数据

ABA覆盖问题

添加版本号判断

  

以上两种方法处理方式从数据库层面解决,相对比较简单直接,侵入性比较强,还有一种方案可以从Web框架层面解决,结合Web框架的AOP与Redis判断,每次请求都会附带一个requestID传入到接口,由Filter拦截后Add到Redis。此方案需要引入Redis,从实现上比前面两个相对复杂,但是通用性相对高一些。


结束

  

该篇到这里就结束了,主要总结了平常在分布式系统不得不去面对的问题,虽然大家会通过一些设计,尽可能去避免,但是唯一不变的是需求的变化,因此我们尽可能优先了解各种处理方案,如有遇到就可针对场景选择合适的方案。

目录
相关文章
|
5天前
|
人工智能 Kubernetes 异构计算
大道至简-基于ACK的Deepseek满血版分布式推理部署实战
本教程演示如何在ACK中多机分布式部署DeepSeek R1满血版。
|
27天前
|
存储 缓存 Java
Java中的分布式缓存与Memcached集成实战
通过在Java项目中集成Memcached,可以显著提升系统的性能和响应速度。合理的缓存策略、分布式架构设计和异常处理机制是实现高效缓存的关键。希望本文提供的实战示例和优化建议能够帮助开发者更好地应用Memcached,实现高性能的分布式缓存解决方案。
39 9
|
2月前
|
开发框架 搜索推荐 算法
一个包含了 50+ C#/.NET编程技巧实战练习教程
一个包含了 50+ C#/.NET编程技巧实战练习教程
124 18
|
2月前
|
数据管理 API 调度
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
HarmonyOS Next 是华为新一代操作系统,专注于分布式技术的深度应用与生态融合。本文通过技术特点、应用场景及实战案例,全面解析其核心技术架构与开发流程。重点介绍分布式软总线2.0、数据管理、任务调度等升级特性,并提供基于 ArkTS 的原生开发支持。通过开发跨设备协同音乐播放应用,展示分布式能力的实际应用,涵盖项目配置、主界面设计、分布式服务实现及部署调试步骤。此外,深入分析分布式数据同步原理、任务调度优化及常见问题解决方案,帮助开发者掌握 HarmonyOS Next 的核心技术和实战技巧。
260 76
鸿蒙HarmonyOS应用开发 | 探索 HarmonyOS Next-从开发到实战掌握 HarmonyOS Next 的分布式能力
|
2月前
|
物联网 调度 vr&ar
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
鸿蒙技术分享:HarmonyOS Next 深度解析 随着万物互联时代的到来,华为发布的 HarmonyOS Next 在技术架构和生态体验上实现了重大升级。本文从技术架构、生态优势和开发实践三方面深入探讨其特点,并通过跨设备笔记应用实战案例,展示其强大的分布式能力和多设备协作功能。核心亮点包括新一代微内核架构、统一开发语言 ArkTS 和多模态交互支持。开发者可借助 DevEco Studio 4.0 快速上手,体验高效、灵活的开发过程。 239个字符
243 13
鸿蒙HarmonyOS应用开发 |鸿蒙技术分享HarmonyOS Next 深度解析:分布式能力与跨设备协作实战
|
2月前
|
存储 监控 供应链
微服务拆分的 “坑”:实战复盘与避坑指南
本文回顾了从2~3人初创团队到百人技术团队的成长历程,重点讨论了从传统JSP到前后端分离+SpringCloud微服务架构的演变。通过实际案例,总结了微服务拆分过程中常见的两个问题:服务拆分边界不清晰和拆分粒度过细,并提出了优化方案,将11个微服务优化为6个,提高了系统的可维护性和扩展性。
66 0
|
2月前
|
NoSQL Java Redis
秒杀抢购场景下实战JVM级别锁与分布式锁
在电商系统中,秒杀抢购活动是一种常见的营销手段。它通过设定极低的价格和有限的商品数量,吸引大量用户在特定时间点抢购,从而迅速增加销量、提升品牌曝光度和用户活跃度。然而,这种活动也对系统的性能和稳定性提出了极高的要求。特别是在秒杀开始的瞬间,系统需要处理海量的并发请求,同时确保数据的准确性和一致性。 为了解决这些问题,系统开发者们引入了锁机制。锁机制是一种用于控制对共享资源的并发访问的技术,它能够确保在同一时间只有一个进程或线程能够操作某个资源,从而避免数据不一致或冲突。在秒杀抢购场景下,锁机制显得尤为重要,它能够保证商品库存的扣减操作是原子性的,避免出现超卖或数据不一致的情况。
87 10
|
3月前
|
消息中间件 开发框架 .NET
.NET 8 强大功能 IHostedService 与 BackgroundService 实战
【11月更文挑战第7天】本文介绍了 ASP.NET Core 中的 `IHostedService` 和 `BackgroundService` 接口及其用途。`IHostedService` 定义了 `StartAsync` 和 `StopAsync` 方法,用于在应用启动和停止时执行异步操作,适用于资源初始化和清理等任务。`BackgroundService` 是 `IHostedService` 的抽象实现,简化了后台任务的编写,通过 `ExecuteAsync` 方法实现长时间运行的任务逻辑。文章还提供了创建和注册这两个服务的实战步骤,帮助开发者在实际项目中应用这些功能。
122 0
|
3月前
|
运维 NoSQL Java
后端架构演进:微服务架构的优缺点与实战案例分析
【10月更文挑战第28天】本文探讨了微服务架构与单体架构的优缺点,并通过实战案例分析了微服务架构在实际应用中的表现。微服务架构具有高内聚、低耦合、独立部署等优势,但也面临分布式系统的复杂性和较高的运维成本。通过某电商平台的实际案例,展示了微服务架构在提升系统性能和团队协作效率方面的显著效果,同时也指出了其带来的挑战。
120 4
|
4月前
|
NoSQL Java Redis
开发实战:使用Redisson实现分布式延时消息,订单30分钟关闭的另外一种实现!
本文详细介绍了 Redisson 延迟队列(DelayedQueue)的实现原理,包括基本使用、内部数据结构、基本流程、发送和获取延时消息以及初始化延时队列等内容。文章通过代码示例和流程图,逐步解析了延迟消息的发送、接收及处理机制,帮助读者深入了解 Redisson 延迟队列的工作原理。