分布式事务- TCC编程式模式

一、前言

严格遵守ACID的分布式事务我们称为刚性事务,而遵循BASE理论(基本可用:在故障出现时保证核心功能可用,软状态:允许中间状态出现,最终一致性:不要求分布式事务打成中时间点数据都是一致性的,但是保证达到某个时间点后,数据就处于了一致性了)的事务我们称为柔性事务,其中TCC编程模式就属于柔性事务,本文我们来阐述其理论。

二、TCC编程模式

TCC编程模式本质上也是一种二阶段协议,不同在于TCC编程模式需要与具体业务耦合,下面首先看下TCC编程模式步骤:

  • 所有事务参与方都需要实现try,confirm,cancle接口。
  • 事务发起方向事务协调器发起事务请求,事务协调器调用所有事务参与者的try方法完成资源的预留,这时候并没有真正执行业务,而是为后面具体要执行的业务预留资源,这里完成了一阶段。
  • 如果事务协调器发现有参与者的try方法预留资源时候发现资源不够,则调用参与方的cancle方法回滚预留的资源,需要注意cancle方法需要实现业务幂等,因为有可能调用失败(比如网络原因参与者接受到了请求,但是由于网络原因事务协调器没有接受到回执)会重试。

  • 如果事务协调器发现所有参与者的try方法返回都OK,则事务协调器调用所有参与者的confirm方法,不做资源检查,直接进行具体的业务操作。

  • 如果协调器发现所有参与者的confirm方法都OK了,则分布式事务结束。
  • 如果协调器发现有些参与者的confirm方法失败了,或者由于网络原因没有收到回执,则协调器会进行重试。这里如果重试一定次数后还是失败,会怎么样那?常见的是做事务补偿。

蚂蚁金服基于TCC实现了XTS(云上叫DTS),目前在蚂蚁金服云上有对外输出,这里我们来结合其提供的一个例子来具体理解TCC的含义,以下引入蚂蚁金服云实例:

“首先我们假想这样一种场景:转账服务,从银行 A 某个账户转 100 元钱到银行 B 的某个账户,银行 A 和银行 B 可以认为是两个单独的系统,也就是两套单独的数据库。

我们将账户系统简化成只有账户和余额 2 个字段,并且为了适应 DTS 的两阶段设计要求,业务上又增加了一个冻结金额(冻结金额是指在一笔转账期间,在一阶段的时候使用该字段临时存储转账金额,该转账额度不能被使用,只有等这笔分布式事务全部提交成功时,才会真正的计入可用余额)。按这样的设计,用户的可用余额等于账户余额减去冻结金额。这点是理解参与者设计的关键,也是 DTS 保证最终一致的业务约束。”

在try阶段并没有对银行A和B数据库中的余额字段做操作,而是对冻结金额做的操作,对应A银行预留资源操作是对冻结金额加上100元,这时候A银行账号上可用钱为余额字段-冻结金额;对应B银行的操作是对冻结金额上减去100,这时候B银行账号上可用的钱为余额字段-冻结金额。

如果事务协调器调用银行A和银行B的try方法有一个失败了(比如银行A的账户余额不够了),则调用cancle进行回滚操作(具体是对冻结金额做反向操作)。如果调用try方法都OK了,则进入confirm阶段,confirm阶段则不做资源检查,直接做业务操作,对应银行A要在账户余额减去100,然后冻金额减去100;对应银行B要对账户余额字段加上100,然后冻结金额加上100。

最关心的,如果confirm阶段如果有一个参与者失败了,该如何处理,其实上面操作都是xts-client做的,还有一个xts-server专门做事务补偿的。

三、总结

TCC是对二阶段的一个改进,try阶段通过预留资源的方式避免了同步阻塞资源的情况,但是TCC编程需要业务自己实现try,confirm,cancle方法,对业务入侵太大,实现起来也比较复杂。

最后

想了解JDK NIO和更多Netty基础的可以单击我
想了解更多关于粘包半包问题单击我
更多关于分布式系统中服务降级策略的知识可以单击 单击我
想系统学dubbo的单击我
想学并发的童鞋可以 单击我
想了解SpringBoot核心模块原理的 单击我

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
tc C程序最好的编程工具 阶乘的推导(郭先强) 下面以精确计算 1000! 为例,阐述该算法: 记 F1(n) = n*(n-1)*...*1; F2(n) = n*(n-2)*...*(2 or 1); Pow2(r) = 2^r; 有 F1(2k+1) = F2(2k+1) * F2(2k) = Pow2(k) * F2(2k+1) * F1(k), F1(2k) = Pow2(k) * F2(2k-1) * F1(k), 及 Pow2(u) * Pow2(v) = Pow2(u+v), ∴ 1000! = F1(1000) = Pow2(500)*F2(999)*F1(500) = Pow2(750)*F2(999)*F2(499)*F1(250) = Pow2(875)*F2(999)*F2(499)*F2(249)*F1(125) = Pow2(937)*F2(999)*F2(499)*F2(249)*F2(125)*F1(62) = Pow2(968)*F2(999)*F2(499)*F2(249)*F2(125)*F2(61)*F1(31) = Pow2(983)*F2(999)*F2(499)*F2(249)*F2(125)*F2(61)*F2(31)*F1(15) = ... 如果你预存了某些小整数阶乘(比如这里的“F1(15)”),则可提前终止分解,否则直至右边最后一项为“F1(1)”为止;这样,我们将阶乘转化为2的整数次幂与一些连续奇数的积(或再乘以一个小整数的阶乘); 再定义:F2(e,f) = e*(e-2)*...*(f+2),这里仍用“F2”,就当是“函数重载”好了:), 则 F2(e) = F2(e,-1) = F2(e,f)*F2(f,-1) (e、f为奇数,0≤f≤e) ∴ F2(999) = F2(999,499)*F2(499,249)*F2(249,125)*F2(125,61)*F2(61,31)*F2(31), F2(499) = ____________F2(499,249)*F2(249,125)*F2(125,61)*F2(61,31)*F2(31), F2(249) = ________________________F2(249,125)*F2(125,61)*F2(61,31)*F2(31), F2(125) = ____________________________________F2(125,61)*F2(61,31)*F2(31), F2( 61) = _______________________________________________F2(61,31)*F2(31), F2( 31) = _________________________________________________________F2(31), ∴ F1(1000) = F1(15) * Pow2(983) * F2(999,499) \ * [F2(499,249)^2] * [F2(249,125)^3] \ * [F2(61,31)^4] * [F2(31)^5] 这样,我们又将阶乘转化为了乘方运算。 上实际上是个形如 a * b^2 * c^3 * d^4 * e^5 的子;我们再将指数转化为二进制,可得到如下公: a * b^2 * c^3 * d^4 * e^5 = (a*c*e)*[(b*c)^2]*[(d*e)^4] = (((e*d)^2)*(c*b))^2*(e*c*a), 即可转化成了可充分利用高效的平方算法。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值