分布式事物的设计与实践

共 4535字,需浏览 10分钟

 ·

2021-04-01 02:39

点击上方蓝色字体,选择“标星公众号”

优质文章,第一时间送达

  作者 |  彼岸舞

来源 |  urlify.cn/VbaYNv

数据一致性定义

  • 任何人

  • 任何时间

  • 任何地点

  • 任何接入方式

  • 任何服务

  • 数据都是一致的

数据不一致产生的原因

  • 数据分散在多处

    • 多个DB

    • DB和缓存

  • 二手交易平台案例

    • 用户,交易,商品等功能

分布式事物产生的原因

刚开始是一个单体进程

经过演变,单体式服务演变成微服务,每个服务都是单独的进程

在用户请求量大的时候,为了缓解数据库的压力,添加了分布式缓存

分布式事物案例

电商平台购买商品

下单->减库存->支付

这就是分布式事物问题,当APP要买东西,这个操作会涉及到多个服务,意味着要操作多个数据库,这样本地事物就无法保证数据的一致性,所以就产生了分布式事物问题.

分布式事物场景

  • 电商下单场景

    • 下单

    • 发送消息到MQ

  • 一致性保证

    • 本地事物

      • 下单操作

      • 发送MQ消息操作

      • 放进一个本地事物

上述做法有什么问题?

问题:如果发送消息超时了,你是不知道MQ的返回结果是成功和失败的,,timeout这操作不是一个原子的

 

分布式事物分类

  • 刚性分布式事物

    • 强一致性

    • XA模型

    • CAP

      • CP

  • 柔性分布式事物

    • 最终一致性

    • CAP,BASE理论

      • AP

刚性分布式事物

满足传统事物特性

ACID( Atomicity-原子性, Consistency-一致性,Isolation-隔离性,Durability-持久性)

XA模型

  • XA是X/Open CAE Specification(Distributed Transaction Processing)模型中定义,XA规范由AP,RM,TM组成

  • 其中应用程序(Application Program简称AP),AP定义事物边界(定义事物开始和结束)并访问边界事物内的资源

  • 资源管理器(Resource Manager简称RM),RM管理计算机共享的资源,资源及数据库等

  • 事物管理器(Transaction Manager,简称TM),负责管理全局事物,分配事物唯一标识,监控事物的执行进度,并负责事物的提交,,回滚,失败恢复等

2PC(两阶段提交-XA规范标准实现)

  • 案例

    • 组织爬山

  • 过程

    • 二阶段提交,是XA规范的标准实现

    • TM发起prepare投票

    • RM都同意后,TM再发起Commit

    • Commit 过程出现宕机等异常,节点服务重启后,根据XA recover 再次进行commit补偿

  • 缺点

    • 同步阻塞模型

    • 数据库资源锁定时间过长

    • 全局锁(隔离级别-串行化),并发低

    • 不适合长事物场景

柔性分布式事物

  • CAP

    • 分布式环境下P一定需要,CA权衡折中

  • BASE理论

    • Basically Available-基本可用

    • Soft state 柔性状态

    • Eventual consistency 最终一致性

  • 架构思考

    • 柔性事物是对XA协议的妥协,他通过降低强一致性要求,从而降低数据库资源锁定时间,提升可用性

  • 架构经典实现

    • TCC模型

    • Saga模型

 

TCC模型

  • Try-confirm-cancel

  • TCC模型完全交由业务实现,每个子业务都需要实现Try-Confirm-cancel接口,对业务侵入大

    • 资源锁定交由业务方

  • try

    • 尝试执行业务,完成所有检查,预留必要的业务资源

  • confirm

    • 真正执行业务,不再做业务检查

  • Cancel

    • 释放Try阶段预留的业务资源

  • 案例

    • 汇款服务,收款服务案例

      • A用户向B用户汇款500元

    • 汇款服务

      • try

        • 检查A账户的有效性,及查看A账户的状态是否为"转账中"或者"冻结"

        • 检查A账户余额是否充足

        • 从A账户中扣减500元,并将状态设置为转账中

        • 预留扣减资源,将从A往B账户转账500元这个事件存入消息或者日志中

      • confirm

        • 不做任何操作

      • cancel

        • A账户增加500元

        • 从日志或者消息中,释放扣减资源

    • 收款服务

      • try

        • 检查B账户是否有效

      • confirm

        • 读取日志或消息,B账户增加500元

        • 从日志或者消息中,释放扣减资源

      • cancel

        • 不做任何操作

