背景
PolarDB-X是一个云原生的分布式数据库,整体架构如下,其中计算节点也称为CN节点,存储节点也称为DN节点,SQL的执行流程由CN节点进行接入进行分布式计算,底层的存储引擎负责数据库的持久化和一致性保障。DN节点利用自研一致性协议库X-Paxos,构建了高可用的存储集群,并且在阿里集团得到了全面的发展和验证。本文主要对DN节点的一致性协议进行概要介绍和进行相关的源码导读,同时提供最小化的搭建案例。

整体架构
先来看一下PolarDB-X存储节点的基本架构:

上图展示的是一个部署三个实例的PolarDB-X存储集群。PolarDB-X存储集群是一个单点写入,多点可读的集群系统。在同一时刻,整个集群中至多会有一个Leader节点来承担数据写入的任务。PolarDB-X存储节点的每个实例都是一个单进程的系统,X-Paxos被深度整合到了数据库内核之中,替换了原有的复制模块。集群节点之间的增量数据同步通过X-Paxos来驱动完成,不再需要外部手动指定复制位点。PolarDB-X存储节点为了追求最高的性能,选择了自己实现Consensus日志这种接入X-Paxos的方式,在MySQL Binlog的基础上实现了一系列X-Paxos日志接口,赋予X-Paxos操纵Binlog的能力。

X-Paxos的整体架构如上图所示,主要可分为网络层、服务层、算法模块、日志模块4个部分。
- 网络层:基于阿里内部非常成熟的网络库libeasy实现。libeasy的异步框架和线程池非常契合我们的整体异步化设计。
- 服务层:服务层是驱动整个X-Paxos运行的基础,为X-Paxos提供了事件驱动,定时回调等核心的运行功能
- 算法模块:基于强leadership的Multi-Paxos实现,在基础算法的基础上,结合阿里业务的场景以及高性能和生态的需求,X-Paxos做了很多的创新性的功能和性能的优化,使其相对于基础的Multi-Paxos,功能变的更加丰富,性能也有明显的提升。
- 日志模块:出于对极致性能要求的考虑,我们把日志模块独立出来,并实现了一个默认的高性能的日志模块,用户可以结合已有的日志系统,对接日志模块接口,以获取更高的性能和更低的成本
角色区别
Paxos将系统中的角色分为提议者 (Proposer),决策者 (Acceptor),和最终决策学习者 (Learner):
- Proposer: 负责提议Proposal。Proposal包含Proposal Number(简称PN)和Value两部分,一个PN=n且Value=v的Proposal记作Proposal{n, v}。
- Acceptor:负责决策,即根据自己所知的信息,回应Proposer发来的请求(下文将看到,有PrepareReq和AcceptReq两种请求)。
- Learner:不参与决策,从Proposers/Acceptors学习最新达成一致的提案(Value)。
在X-Paxos一致性协议中,将整个一致性协议的持久存储分两块:日志和状态机。日志代表了对状态机的更新操作,状态机存放了外部业务读写的实际数据。基于日志和状态机,与Paxos的角色定义不同,X-Paxos将系统中的角色分为Leader(主节点)、Follower(从节点)、Logger(日志节点)、Learner(只读节点)。
- Leader: 主节点是集群的唯一写节点。它给集群所有节点发送新写入的日志,达成多数派后允许提交,并回放到本地的状态机。Leader节点的定义也是为了解决Paxos中活锁的问题,避免两个Proposer交替发起Prepare请求成功,而Accept失败引起的活锁(LiveLock)问题。
- Follower:从节点用于收集Leader发送的日志,并负责把达成多数派的日志回放到状态机。当Leader发生故障时,集群中的剩余节点会选一个新的Follower升级成Leader接受读写请求。
- Logger: 日志节点是一种特殊类型的Follower,不对外提供服务。Logger做两件事:存储最新的日志用于Leader的多数派判定;选主阶段行使投票权。Logger不回放状态机,会定期清理老旧的日志,占用极少的计算和存储资源。因此,基于Leader/Follower/Logger的部署方式,三节点相比双节点高可用版,只额外增加很少的成本。
- Learner: 只读副本的一种模式,这种模式下Leader节点没有投票权,不参加多数派的计算,仅从Leader同步已提交的日志,并回放到状态机。在实际使用中,我们把Learner作为只读副本,用于应用层的读写分离。此外,X-Paxos支持Learner和Follower之间的节点变更,基于这个功能可以实现故障节点的迁移和替换。
日志复制
首先回顾MySQL双节点高可用版本的复制模式。其中Master节点负责写入binary log,并提交事务。Slave节点通过IO线程从Master节点发起dump协议拉取binary log,并存储到本地的relay log中。最后由Slave节点的SQL线程负责回放relay log。双节点复制模式可以用下图表示:

