本文详细介绍KunlunBase金融级高可靠性技术体系中最关键的部分--- kunlun-storage 存储节点故障恢复机制。KunlunBase用户并不需要理解本文内容就可以有效地使用KunlunBase,本文内容主要是给对KunlunBase核心技术和MySQL事务处理技术感兴趣的读者参考和学习。
关键词:事务处理、故障恢复、高可用、高可靠
社区版MySQL不支持对XA事务的故障恢复,因此无法直接使用作为分布式数据库的存储节点。Kunlun-storage完善和增强了MySQL的事务恢复机制,其中最主要的是增加了对XA事务的故障恢复机制,为KunlunBase集群故障恢复机制提供了基础条件,这部分技术是KunlunBase核心技术体系的重要组成部分。
经过本文所述的对社区版MySQL事务故障处理的完善和增强,kunlun-storage组成的KunlunBase集群可以正确地处理其集群任何节点的故障,并保证在KunlunBase集群中所有提交成功的事务的ACID属性,从而助力KunlunBase达到金融级高可靠性。
本文先简介KunlunBase产品概况和技术架构,然后简介KunlunBase集群故障恢复技术。这些内容在其他文章中都有详细论述。接着介绍分布式数据库集群可能面临的故障以及如果不能有效解决的话可能造成的危害。然后介绍MySQL 事务处理的基础知识和关键技术,以及MySQL故障处理和事务恢复技术。然后重点介绍MySQL在XA事务处理方面的一系列缺陷和漏洞以及KunlunBase如何解决这些问题。
本文作者赵伟曾在2021年2月的FOSDEM上做过本人内容的技术分享,受到了国内外MySQL社区的广泛关注。也曾在2023年5月我们泽拓科技在北京举办的线下meetup中以中文再次讲解本文内容。
1 KunlunBase概况
泽拓科技的KunlunBase(也叫做Klustron)一个分布式关系数据库系统,支持OLTP和OLAP混合负载(HTAP),支持不停服的水平弹性伸缩,可以随时按需扩缩容;支持金融级高可靠性,可以在集群节点和网络故障情况下正常工作不丢失或者损坏数据,并持续提供正常服务;KunlunBase具有完备的数据安全机制,支持多粒度访问控制,全链路加密传输数据,以及数据文件和日志文件加密等功能;
KunlunBase兼容MySQL和PostgreSQL的SQL语法和连接协议,绝大多数使用MySQL和PostgreSQL数据库的应用软件和web程序无需修改即可使用KunlunBase。
应用软件开发者使用KunlunBase开发应用系统与使用MySQL或者PostgreSQL的用法完全相同 --- 他们完全不需要考虑数据在KunlunBase 分布式数据库集群中如何拆分存储和分布,也不需要担心一个事务写入多个存储集群的情况下,如何可靠地提交事务,如何执行获取多个存储集群上的数据来执行一个SQL查询语句 --- 所有这些技术细节都由KunlunBase处理,确保数据库事务的ACID属性,并且高效地从目标数据所在的若干个存储集群获取目标数据来执行任意复杂度的SQL查询。这是KunlunBase对应用开发团队来说显著优于应用层分库分表或者使用分库分表中间件的优势。
2 KunlunBase架构

KunlunBase的计算节点(Kunlun-server) 负责接受应用软件端的连接请求,验证请求合法性后建立连接;以及从已经建立的连接中接受SQL查询请求,执行请求,然后后返回查询结果。
三个或者更多个存储节点组成一个存储集群(storage shard,简称shard),每个shard存储着一部分用户表或者表分区,不同shard的数据没有交集;
每个KunlunBase集群有若干个计算节点和若干个shard组成。一个shard的主节点接受来自计算节点的读写请求,执行请求并返回结果给计算节点;启用了备机读功能时,shard的备节点可以接收和处理来自计算节点的只读请求,常用于做数据分析和报表。
MySQL使用binlog做主备复制实现高可用,KunlunBase的fullsync技术增强了这种binlog复制,可以确保在主节点发生故障时,一定有备机拥有主节点的全部数据,从而确保所有已提交的事务都不丢失。
存储集群主备节点之间通过KunlunBase特有的Fullsync强同步机制来实现金融级数据一致性,确保RPO=0;同时KunlunBase自研的高可用机制 Fullsync HA可以监测每个shard的主节点运行状态并且在发现主节点故障时自动选举新主节点并完成主备切换,确保 RTO小于30秒。
关于KunlunBase架构的更多信息,点击这里查看。
3 KunlunBase故障恢复技术概况
KunlunBase分布式事务两阶段提交流程
为描述方便,先简单介绍两阶段提交算法的技术术语,一个全局事务(global transaction, GT)在若干个存储节点(resource manager, RM)中执行事务分支(transaction branch, LT),由全局事务管理器(GTM)管理其状态和提交过程。在MySQL中,把可以作为分布式事务分支的事务称为XA事务,针对这些事务有专门的SQL语句做事务控制(XA START, XA END, XA PREPARE, XA COMMIT [ONE PHASE])。与这些XA事务相对应的,就是普通事务,也就是通过begin...commit启动和提交的事务,以及autocommit的增删改查(CRUD)语句事务。

