分布式事务对于两阶段提交的错误处理

一、背景
笔者和团队在昆仑分布式数据库中的两阶段提交方式,可以成功避免经典的两阶段提交算法的缺陷。
而在此分布式事务处理两阶段提交机制和原理上,笔者和团队增强其容灾能力和错误处理能力,可以做到任意时刻昆仑数据库集群的任意节点宕机或者网络故障、超时等都不会导致集群管理的数据发生不一致或者丢失等错误。
本文会详述分布式事务对于两阶段提交算法的错误处理原理和机制及延时损耗~
【分布式事务对于两阶段提交的错误处理】二、昆仑数据库如何对两阶段提交算法错误处理?
在生产环境的分布式数据库集群的工作场景中,通常只有不到0.01%的分布式事务提交会发生错误,但是我们仍然需要处理所有可能发生的错误。
因为哪怕执行了100亿笔事务,只要有1笔发生了提交错误,都会导致用户数据出错。
数据库系统就是要确保事务永远正确地提交,ACID保障始终成立,没有例外。
这对于分布式数据库系统来说,会比单机数据库更加复杂,因为可能的错误来源更多(多个计算节点和多个存储节点,及其之间的网络连接)。
这也是为什么数据库系统的设计和实现会如此复杂,而分布式数据库系统的设计和实现更加复杂。
下面,我们就看一下昆仑分布式数据库集群如何处理分布式事务提交过程中发生的错误。我们分别讲述两阶段提交的每个阶段的错误处理,以及批量写入commit log的错误处理。
2.1 第一阶段错误处理
分布式事务对于两阶段提交的错误处理
文章图片

图1. 第一阶段提交失败的处理
如果prepare阶段发生语句错误,网络断连或者超时,那么GTM会提交rollback记录请求给GTSS,并且不等待其返回结果就立刻发送rollback命令给出错的节点并且断连超时的连接,然后返回错误给客户端,告知客户端该事务GT被回滚。
GTSS会在commit log中记录GT的提交指令为ROLLBACK, 这样cluster_mgr 随后处理GT的prepared事务分支时会回滚它们。
2.2 批量写入Commit logging 错误处理
分布式事务对于两阶段提交的错误处理
文章图片

图2. commit log写入失败的处理
如果GTSS写入commit log 出错或者超时,那么GTM会回滚GT的所有preapred事务分支,也就是发送XA ROLLBACK给GT写入的所有存储集群,然后不论其结果如何都返回‘Aborted’给客户端标明GT被回滚了。
即使XA ROLLBACK发送失败了那么这个事务分支仍然会按预期被cluster_mgr回滚。
2.3 第二阶段错误处理
分布式事务对于两阶段提交的错误处理
文章图片

图3. 第二阶段提交失败的处理
如果第二阶段发生网络错误或者超时,那么仍然返回提交成功给客户端。
这是因为只要记录了commit log提交的任何分布式事务,都必须完成提交。
如果执行第二阶段期间任何计算、存储节点发生宕机或者网络故障,那么cluster_mgr进程会根据commit log的指令,来处理这些事务分支 --- 如果指令是提交那么就提交GT的所有事务分支。
如果指令是回滚或者无法找到GT的commit log,那么就回滚GT的所有事务分支。
如果第二阶段进行过程中计算节点宕机或者断网了那么这个事务仍将提交,此时应用系统后端(也就是数据库的客户端)会发现自己的commit语句没有返回直到数据库连接超时(通常应用层也会让终端用户连接超时)或者返回了断连错误。
三、延时损耗
由于两阶段提交的prepare和commit阶段都需要等待存储引擎flush WAL日志,并且在两个阶段之间还需要等待commit log写入元数据集群,所以两阶段提交的时耗一定比执行相同的SQL DML语句但做一阶段条会增加一些。
根据这个性能报告:http://www.zettadb.com/blogs/...,昆仑数据库的两阶段提交在普通的服务器硬件配置和千兆网络情况下会增加约30毫秒的延时。
在商用服务器硬件和网络环境下,这个延时增加会少于30毫秒。这个30毫秒包括了commitlog的写入,多执行一个阶段的等待时间以及所有增加的网络通信时间开销等。
四、总结
昆仑分布式数据库的分布式事务处理机制,确保了分布式事务执行和提交的一致性和容灾能力,在事务提交期间任何节点、网络故障都不会导致事务的ACID保障失效,从而确保了用户数据正确。

    推荐阅读