分布式事务--TCC优化方案

方案核心:TCC+事务消息+异常日志+人工介入

1 前言

分布式事务是分布式领域一大神坑。
架构即取舍、衡量利弊,世上没有完美的方案。无需过多转牛角尖,无需纠结,以免进入死胡同。

1.1什么是分布式事务

简单的讲,N个服务调用,要么同时成功,要么同时失败。
简单的讲,垮N个库,要么同时成功,要么同时失败。
数据库事务-》强一致性
分布式事务-》性能、可用性方面的考量,最终一致性
分布式环境中通信存在三种状态:success failure timeout,超时是最麻烦的
最基本要求:事务参与者要实现幂等性,简单的讲,就是多次提交依然能够达到同样的目的,数据状态的预期都是一致的
怎么实现幂等性?说白了就是去重,可借助业务id来进行校验,可用的工具有redis、db

1.2什么场景下需要分布式事务

能不用尽量不用。

2 实现分布式事务的几种方案

2.1 2PC

数据库层面,强一致性

第一阶段:协调者向所有事务参与方询问,都可以提交吗?所有参与方锁定资源,如果全部say yes,则想所有参与方发布提交命令。否则发布rollback命令。
第二阶段:大家一起提交或回滚

同步问题:大家都处于阻塞状态,协调者挂了,故障转移,需要阻塞的时间更长
超时问题:如果参与方超时了,还没接收到协调者的指令怎么办?傻傻的原地等待?这样也可能导致不一致

2.2 3PC

为了解决2PC阶段存在的超时、宕机等问题,加入一个precommit阶段,如果超时,则自动提交。方案基本用不到,不过多啰嗦展开。

2.3 TCC

Try-Confirm-Cancel的简称,是一种达到最终一致性的补偿性事务,跟2PC有点像,TCC针对的是业务层面,并非数据库层面。

在try阶段只是保留资源,执行业务锁定;
confirm阶段:当发起者收到所有请求者try success应答,向协调者发出confirm。

如果出现超时,或者failure响应的,则发出cancel指令。

协调者负责统一协调所有事务参与者进行confirm、cancel指令。

缺点:状态复杂,导致在业务开发过程中,复杂度上升,状态处理更麻烦。
协调者是一个关键角色,怎么保证协调者是高可用?

2.4 saga

image

该中心节点,即协调器知道整个事务的分布状态,相比于无中心节点方式,该方式有着许多优点:
能够避免事务之间的循环依赖关系。
参与者只需要执行命令 / 回复 (其实回复消息也是一种事件消息),降低参与者的复杂性。
开发测试门槛低。
在添加新步骤时,事务复杂性保持线性,回滚更容易管理。因此大多数 saga 模型实现均采用了这种思路。
总结一下:SAGA 模型的优点在于其降低了事务粒度,使得事务扩展更加容易,同时采用了异步化方式提升性能。但是其缺点在于很多时候很难定义补偿接口,回滚代价高,而且由于 SAGA 在执行过程中采用了先提交后补偿的思路进行操作,所以单个子事务在并发提交时的隔离性很难保证。

2.5 事务消息

rocketmq4.3支持事务消息,简单的讲,就是保持本地事务与消息发送的原子性。再简单的讲,就是我本地事务做完了,消息一定100%发送出去。

1、发送方:先往half队列发prepare消息
2、发送方:执行本地事务
3、发送方:如果commit,就发生commit消息,下发给订阅者;如果rollback就发生rollback消息,删除prepare,不下发。
4、rocketmq:如果没有接收到任何信息,可能超时啦,出了各种异常,咋办?回查事务状态,有可能发送方实例已经宕机,需要回查同一个生产者组的其他实例来获取状态,具体怎么获取?参考rocketmq的事务消息示例代码即可。
5、consumer段消息成功机制保障
对于消费者集群执行本地事务失败的情况,阿里提供给我们的解决方法是:人工解决
按照事务的流程,因为某种原因事务失败,那么需要回滚整个流程。如果消息系统要实现这个回滚流程的话,系统复杂度将大大提升,且很容易出现Bug,估计出现Bug的概率会比消费失败的概率大很多。

事务消息一定程度上也实现了分布式事务,适用于上游业务不需要下游响应的场景。发给事务消息就完事了。订阅者根据消息做下游业务。失败时人工介入。

2.6 分布式数据库

