分布式事务浅析

个人学习分布式事务的总结,引用了很多优秀文章的阐述。如有版权问题,请告知。

事务的特点

事务拥有以下四个特性,习惯上被称为ACID特性。

  1. 原子性(Atomicity):事务作为一个整体被执行,包含在其中的对数据库的操作要么全部被执行,要么都不执行。
  2. 一致性(Consistency):事务应确保数据库的状态从一个一致状态转变为另一个一致状态。一致状态是指数据库中的数据应满足完整性约束。除此之外,一致性还有另外一层语义,就是事务的中间状态不能被观察到(这层语义也有说应该属于原子性)。
  3. 隔离性(Isolation):多个事务并发执行时,一个事务的执行不应影响其他事务的执行,如同只有这一个操作在被数据库所执行一样。
  4. 持久性(Durability):已被提交的事务对数据库的修改应该永久保存在数据库中。在事务结束时,此操作将不可逆转。

本地事务

本地事务一般指数据库单库事务。传统关系数据库对事务支持已经非常完善。主流的开发框架,比如Spring,针对传统数据库的事务提供了便捷的支持,通过配置或者注解等方式来控制事务。

分布式事务

规模庞大的系统,就要跟分布式事务打交道了。主要的一些业务场景如下。

分库分表

数据库做水平切分时,一个SQL操作会涉及多个数据库,这些操作需要在一个事务中完成。MyCat支持分布式事务。

image.png

微服务

业务拆分成众多微服务之后,业务的调用链条变长了,可能涉及众多服务、数据库、消息服务,所有的资源操作需要在一个事务中完成。

两阶段提交

XA是一个分布式事务协议。XA分为两部分:事务管理器(Transaction Manager)和本地资源管理器(Resource Manager)。其中本地资源管理器往往由数据库实现,比如Oracle、DB2这些商业数据库都实现了XA接口,而事务管理器作为全局的调度者,负责各个本地资源的提交和回滚。2PC和3PC提交都是基于XA协议实现的。

两阶段提交的问题

  1. 同步阻塞问题。执行过程中,所有参与节点都是事务阻塞型的。当参与者占有公共资源时,其他第三方节点访问公共资源不得不处于阻塞状态。

  2. 单点故障。由于协调者的重要性,一旦协调者发生故障。参与者会一直阻塞下去。尤其在第二阶段,协调者发生故障,那么所有的参与者还都处于锁定事务资源的状态中,而无法继续完成事务操作。(如果是协调者挂掉,可以重新选举一个协调者,但是无法解决因为协调者宕机导致的参与者处于阻塞状态的问题)

  3. 数据不一致。在二阶段提交的阶段二中,当协调者向参与者发送commit请求之后,发生了局部网络异常或者在发送commit请求过程中协调者发生了故障,这回导致只有一部分参与者接受到了commit请求。而在这部分参与者接到commit请求之后就会执行commit操作。但是其他部分未接到commit请求的机器则无法执行事务提交。于是整个分布式系统便出现了数据部一致性的现象。

  4. 二阶段无法解决的问题:协调者再发出commit消息之后宕机,而唯一接收到这条消息的参与者同时也宕机了。那么即使协调者通过选举协议产生了新的协调者,这条事务的状态也是不确定的,没人知道事务是否被已经提交。

TCC

补偿性事务大致含义是,"补偿是一个独立的支持ACID特性的本地事务,用于在逻辑上取消服务提供者上一个ACID事务造成的影响,对于一个长事务(long-running transaction),与其实现一个巨大的分布式ACID事务,不如使用基于补偿性的方案,把每一次服务调用当做一个较短的本地ACID事务来处理,执行完就立即提交”。

confirm和cancel就是补偿事务,用于取消try阶段本地事务造成的影响。因为第一阶段try只是预留资源,之后必须要明确的告诉服务提供者,这个资源你到底要不要,对应第二阶段的confirm/cancel。

可靠消息最终一致性

可靠消息最终一致性是指产生消息的业务动作与消息发送的一致。也就是说,如果业务操作成功,那么由这个业务操作所产生的消息一定要成功投递出去(一般是发送到kafka、rocketmq、rabbitmq等消息中间件中),否则就丢消息。

阿里云提供的MQMNS两种消息产品都支持事务型消息,将这个特性跟数据库事务结合,可以实现基于可靠消息的最终一致性。

image.png
image.png

GTS

GTS是阿里云提供的全局事务服务。GTS 支持 DRDS、RDS、Oracle、MySQL、PostgreSQL、OceanBase 和 Petadata 等多种数据源,可以配合 EDAS、Dubbo 和 Spring Cloud 等微服务框架使用, 兼容 MQ 实现事务消息。通过各种组合,可以轻松实现分布式数据库事务、多库事务、消息事务、服务链路级事务等多种业务需求。

针对不同的应用场景,GTS 主要提供标准模式(AT)和自定义模式(MT)两种事务模式。AT模式会依赖数据库,用户需要创建txc_undo_log表。MT模式更像TCC,用户需要自己实现两阶段提交的逻辑。

AT 模式

AT 模式是 GTS 最主要的事务模式,通过 GTS 基于 DRDS/RDS 的数据源,对 SQL 语句提供分布式事务支持。它帮助应用方以最小的改造代价来实现数据库的事务功能。

AT 模式适合于 DRDS 分库分表、多数据库数据源、跨进程的多数据库数据源等几乎任何 DRDS 应用场景下的分布式事务。

MT 模式