3. 如果一个存储节点提交XA事务期间发生故障并且不能正确地恢复这些事务,就可能导致这个存储节点上当时正在提交的事务分支被回滚,这就会导致一个全局事务的一部分事务分支提交,部分事务分支回滚,从而导致数据丢失或者不一致。
4 社区版MySQL事务故障恢复技术
MySQL事务处理的基础知识简介
为了本文后面章节描述方便,简单罗列一下MySQL的基础知识和概念,已掌握的话可以直接跳过。
MySQL支持多存储引擎,通过其内部定义的Handler接口与存储引擎交互。目前常用的支持事务处理的存储引擎(简称事务存储引擎,transactional storage engine)是InnoDB,InnoDB也是MySQL目前默认的存储引擎。同时MySQL社区还有MyRocks,它包含RocksDB并且为RocksDB存储引擎实现了HANDLER接口,使得MySQL可以使用RocksDB这个事务存储引擎。
MySQL通过binlog事件流把数据更新传输给备机节点,备机重新执行这些binlog事件,从而获得与主节点相同的数据,成为主节点的一个实时可用的备用节点,这就实现了高可用(high availability, HA) 。Binlog系统在MySQL中也被当做一种存储引擎,实现了HANDLER接口。不过,binlog系统本身并不支持事务处理,不能做事务回滚或者恢复。Binlog文件达到一定大小后,MySQL会自动切换到一个新的binlog文件,这些文件依次升序编号。老旧不用的binlog文件会被DBA删除(purge)掉来释放存储空间。
在启用binlog系统和gtid_mode=on的情况下,每个MySQL的事务使用一个gtid来唯一标识,gtid包含了主节点的UUID和单调递增的顺序号,由MySQL自动分配(本文不讨论GTID的其他边缘用法)。系统表mysql.gtid_executed 会详细记录一个MySQL实例执行过的所有gtid的集合。因此,一个MySQL实例的这3个事务集合必须相同,这也是MySQL数据一致性条件:
1. binlog中记录过的所有事务的集合(尽管其中大多数后来都会被purge掉)
2. 存储引擎中执行过的事务的集合
3. mysql.gtid_executed中记录着的gtid所属的事务的集合
这是MySQL binlog recovery的目标。对于普通事务,社区版MySQL实现了这个目标,但是对于XA事务,社区版MySQL完全忽略了,没有做任何处理。kunlun-storage完整地支持了XA事务的故障处理,可以确保XA事务也符合上述一致性要求。
本文所述的技术基于这个常用的也是数据一致性保障级别最高的设置,这也是KunlunBase要求必须使用的设置:启用binary logging, gtid_mode=on,sync_binlog=1, innodb_flush_at_trx_commit=1。

5 社区版MySQL XA事务处理的缺陷及其kunlun-storage中的修复
对于XA事务来说,社区版MySQL有一系列问题,本节依次详述。考虑到上述严重的潜在危害,我们需要完善和改进MySQL对XA事务处理的错误处理和故障恢复能力,以便kunlun-storage可以正确地恢复出XA事务分支,这样在KunlunBase集群层面KunlunBase才可以正确地恢复故障发生时刻正在提交的那些全局事务。恢复最关键的一环,就是存储节点要正确地恢复其本地XA事务分支。
XA PREAPRE写binlog的时机错误