一般情况下,Slave节点还需要开启log-slave-updates来保证从库也可以为下游提供日志同步,因此Slave线程除了relay log,还会有一份冗余的binary log。 PolarDB-X存储节点整合了binary log和relay log,实现了统一的consensus log,节省了日志存储的成本。当某个节点是Leader的时候,consensus log扮演了binary log的角色;同理当某个节点被切换成Follower/Learner时,consensus log扮演了relay log的角色。X-Paxos一致性协议层接管consensus log的同步逻辑,同时提供对外的接口来实现日志写入和状态机回放。新的consensus log基于一致性协议和State Machine Replication理论,保证了多个节点之间的数据一致性。此外,PolarDB-X存储节点日志的实现遵循了MySQL binary log的标准,可以无缝兼容aliyun DTS、Canal等业内常用的binlog增量订阅工具。 三节点复制模式如下图所示:

状态机
PolarDB-X存储节点的状态机实现改造了MySQL原有事务提交的流程。MySQL组提交(Group Commit)相关的技术文章网上有很多,原有Group Commit分为三个阶段:flush stage、sync stage、commit stage。对于Leader节点,PolarDB-X存储节点修改了其中commit stage的实现方式。所有进入commit stage的事务会被统一推送到一个异步队列中,进入quorum决议的判定阶段,等待事务日志同步到多数节点上,满足quorum条件的事务才允许commit。另外,Leader上consensus log的本地写入和日志同步可以并行执行,保证了高性能。对于Follower节点,SQL线程读取consensus log,开始等待Leader的通知。Leader会定期同步给Follower每一条日志的提交状态,达成多数派的日志会被分发给worker线程并行执行。 Learner节点相对Follower的逻辑更加简单,一致性协议保证了它不会接收到未提交的日志,SQL线程不用等待任何条件,只需分发最新的日志给worker线程即可。此外,PolarDB-X存储节点使用特殊版本的Xtrabackup进行实例备份和恢复。我们基于X-Paxos的snapshot接口改进了Xtrabackup,支持创建带有一致性位点的物理备份快照,可以十分快捷的孵化一个全新的Learner节点,并加入到集群中提供读能力的扩展。

源码导读
模块划分
X-Paxos一致性协议的代码在
https://github.com/ApsaraDB/galaxyengine/tree/main/extra/IS/consensusgithub.com/ApsaraDB/galaxyengine/tree/main/extra/IS/consensus
主要涵盖algorithm(算法模块)、net(网络处理)、protocol(协议处理)、服务管理(service)、uniteest(单元测试)等。

模块介绍
- algorithm目录为核心的一致性协议算法,X-Paxos当前的算法基于
强leadership的Multi-Paxos实现www.cs.utexas.edu/users/lorenzo/corsi/cs380d/past/03F/notes/paxos-simple.pdf?spm=ata.21736010.0.0.4e5c5d5fDidCAa&file=paxos-simple.pdf
Multi-Paxos在写入过程中会先用Paxos协议选举出一个Leader,之后只由这个leader写入。核心的Paxos流程实现过程主要见http://paxos.cc。

- example目录为如果使用X-Paxos协议库的案例

- net目录为X-Paxos使用的libeasy协议的封装,libeasy是一个基于libev处理tcp连接的事件驱动的网络框架,框架本身封装好了底层的网络操作,只需要开发者处理其中的各种事件。libeasy也随着X-Paxos的开源一起开放了代码,主要代码见
https://github.com/ApsaraDB/galaxyengine/tree/main/extra/IS/dependency/easy/srcgithub.com/ApsaraDB/galaxyengine/tree/main/extra/IS/dependency/easy/src

- protocol目录为X-Paxos协议通信的结构体,X-Paxos使用protocol buffer进行数据的结构化封装。

- service目录基于libeasy封装之后的client/service网络服务调用

http://service.cc主要包含对不同类型的消息的处理,包含RequestVote、AppendLog等,详细可以见Service::process函数

- unitetest目录为一致性协议相关的单元测试case