Saga模型

  • 起源于1987年Hector & Kenneth发表的论文Sagas

  • Saga模型把一个分布式事物拆分为多个本地事物,每个本地事物都有相应的执行模块和补偿模块(对应TCC中的confirm和cancel)

  • 当Saga事物中任意一个本地事物出错时,可以通过调用相关的补偿方法恢复之前的事物,到达事物最终一致性

  • 当每个Saga子事物T1,T2,....TN都有对应的补偿定义C1,C2,....CN-1,那么Saga系统可以保证

    • 子事物序列T1,T2,.....TN得以完成(最佳情况)

    • 或者序列T1,T2,...TJ,CJ-1,..., C2,C1,0<J<N,得以完成

  • Saga隔离性

    • 业务层控制并发

      • 在应用层加锁

      • 应用层预先冻结资源等

  • Saga恢复方式

    • 向后恢复,补偿所有已完成的事物,如果任意子事物的失败

    • 向前恢复,重试失败的事物,假设每个子事物最终都会成功

 

刚性分布式事物VS柔性分布式事物


刚性事物(XA)

柔性事物

业务改造

回滚

支持

实现补偿接口

一致性

强一致(CP)

最终一致性(AP)

隔离性

原生支持

实现资源锁定接口

并发性能

严重衰退

略微衰退

适合场景

短事物,并发较低

长事物,高并发

我们如何实践

  • 问题通用解决思路

    • 解决这个问题本身

    • 让问题本身消失

      • 圆珠笔笔芯漏油解决

  • 圆珠笔笔芯在写2W次就开始漏油,如果要解决这个问题本身,那么就是加入更好的材料,更高端的技术,如果是让问题本身消失呢,就是固定一个次数,让它只能写1.5W次就没油开始丢弃,这样的两种办法

  • 首选是让问题本身消失,次选是解决这个问题本身

  • 方案一:从业务场景消除分布式事物

    • 思路:核心业务先处理,其他业务异步处理

  • 方案二:柔性分布式事物

柔性分布式事物实践

  • 通用处理思路

    • 本地事物-->短事物

    • 分布式事物-->长事物

    • 转变成多个短事物

    • 案例

      • A[下单]->B[减库存]->C[支付]

        • A->DB1

        • B->DB2

        • C->DB3

        • A/B/C都成功

        • A/B成功,C失败

          • 补偿

  • 业务场景

    • 异步场景

      • 基于MQ消息驱动分布事物

    • 同步场景

      • 基于异步补偿分布

异步场景分布式事物设计

异步场景

商品交易

下单,支付

方案一:业务方提供本地操作成功回查功能

    • 事物消息:MQ提供类似X/Open XA的分布式事物功能,通过MQ事物消息能达到分布式事物的最终一致

    • 半消息:暂不投递的消息,发送方已将消息成功发送到了MQ服务端,但是服务端未收到生产者对该消息的二次确认,此时该消息被标记成"暂不能投递"状态,处于该种状态下的消息即半消息

    • 消息回查:由于网络闪断,生产者应用重启等原因,导致某条事物消息的二次确认丢失,MQ服务端通过扫描发现某条消息长期处于半消息时,主要主动向消息生产者询问该消息的最终状态(Commit或Rollback),即消息回查

  • MQ分布式事物设计方案

  • MQ分布式事物消息设计

    • MQ事物消息设计事物消息作为一种异步确保型事物,将两个事物分支通过MQ进行异步解耦,MQ事物消息的设计流程同样借鉴了两阶段提交理论,整体交互流程如上图

    1. 事物发起方首先发送prepare消息到MQ

    2. 在发送prepare消息成功后执行本地事物

    3. 根据本地事物执行结果返回commit或rollback

    4. 如果消息是rollback,MQ将删除该prepare消息,不进行下发,如果是commit消息,MQ会将消息发送给consumer端

    5. 如果执行本地事物过程中,执行端挂掉,或者超时,,MQ服务器端将不停的询问producer来获取事物状态

    6. consumer端的消费成功机制有MQ保证

  • 成本:

    • MQ需要支持半消息

    • MQ需要提供消息遍历

    • 业务方需要提供回查接口

  • 业务方接入步骤

  • 优点

    • 通用

  • 缺点

    • 业务方需要提供回查接口,对业务侵入大

    • 发送消息非幂等

    • 消费端需要处理幂等

 

