2PC的问题

2PC简介

说到分布式事务,就会提到2pc。2pc是什么,我这里简要说明一下。网上文章实在太多。就不画图详细阐述了。

2pc涉及到2个阶段,3个操作:

阶段1:“准备提交”。事务协调者向所有参与者发起prepare,所有参与者回答yes/no。

阶段2:“正式提交”。如果所有参与者都回答yes,则向所有参与者发起commit;否则,向所有参与者发起rollback。

因此,要实现2pc,所有参与者,都得实现3个接口:prepare/commit/rollback。

2PC的实现

关于2pc,对应的实现层面,也就是XA协议。有一个Atomikos开源库,也实现了这个协议。有兴趣的可以去看一下如何使用。

2PC的问题

(1)阶段2,事务协调者挂了,则所有参与者接受不到commit/rollback指令,将处于“悬而不决”状态

(2)阶段2,其中一个参与者超时或者出错,那其他参与者,是commit,还是rollback呢? 也不能确定

为了解决2pc的问题,又引入3pc。3pc有类似的挂了如何解决的问题,因此还是没能彻底解决问题,此处就不详述了。

TCC

为了解决SOA系统中的分布式事务问题,支付宝提出了TCC。2PC通常都是在跨库的DB层面,而TCC本质就是一个应用层面的2PC。

同样,TCC中,每个参与者需要3个操作:Try/Confirm/Cancel,也是2个阶段。

阶段1:”资源预留/资源检查“,也就是事务协调者调用所有参与者的Try操作

阶段2:“一起提交”。如果所有的Try成功,一起执行Confirm。否则,所有的执行Cancel。

TCC是如何解决2PC的问题呢?

关键:Try阶段成功之后,Confirm如果失败(不管是协调者挂了,还是某个参与者超时),不断重试!

同样,Cancel失败了,也是不断重试。这就要求Confirm/Cancel都必须是幂等操作。

下面以1个转账case为例,来说明TCC的过程:

有3个账号A, B, C,通过SOA提供的转账服务操作。A, B同时分别要向C转30, 50元,最后C的账号+80,A, B各减30, 50。

阶段1:A账号锁定30,B账号锁定50,检查C账号的合法性(比如C账号是否违法被冻结,C账号是否已注销。。。)。

所以,对应的“扣钱”的Try操作就是”锁定”,对应的“加钱”的Try操作就是检查账号合法性

阶段2:A, B, C都Try成功,执行Confirm。即A, B减钱,C加钱。如果任意一个失败,不断重试!

从上面的案例可以看出,Try操作主要是为了“保证业务操作的前置条件都得到满足”,然后在Confirm阶段,因为前置条件都满足了,所以可以不断重试保证成功。

1PC

我们知道,在tcc里面,有2个阶段。其中第1个阶段是“锁定资源”,目的是为了保证第2个阶段的提交在业务上不会失败。

而1pc,就是舍弃掉第1个阶段,不做资源锁定,直接进行第2个阶段的提交!如果业务的特性可以允许不需要锁定资源,那就可以省去第1个阶段,直接做第2个阶段。

如果第2个阶段失败呢,有2种策略:策略1,同TCC一样,也是不断重试commit,硬着头皮上;策略2,回滚,也就是事务补偿,做之前操作的反操作。