MT模式提供用户可以介入两阶段提交过程的一种模式。在这种模式下,用户可以根据自身业务需求自定义在 GTS 的两阶段中每个阶段的具体行为。MT 模式提供了更多的灵活性,可能性,以达到特殊场景下的自定义优化,及特殊功能的实现。

MT 模式不依赖于数据库,这是它相对于 AT 模式的一个最大的优势。MT 模式几乎满足任何事务场景。

样例

GTS提供了丰富的样例帮助大家理解产品的原理和使用。

基于消息的最终一致性

sample-txc-mq这个例子使用MQ实现的最终一致性。循环转账十次,前五次会成功,后五次会因为余额不足而失败。

[root@izuf60wa1jflm222pngldrz bin]# ./run.sh 
log4j:WARN No appenders could be found for logger (org.springframework.core.env.StandardEnvironment).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.
JM.Log:INFO Init JM logger with Slf4jLoggerFactory success, sun.misc.Launcher$AppClassLoader@4617c264
JM.Log:INFO Log root path: /root/logs/
JM.Log:INFO Set txc log path: /root/logs/txc
JM.Log:INFO Set diamond-client log path: /root/logs/diamond-client
client mode:3 [0:None (only be client) 1:Default Mode 2:Manual Mode 3:Default Mode & Manual Mode 5:Default Mode & Service Mode 6:Manual Mode & Service Mode 7:Default Mode & Manual Mode &Service Mode]
txcAppName:gts_henshao_test.1162142976628250.SH
txcServerGroup:gts_henshao_test.1162142976628250.SH
Sat Dec 15 15:56:46 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Sat Dec 15 15:56:46 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Producer started!

Sat Dec 15 15:56:46 CST 2018
send msgId:AC139F2C46554617C26448F1D3960000 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中间状态为:80元
本次转账结束,A和B的余额为:
A账户现在余额为80元
B账户现在余额为120元
A和B的金额总和为200元

Sat Dec 15 15:56:47 CST 2018
Sat Dec 15 15:56:48 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
Sat Dec 15 15:56:48 CST 2018 WARN: Establishing SSL connection without server's identity verification is not recommended. According to MySQL 5.5.45+, 5.6.26+ and 5.7.6+ requirements SSL connection must be established by default if explicit option isn't set. For compliance with existing applications not using SSL the verifyServerCertificate property is set to 'false'. You need either to explicitly disable SSL by setting useSSL=false, or set useSSL=true and provide truststore for server certificate verification.
send msgId:AC139F2C46554617C26448F1D6BC0003 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中间状态为:60元
本次转账结束,A和B的余额为:
A账户现在余额为60元
B账户现在余额为140元
A和B的金额总和为200元

Sat Dec 15 15:56:48 CST 2018
send msgId:AC139F2C46554617C26448F1D9D10006 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中间状态为:40元
本次转账结束,A和B的余额为:
A账户现在余额为40元
B账户现在余额为160元
A和B的金额总和为200元

Sat Dec 15 15:56:49 CST 2018
send msgId:AC139F2C46554617C26448F1DA7E0009 status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中间状态为:20元
本次转账结束,A和B的余额为:
A账户现在余额为20元
B账户现在余额为180元
A和B的金额总和为200元

Sat Dec 15 15:56:49 CST 2018
send msgId:AC139F2C46554617C26448F1DAFE000C status:SEND_OK broker:shanghaishare-10 qid:0, topic:mq_henshao_test
A的中间状态为:0元
本次转账结束,A和B的余额为:
A账户现在余额为0元
B账户现在余额为200元
A和B的金额总和为200元

Sat Dec 15 15:56:49 CST 2018
send msgId:AC139F2C46554617C26448F1DB80000F status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中间状态为:-20元
not enough money. 回滚到事务前状态
本次转账结束,A和B的余额为:
A账户现在余额为0元
B账户现在余额为200元
A和B的金额总和为200元

Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DCF60012 status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中间状态为:-20元
not enough money. 回滚到事务前状态
本次转账结束,A和B的余额为:
A账户现在余额为0元
B账户现在余额为200元
A和B的金额总和为200元

Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DDC20015 status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中间状态为:-20元
not enough money. 回滚到事务前状态
本次转账结束,A和B的余额为:
A账户现在余额为0元
B账户现在余额为200元
A和B的金额总和为200元

Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DE870018 status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中间状态为:-20元
not enough money. 回滚到事务前状态
本次转账结束,A和B的余额为:
A账户现在余额为0元
B账户现在余额为200元
A和B的金额总和为200元

Sat Dec 15 15:56:50 CST 2018
send msgId:AC139F2C46554617C26448F1DF75001B status:SEND_OK broker:shanghaishare-11 qid:0, topic:mq_henshao_test
A的中间状态为:-20元
not enough money. 回滚到事务前状态
本次转账结束,A和B的余额为:
A账户现在余额为0元
B账户现在余额为200元
A和B的金额总和为200元
wait for several seconds  ------------------
checking result --------------------
A原来来有100元,现在为0元
B原来来有100元,现在为200元
A和B的金额总和为200元

三个分支事务分别是两个数据库,一个MQ消息。

image.png

去MQ里面可以看到一共发送了五条消息,失败的五条是看不到的。

image.png

预留和补偿事务

MT模式的两个例子,预留事务是在rollin的时候预留资源,commitRollin的时候操作资源及删除分支事务的数据。补偿事务则是在rollin的时候就操作资源,commitRollin的时候只删除分支事务的数据。

参考资料

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

推荐阅读更多精彩内容