解决分布式事务的最好方案就是不解决,交给分布式数据库,天下大事,分久必合合久必分。以前大家费了老大劲把数据库拆开,现在技术条件逐渐成熟。陆续出现了几个分布式数据库,首推google的spanner全球分布式数据库,天然支持分布式事务。
基于google F1 spanner论文实现的分布式数据库有:TIDB、cockroachdb发展的都不错,1w+star可以持续关注,在国内也有诸多落地实现的。

3 TCC方案详解

3.1 角色

发起者、协调者、参与者


tcc.png

在上述例子中,bookingprocess即为发起者A,swiss B、easyjet C为参与者。

3.2 各个角色职责

发起者负责try,根据结果,向协调者发送confirm、cancel指令。

参与者实现try、confirm、cancel三个接口;
实现幂等性;
超时自动cancel。

协调者保证高可用,接收发起者的指令,根据情况发起confirm 、cancel,失败重试。

3.3 主流程

1、外部前端调用booking A,A调B\C服务的try接口,
2、B\C服务返回response给A,有几种情况:所有响应均为success;响应含有failure;B、C调用失败,不可用,或者超时。
3、如果所有请求均为success,则向协调者发出confirm指令,大家一起提交。消息中包含了B\C服务的confirm URL。
4、如果响应包含failure,则向协调者发出cancel指令,大家一起回滚。

4 TCC进化

4.1 TCC的缺陷

1、协调器如何保证高可靠,怎么解决协调器的单点故障?怎么解决服务宕机、网络抖动,超时等问题
2、开发复杂,参与者需要提供try、confirm、cancel接口
3、如果所有的可靠性措施都失灵了,还是有异常情况,怎么处理?
4、resttcc对接口做了一些约束,并不符合实际要求,例如用httpcode来标识各种状态,而很多项目团队一般在数据包中定义返回状态。

4.2 rocketmq事务消息登场

TCC方案中的交互模式皆为rest接口,在性能、可靠性方面不如消息的发布订阅模式,rocketmq4.3支持事务消息,那么我们可以让rocketmq担任协调者的角色。
当然你首先要先能玩转rocketmq,能保证高可用,不是随便搭个玩玩就行了。

怎么改进?
一、try阶段还是rest调用。
事务发起者发送两条事务消息一条消息体为commit,另一条为cancel,在接收到所有参与者的response后,根据返回的状态进行相应处理:
1、如果所有的参与者都返回success(怎么样标识success大家遵循统一的约定),标识“commit”事务消息的状态为commit,cancel直接丢弃即可
2、如果含有failure,则标识“cancel”事务消息的状态为commit,则cancel事务消息生效,另一台直接丢弃
3、如果超时了,或者发起者当前实例宕机等等异常因素,这时候不用处理都可以,大家想想为什么?

二、confirm阶段
各个参与者无需实现confirm、cancel restfu接口
需要去订阅事务消息队列,监听commit或者cancel消息

如果订阅到commit消息,那就是标识try阶段,大家都已经成功锁定资源了。那就大家都来commit吧

流程走到这里,大家都已经锁定资源的前提下,commit出现异常的概率已经非常低了。
但是如果真的出现异常,commit失败怎么办?怎么办?怎么办?
再通知发起者,再发起cancel消息,再大家一起cancel,如果有人cancel失败怎么办?怎么办?怎么办?
死循环了,果断跳出这个定时思维,这时候需要记录异常日志,人工介入处理。不要什么都自动化,架构即取舍,孰重孰轻,掂量一下就知道了。
三、异常日志体系
服务如果commit失败,或者超时自动cancel等等,都记录异常日志到业务数据库,同时把异常日志推送到kafka->elk,结合链路监控日志、应用日志、业务异常日志进行综合处理,人工介入。

四、cancel阶段
如果订阅到cancel消息,那就表明发起者让大家一并cancel,释放资源,做业务补偿处理
cancel完,把日志推送到kafka-》elk-》人工综合分析

4.3 异常日志体系的建立

方案可以采用业务异常日志(业务DB存储一份)+kafka+ELK。
关联聚合分析:根据traceid进行聚合分析,异常日志+链路监控+应用日志。

以便人工介入做最后的一环保障

参考资料

TCC英文文档、github开源TCC方案、ACID、CAP原理、rocketmq4.3事务消息的实现机制https://mp.weixin.qq.com/s/rE6l2iWY2lGxDCcog7Muvw

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容