方案二:本地事物消息表

  • 本地操作和发送消息通过本地事物强一致性

    • 本地事物操作表

    • 本地事物消息表

      • mqMessages(msgid,content,topic,status)

  • 发送端消息不幂等

    • At least once (最少发一次)

    • Once Only (只发一次)

    • At more once(最多发一次)

  • 消费端处理消息幂等

    • 分布式锁

  • A->B->C

    • A/B成功,C失败

      • 记录错误日志

      • 报警

      • 人工介入

  • 优点

    • 业务入侵小

相比于提供消息回查接口(RockectMQ)来说,实际异步场景还是本地消息事物表使用的比较多

 

同步场景分布式事物设计

  • 同步场景

    • 首页推荐商品列表

      • 商品信息

      • 用户信息

      • 社交信息

    • 购买商品

      • 下单->A

      • 减库存->B

      • 支付->C

通过业务逻辑层驱动

  • 解决方案

    • 基于异步补偿的分布式事物

    • 架构设计的三大关键点

开始记录调用请求的参数,如果失败后基于参数做补偿接口,接口需要保证幂等性

  • 总体架构设计

场景:A下单,B减库存,C支付,在调用接口的时候,A先走Proxy存入事物ID,状态,参数等信息,然后执行本地事物,接着B,C走同样的流程如果都成功,那么事物状态改成2,也就是成功,如果在C失败的时候可以更具参数,事物ID对A,B进行补偿

业务逻辑层Proxy设计(基于AOP实现)

    • 逻辑层调用上加上事物注解@Around("execution(**(..)) && @annotation(TX)")

    • Proxy在真正业务逻辑被调用之前,生成一个全局唯一TXID标示事务组,TXID保存在ThreadLocal变量中,方法开始前写入,完成后清除,并向远端数据库写入TXID并把事务组制成开始状态

    • 业务逻辑层调用数据访问层之前,通过RPCProxy代理记录,当前调用请求参数

    • 如果业务正常,调用完成后,当前方法的调用记录删除或者存档

    • 如果业务异常,查询调用链反向补偿

  • 数据访问层设计

    • 原子接口

    • 补偿接口

      • 谁来提供?

        • 业务方提供

      • 幂等性保证

        • 采用本地资源锁,锁定唯一资源

    • 基于原则接口方法,在方法名加注解标注补偿方法名

    • @Compensable(cancelMethod = "cancelRecord")

  • 分布式事物补偿服务

    • 事物组表(数据库表TDB)    

      • 记录事物组状态

      • txid state timestamp

    • 事物调用组表(数据库表TDB)

      • 记录事物组内的每一次调用,以及相关参数

      • txid actionid callmethod pramatype params

    • 补偿策略

      • 调用执行失败,修改事物组状态

      • 分布式事物补偿服务异步执行补偿

分布式事物成功案例

  • 二手交易创建订单事务组正常流程

    • 锁库存->减红包->创建订单

  • 代理层透明记录调用请求参数

    • 记录事物域的开始与结束

    • 在所有远程调用成功时

    • 对业务逻辑不做侵入

分布式事物失败案例

  • 二手交易创建订单事务组异常流程

    • 微服务数据访问层失败,代理更改事务组状态

    • 微服务业务正常执行

    • 事物补偿服务异步执行补偿







粉丝福利:Java从入门到入土学习路线图

👇👇👇

👆长按上方微信二维码 2 秒


感谢点赞支持下哈 

浏览 19
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报
评论
图片
表情
推荐
点赞
评论
收藏
分享

手机扫一扫分享

分享
举报