但是3PC仍然存在类似2PC的问题,即最后阶段失败或超时同样有可能出现数据不一致的问题。所以3PC仍然只是降低了发生概率,并没有真正解决问题。
XTS工业界的对分布式事务的应用是如何呢?可以参考某宝的知名分布式框架XTS。
XTS本质上是2PC(实际上如果引入3PC会多2n次网络交互,在量大时反而更加不安全)。XTS引入协调者A的server部分,实际上是一个大集群,以配置的方式接入各种需要分布式事务的业务,集群由专门的团队维护,保证其可用性和性能;而协调者A的client部分则通过发起方调用,prepare阶段时,先通过client将本次事务信息发送到server,落库,然后即时推送prepare请求到B和C,当收到B,C的响应时把他们状态入库,如果正常,则做commit提交;否则会用定时任务去推送未完成的状态直到完成。上文提到的prepare之后协调者A挂了这种情况,在server集群的保证下,几乎很少会发生。而上文提到的所有超时的情况,都可以通过定时任务推送拿到一个确定的状态而不是盲目的选择回滚或者提交。另外由于B和C都是集群,很少会发生多次请求过去无响应的情况。直到最后一种情况就是commit时B成功了C失败了,或者反过来B失败C成功,这种情况成为悬挂事务,最终等待人工来解决,据说每天都有几笔到几十笔。
无疑XTS作为2PC在工业界的应用,是相当了不起的设计,通过各种方式规避了各种可能的不一致性,在性能,效率等方面做到了平衡。
TCC(Try/Confirm/Cancel)业务补偿类型,其基本思想是对每一个业务操作做一个逆操作,一旦成功了,就做正向业务,一旦失败了就做业务的逆操作。通常在业务逻辑简单并且正逆操作清晰的时候用比较好。
查询补偿典型的场景是向银行发送了转账请求未得到明确的成功失败返回码,此时先做业务结果的查询,根据结果做相应处理,比如查询结果成功,则置状态为成功,查询结果失败,则做相应的业务补偿,查询结果为未知,则继续查询。
消息事务及消息重试事务消息及消息重试本质上都是将一些通用的事务交给消息中间件,通过消息中间件来保证消息的最终一致性。
事实上,消息事务解决了这类问题,即本地事务和消息应当有一致性,解决这个一致性比较麻烦,比如消息中间件和业务同时实现XA;或者采用一些更加复杂的方式,比如将消息表与业务表放同库,利用数据库的事务来保证一致性,而消息系统只需要轮训该消息表即可;当然,也有消息的二阶段提交+补偿的方式。消息事务解决了消息发起方,即生产者与消息中间件之间的一致性问题。
try{ //数据库操作 //消息投递 }catch(Exception e){ //回滚 }消息中间件与消费者之间的一致性问题则需要通过重试+幂等来解决。消息重试中主要考虑重试次数以及重试时间的阈值变化。
最后我这边整理了一份:Zookeeper相关资料,Java核心知识点(包括Spring全家桶系列、面试专题和20年最新的互联网真题、电子书等)有需要的朋友可以关注公众号【程序媛小琬】即可获取。