how to fix distributed transation
分布式事务中的概念众多,解决方案也很多。
怎么样去理解, 怎么使用
知识点
硬性事务:单机数据库事务,分布式数据库事务。如 OceanBase,TiDB.
柔性事务:针对 硬性事务而言,规避硬性事务实现的难度和问题,可以达到最终一致性的解决方案。如 XA多阶段提交, Sags长事务, 本地事务表, 外部事务表(可靠消息)。
最近在公司 SOA化的过程中,遇到了分布式事务的问题,分布式事务中涉及概念众多,如ACID,CAP,BASE。
解决方案: XA多阶段提交, Sags长事务, 本地事务表, 外部事务表(可靠消息)。
但是 具体在项目中怎么使用,很难得出肯定的答案。
OK 我来试着分析一下
举个做菜的场景,比较容易解释(我不会承认我是个吃货)。
假设我现在要烹饪 “分布式事务”这道菜,这道菜我不做怎么办,正常的思路是去找菜谱,然后我们找到了 猪肉,牛肉,鸡肉,鱼的菜谱。
但是 由于分布式事务的复杂性, 这个 锅里的 “分布式事务” 是一个猪肉,牛肉,鸡肉,鱼的混合体,虽然有了菜谱 , 你知道这道菜咋做么?
写到这,我谈谈对 做菜的理解。 遇到这种情况 考验的是 一个厨师对食材的理解,厨师的经验,进而推导出烹饪的方法。
现在 我们试着来分析一下 “分布式事务”这道食材
食材的理解
分布式事务的出生
让我们从分布式的出现开始推导.
为什么会有分布式的出现, 因为 单机的硬件的导致单机的 磁盘,CPU,网络IO有限制。在单机无法无限扩展,而计算的需求无限增长的现实情况,不得已做出的妥协。
原来单机事务的原理是 先写到缓存中 缓存中处理成功后再提交到disk上.
分布式设计的出现 导致了 数据空间上的隔离 ,原来单机
DB的事务方案 不能使用,产生了分布式事务。
ACID 在分布式中的演变方案
分布式数据库: shard disk 的RDMA方案,技术难度高
XA 二阶段提交,是通过阻塞实现,对性能有较大影响。
单机
DB的事务方案 不能使用的处理事务 ,而现有的分布式ACID解决方案有缺陷,也不能使用。
目前来看,分布式事务没有较好的通用方案,业界提出针对不同业务的一致性要求,采用不同的方法.
烹饪方法
这里 试着对 常用的事务处理方案( Sags长事务, 本地事务表, 外部事务表(可靠消息)) 做一个分析。
当我了解了这些解决方案后有如下疑问
这些个方案 在什么情况下使用?
如此多的方案,有没有一个方法能够理解这些方案找出一些共性的东西?
因为数据空间的隔离 导致 分布式事设计下的事务只能用RPC来处理。
这种情况下处理方式只能有以下几种
- 协商处理,互相让步
- 中间人调停
- 失败了重试
此时
业务要求强一致性的:Sags,TCC,可靠消息模式
业务要求最终一致性的:最大努力交付,外部事件表(写临时数据,定时任务驱动)。
业务要求弱一致性的:消息通知
然后根据业务要求的强弱来设计处理方案。
通常一个事务的处理流程如下
发生数据不一致-> 通过 catch 捕捉 编程式重试 ,或交给外部程序自动重试 -> 服务接受请求重新处理,或修复。
发生数据不一致 :发生了 数据不一致的事件,可简称为事件源
通过 catch 捕捉 编程式重试 ,或交给外部程序自动重试: 动作的实现方式
服务接受请求重新处理,或修复: 修复数据
通过上面的分析
可以 得出结论 分布式事务的要素
event:事件源 action:动作 fix:修复
level:一致性要求级别
event
- 要处理 异常问题
- 抛出异常
- 通过主动计算发现数据不一致
action:
- 编程式: try-catch
- 定时:定时任务
- 延时操作: 延时任务, 延时消息
- 消息队列:mq消息
fix:
- 重试
- 回滚
level:
- 强
- 中
- 弱
实现过程:
由于不一致 产生 事件源(event),动作(action)处理事件源进行修复(fix),然后根据业务的一致性需求级别(level)选择合适的实现方案。
分布式事务中经常提到的还有幂等 和异步化
异步化
异步化是程序处理逻辑的优化,由于SOA过程中, 很多本地调用的方法变成了异步
在分布式事务解决方案中 根据业务 一致性强弱的需求,
采用了异步的的方式。
幂等
幂等实现方案
不需要幂等,对其他业务无影响
外部事物表:写入一条有状态标识的数据,通过重试 更新状态
实现可查询模式:依赖
唯一ID+存储,
具体的逻辑有 直接查询,前置状态判断, 写入主键duplicate 异常判断。
分布式锁:依赖
唯一ID+存储。 实现方式有 zookeeper,redis,db等
怎么理解,怎么用
我问过很多童鞋,分布式事务的解决方案 大多回答 重试+幂等。 为什么呢?
重试+幂等是处理分布式事务方法之一,简单易用,方便理解,so大部分的人回答都是如此。
在系统的演化过程中,幂等是从多个方法调用中抽出一个方法做成了服务时使用的方案,并没有考虑业务整体对一致性的要求。
只要认真想一下 就会发现重试+幂等 不能解决所用的问题,理解背后的原理尤其重要
对应我提出的EAF理论,
幂等是EAF中 fix 的补充,重试是Action的实现。
厨师的经验
场景:
数据同步: 写临时数据,通过定时任务驱动
两个银行转钱: 可靠消息
支付帐务:TCC
案例:
下单过程中调用积分服务,优惠券服务,发生异常调用回滚接口,并发送MQ,积分服务,优惠券服务方接到MQ后进行核对。
订单生产库与订单展示库 数据同步方案,写入一条临时数据,标识状态flag=0,通过定时任务驱动, 同步成功,flag=1。
主生产流程中 生成多条任务数据,定时任务驱动 主流程写订单生产,分支写订单中心。
订单生产中间项目MQ写订单状态记录。关联系统订阅。
总结:
写在最后: 解决分布式事务重要的是 理解原理,不断积累项目经验,本人水平有限,写此文章,目的在于抛砖引玉,文中如有谬误,请不吝赐教。