欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

大话分布式事务-方案篇

程序员文章站 2022-05-31 13:07:08
...
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来处理。
这种情况下处理方式只能有以下几种
  1. 协商处理,互相让步
  2. 中间人调停
  3. 失败了重试
此时
业务要求强一致性的:Sags,TCC,可靠消息模式
业务要求最终一致性的:最大努力交付,外部事件表(写临时数据,定时任务驱动)。
业务要求弱一致性的:消息通知
然后根据业务要求的强弱来设计处理方案。
 
通常一个事务的处理流程如下
发生数据不一致-> 通过 catch 捕捉 编程式重试 ,或交给外部程序自动重试 -> 服务接受请求重新处理,或修复。
发生数据不一致 :发生了 数据不一致的事件,可简称为事件源
通过 catch 捕捉 编程式重试 ,或交给外部程序自动重试: 动作的实现方式
服务接受请求重新处理,或修复: 修复数据
通过上面的分析
可以 得出结论 分布式事务的要素
event:事件源 action:动作 fix:修复 level:一致性要求级别
event
  1. 要处理 异常问题
  2. 抛出异常
  3. 通过主动计算发现数据不一致
 
action:
  1. 编程式: try-catch
  2. 定时:定时任务
  3. 延时操作: 延时任务, 延时消息
  4. 消息队列:mq消息
fix:
  1. 重试
  2. 回滚
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写订单状态记录。关联系统订阅。
 
总结:
写在最后: 解决分布式事务重要的是 理解原理,不断积累项目经验,本人水平有限,写此文章,目的在于抛砖引玉,文中如有谬误,请不吝赐教。