源码编译&部署测试
编译源码
详细源码编译按照步骤见
源码编译安装 · PolarDB-X 产品文档doc.polardbx.com/quickstart/topics/quickstart-development.html
准备配置文件
为了支持三节点我们新增了对应的配置参数如下
| 仅限my.cnf和命令行启动参数 | |
|---|---|
| 参数名 | 含义 |
| cluster-learner-node | learner节点设为ON |
| cluster-log-type-node | 日志节点设为ON |
| cluster-info | 对于leader和follower节点,格式为ip1:port1;ip2:port2...@N,前面列出集群所有ip:port,并保证集群内所有节点配置一致。每个节点配置的区别在@N,N为当前节点在列表里的index,从1开始计。 对于learner节点,格式为ip:port。 可以搭配cluster-force-change-meta使用,订正consensus_info的cluster-info或cluster-learner-info信息。 注意1:这里的port是协议层的port,不是3306,是11306。 注意2:learner节点没有@N 注意3:通过命令行配置时加引号,即--cluster-info="ip1:port1;ip2:port2...@N" 举个例子: 三个节点ip分别为IP1,IP2,IP3 统一使用11306作为协议层port 那么三个节点的cluster-info的写法分别是: IP1的my.cnf cluster-info=IP1:11306;IP2:11306;IP3:11306@1 IP2的my.cnf cluster-info=IP1:11306;IP2:11306;IP3:11306@2 IP3的my.cnf cluster-info=IP1:11306;IP2:11306;IP3:11306@3 |
| cluster-current-term | 搭配cluster-force-change-meta使用,订正consensus_info的term信息。 |
| cluster-force-recover-index | 备份恢复时使用,主库备份依赖,从库备份会忽略该参数。 |
| cluster-force-change-meta | 强制刷新consensus_info表的数据,一般用于非标操作导致内部元数据错乱后的fix。只有命令行指定了cluster-force-change-meta,系统才会重新更新并持久化元数据,否则不会读取my.cnf里的cluster-info和cluster-current-term。 |
| cluster-dump-meta | 导出consensus_info表数据,存放在data目录下,文件名是“consensus.meta”。用于实例起不来的时候,排查元数据是否正确。用法类似于cluster-force-change-meta。 |
| cluster-force-single-mode | 强制单节点,等价于change consensus_node to consensus_force_single_mode的SQL。 |
| cluster-mts-recover-use-index | 并行复制使用index为位点依据,必须设为ON。 |
| cluster-start-index | 备份恢复时使用,备份恢复的节点没有旧的binlog日志。该index之前的日志都需要走mock逻辑,协议层在判定一致时可以不作校验。 |
根据以上参数准备三个节点的my.cnf文件参数如下
- cluster-id: 集群标识ID
- cluster-info: 根据自己的集群信息配置对应的IP和PORT,还有对应的节点标识
准备好原有的my.cnf文件,新增加三节点配置如下,对于不同的节点需要修改对应的INDEX值
# galaxyengine三节点相关配置
cluster-id=872339378
cluster-info=IP1:PORT1;IP2:PORT2;IP3:PORT3@INDEX
consensus_io_thread_cnt=8
consensus_worker_thread_cnt=8
consensus_max_delay_index=10000
consensus_election_timeout=10000
consensus_max_packet_size=131072
consensus_max_log_size=20M
cluster-mts-recover-use-index=ON
#loose_async_commit_thread_count=128
#async_commit=OFF
replicate-same-server-id=on
#loose_commit_lock_done_count=1
binlog_order_commits=OFF
#cluster-log-type-node=OFF初始化数据
配置好对应的配置文件之后进行初始化
mysqld --defaults-file=my.cnf --initialize-insecure --user=mysql
启动实例
分别启动多副本集群里的几个实例:
mysqld --defaults-file=my.cnf &
启动完成之后查看对应的mysql日志,如果有以下选主成功的日志输出则代表集群创建成功
[2022-04-26 15:14:29.141505] [ERROR] Server 2 : Paxos state change from FOLL to CAND !!
[2022-04-26 15:14:29.141505] [ERROR] Server 2 : Start new requestVote: new term(2)
[2022-04-26 15:14:44.088529] [ERROR] Server 2 : Paxos state change from CAND to CAND !!
[2022-04-26 15:14:44.088529] [ERROR] Server 2 : Start new requestVote: new term(3)
[2022-04-26 15:14:58.821423] [ERROR] Server 2 : Paxos state change from CAND to CAND !!
[2022-04-26 15:14:58.821423] [ERROR] Server 2 : Start new requestVote: new term(4)
[2022-04-26 15:15:00.537734] [ERROR] EasyNet::onConnected server 1
[2022-04-26 15:15:13.165122] [ERROR] Server 2 : Paxos state change from CAND to CAND !!
[2022-04-26 15:15:13.165122] [ERROR] Server 2 : Start new requestVote: new term(5)
[2022-04-26 15:15:13.168488] [ERROR] Server 2 : server 1 (term:5) vote me to became leader.
[2022-04-26 15:15:13.168488] [ERROR] Server 2 : Paxos state change from CAND to LEDR !!
[2022-04-26 15:15:13.168488] [ERROR] Server 2 : become Leader (currentTerm 5, lli:1, llt:5)!!查看集群状态
使用mysql客户端链接三节点集群mysql -P端口 -uroot -h127.0.0.1,可以使用以下SQL查看集群的状态 select * from information_schema.alisql_cluster_global;
select * from information_schema.alisql_cluster_local;

如果要切换leader可以使用以下命令进行切换 call dbms_consensus.change_leader("IP:PORT");

总结
PolarDB-X融合了基于X-Paxos的数据库存储技术,通过经历阿里集团多年双十一的技术积累和稳定性验证,PolarDB-X在稳定性、易用性、高可用特性上都会有不错的表现。文章主要对X-Paxos一致性协议的整体架构、节点角色、集群管理、日志和状态机的机制进行了介绍,同时对源码进行了导读,后续我们还会深入介绍X-Paxos相关的源码技术。
文章来源:阿里云数据库




