PolarDB- X 作为 PolarDB 分布式版,是阿里巴巴自主设计研发的高性能云原生分布式数据库产品,为用户提供高吞吐、大存储、低延时、易扩大和超高可用的云时代数据库服务。PolarDB- X 在架构上能够简略分为 CN 节点和 DN 节点。计算节点 CN 负责 SQL 的解析和执行,存储节点 DN 负责数据的分布式事务和高可用存储。本文次要对存储引擎外围中高可用局部具体技术解读。
背景
传统的存储引擎高可用次要采纳主备同步的形式,然而主备同步形式人造存在以下限度:
- 高性能与数据一致性的取舍:主备复制采纳强同步形式会导致主库写入性能升高,采纳异步形式无奈保障主库宕机时备库无损提供一致性保障,半同步形式尽管能无效缓解性能升高,但同样无奈提供严格的一致性保障
- 零碎可用性:主备库形式在面临网络故障或提早较大场景时,可能会存在主库迟迟无奈提交事务,不能及时主备切换,从而影响零碎的可用性
针对主备库形式的问题,以后业界次要采纳基于多正本的高可用存储引擎计划。PolarDB- X 同样基于该路线,自研了分布式一致性协定模块 X-Paxos,并将其与 MySQL 引擎深度联合,造成了 PolarDB- X 的多正本高可用存储引擎。
个性
下图是 PolarDB- X 多正本存储节点的根本架构,展现了一个部署三个正本的 PolarDB-X DN 集群。PolarDB-X DN 集群是一个单点写入,多点可读的集群零碎。在同一时刻,整个集群中至少会有一个 Leader 节点来承当数据写入的工作。PolarDB-X DN 节点的每个实例都是一个单过程的零碎,X-Paxos 被深度整合到了数据库内核之中,替换了原有的复制模块。集群节点之间的增量数据同步通过 X -Paxos 来驱动实现,不再须要内部手动指定复制位点。
总的来说,PolaDB- X 多正本存储引擎具备以下个性:
- 强一致性保障:X-Paxos 基于强 Leadership 的 Multi-Paxos 实现,大量实践和实际曾经证实了强 Leadership 的 Multi-Paxos,性能好于 Multi-Paxos/Basic-Paxos。PolarDB- X 在解体复原时的一致性问题上更是做了深刻的保障
- 高性能的数据同步:具备 Batching/Pipelining 形式的高效日志传输,具备多线程异步的高效数据传输,具备 X -Paxos 日志和 Binlog 交融的极致精简对立
- 灵便的运维容灾:在线增加 / 删除 / 权重化配置任意节点,具备手动 / 主动选主的灵便策略
- 低成本的数据存储:翻新引入 Logger 角色正本,让三正本具备最低两份存储的数据存储开销
上面针对以上个性别离进行深刻解读。
原理
强一致性保障
强一致性保障次要依赖 X -Paxos 模块,上图展现的 X -Paxos 整体架构,整体可分为网络层、服务层、算法模块、日志模块 4 个局部:
- 网络层:基于 libeasy 网络库实现。libeasy 的异步框架和线程池十分符合咱们的整体异步化设计,同时咱们对 libeasy 的重连、日志等逻辑进行了批改,以适应分布式协定的需要
- 服务层:驱动整个 Paxos 运行的根底,为 Paxos 提供了事件驱动,定时回调等外围的运行性能。每一个 paxos 实现都有一个与之严密相干的驱动层,驱动层的架构与性能和稳定性密切相关。
- 算法模块:一致性协定的外围,包含基于强 Leadership 的 Multi-Paxos 实现的选主模块,采纳预读缓冲区 / 热缓冲区的数据管理模块,复用 Enhanced Multi-Threaded Slave 技术的同步传输利用模块,以及扩大 sync_relay_log_info 零碎表的集群元数据模块。
- 日志模块,本来是算法模块的一部分,出于对极致性能要求的思考,咱们把日志模块独立进去,并实现了一个默认的高性能的日志模块。
如果说算法模块是运行时强一致性的保障,那么日志模块就是容灾时的强一致性保障。日志模块和 Binlog 极致耦合,同时也是保护解体复原逻辑的要害局部。Paxos 多正本强统一算法网上介绍很多,这里不再论述。咱们重点阐明下 PolarDB- X 中的日志模块实现。
日志模块
在原有的 MySQL 主备复制模式中,Master 节点负责写入 binary log,并提交事务。Slave 节点通过 IO 线程从 Master 节点发动 dump 协定拉取 binary log,并存储到本地的 relay log 中。最初由 Slave 节点的 SQL 线程负责回放 relay log。默认状况 Slave 节点除了产生 relay log,还会依据 log-slave-updates 有一份冗余的 binary log。
PolarDB- X 存储节点整合了 binary log 和 relay log,实现了对立的 consensus log,节俭了日志存储的老本。当某个节点是 Leader 的时候,consensus log 表演了 binary log 的角色;同理当某个节点被切换成 Follower/Learner 时,consensus log 表演了 relay log 的角色。新的 consensus log 基于一致性协定和 State Machine Replication 实践,保障了多个节点之间的数据一致性。
日志模块也接管 consensus log 的同步逻辑,勾销 Relay IO 线程,复用 Relay SQL 线程和 Relay Worker 线程,反对 MTS 多线程并行回放。同时提供对外的接口来实现日志写入和状态机回放。
依据算法模块和 Binlog 的依赖,日志模块引入了四种日志类型:
- Consensus Log Event:标记在每个事务的 Anonymous_GTID 日志之前,用于记录以后事务对应协定层 index、term、flag 等元信息
- Previous Consensus Index Event:写在每个 binary log 文件的最开始,Format_description events 之后,Previous_gtids events 之前,用于标记以后文件起始的事务 index
- Consensus Cluster Info Log Event:记录多正本集群配置变更的信息
- Consensus Empty Log Event:记录 X -Paxos 协定选主日志
PolarDB- X 日志模块同样革新了 MySQL 原有事务提交的流程。MySQL 的 Group Commit 分为三个阶段:flush stage、sync stage、commit stage。对于多正本的 Leader 节点,PolarDB-X DN 节点在 Binlog 的 Flush 和 Sync 过程中将携带 Consensus Log Event 的 Binlog 内容同时播送到所有 Follower。所有进入 commit stage 的事务会被对立推送到一个异步队列中,进入 quorum 决定的断定阶段,期待事务日志同步到少数节点上,满足 quorum 条件的事务才容许 commit,以保证数据的强统一。
此外,为了保障高性能,Leader 上 consensus log 的本地写入和日志同步能够并行执行对于 Follower 节点,SQL 线程读取 consensus log,期待 Leader 的告诉。Leader 会定期同步给 Follower 每一条日志的提交状态,达成多数派的日志会被分发给 worker 线程并行执行。
在事实利用场景中,Follower 和 Leader 的状态机难免会存在回放提早,比方一个大的 DDL 会导致 Follower 的回放提早被有限放大,而如果在回放提早存在的状况下 Leader 挂掉新主选出时,新主无奈对外提供服务,而此时老 Leader 可能曾经重启复原,所以在这种状况下 X-Paxos 会被动探测状态机的健康状况,如果在一段时间内回放提早无奈追平,则会尝试 Leader 被动回切,让没有回放提早的老 Leader 对外提供服务。
复原逻辑
PolarDB- X 的多正本存储引擎的复原流程和原生 MySQL 大不相同,不同在 Binlog 参加的复原流程,须要 X -Paxos 协定层参加,并且须要重点解决原生 MySQL XA 的不完整性问题。
PolarDB- X 的多正本存储引擎的复原的流程如下:
- 扫描 Binlog 文件
- 扫描 consensus 日志的完整性,不残缺的日志须要整体切除。
-
收集记录残缺提交 Binlog 的事务,构建提交事务的 hash 表
1)确认最初一次实例存活时产生的 Binlog 文件。以用作复原悬挂事务的根据
2)必须保障所有悬挂的事务都是在最初一个 Binlog 中,即便产生过切主
3)relay log 也必须保障没有悬挂事务,因为这里会波及到前一个作为主的任期的悬挂事务
- 扫描 InnoDB,取得所有的悬挂事务,如果不在提交事务 hash 表,那么回滚
- 期待 X -Paxos 启动,推动回放位点,依据回放位点确定悬挂事务的是否提交
a. 如果回放之前节点是处于 Binlog WORKING 状态,并且协定层也是 leader role(leader 宕机复原),则意味着协定层没有降级,那么能够判断为是在写入的状态下宕机复原,此时须要从零碎表的 last_leader_term 字段中依据最初是 leader 的 term 来遍历日志,从此 term 最初一条日志后开始作为回放终点。
b. 如果回放前节点是处于 Binlog WORKING 状态,协定层曾经不是 leader role(协定 leader 降级,或者是降级后 server 状态未变更时宕机),则意味着协定层曾经降级,在降级的时候把 commit index 写入了 start_apply_index。此时就从 start_apply_index 前面的一条日志开始回放。
c. 如果回放前节点是处于 RELAY LOG WORKING 状态,协定层也是非 leader(每次重启非 leader 的回放线程),则这意味着此实例始终是一个非 leader,那么找到 slave_relay_log_info 表中记录的 consensus_apply_index 作为回放位点
d. 如果回放前节点是处于 RELAY LOG WORKING 状态,然而协定层曾经切换到了 leader(协定 follower 降级,或者是降级过程中 server 状态未变更时宕机),则这意味着此实例始终是一个非 leader,那么找到 slave_relay_log_info 表中记录的 consensus_apply_index 作为回放位点
- 启动 apply 线程,实现复原流程
- 关上 MySQL 监听端口
MySQL XA 实现了一套两阶段提交协定,以便在分布式事务零碎中应用,但原生的 MySQL XA 存在完整性问题,如果在分布式场景中,Node1, Node2 … NodeN 作为节点参与方,XA 应用 2PC 保障分布式事务的原子性,但对于每个节点中的 Binlog Storage 和 InnoDB Storage 两个参与方,MySQL 目前没有机制保障在每个阶段(Prepare 或者 Commit) 不同 Storage 参与方之间的一致性,这也源于 Binlog Storage 自身没有 UNDO 的机制保障无关,这样 2PC 的解体复原协定也就无奈取得无效的节点事务状态。
为了保障严格的强一致性保障,PolarDB- X 多正本存储引擎除了应用两阶段提交协定的 External Coordinator 以外,引入了应用 GTID 弥补协定的 Internal Coordinator 来保障 Storage 之间的一致性。
GTID 弥补协定的次要工作原理:
- 在单个节点解体复原阶段,依据 Binlog File 构建 Binlog GTID 汇合;
- 在单个节点解体复原阶段,依据 InnoDB GTID_EXECUTED 以及 TRANSACTION UNDO HISTORY 构建 InnoDB GTID 汇合
- 构建汇合的差集,应用 Binlog Event 进行弥补 InnoDB 失落的事务,复原单个节点
- 实现单个节点的弥补后,XA 组件开始分布式集群的两阶段提交事务的解体复原
高性能数据同步
高吞吐的日志传输
X-Paxos 针对高提早网络做了大量的协定优化尝试和测试,并联合学术界现有的实践成绩通过正当的 Batching 和 Pipelining,设计并实现了一整套自适应的针对高提早高吞吐和低提早高吞吐网络的通信模式,极大地晋升了 X -Paxos 的性能。
Batching 是指将多个日志合并成单个音讯进行发送;Batching 能够无效地升高音讯粒度带来的额定损耗,晋升吞吐。然而过大 Batching 容易造成单申请的提早过大,导致并发申请数过高,继而影响了吞吐和申请提早。
Pipelining 是指在上一个音讯返回后果以前,并发地发送下一个音讯到对应节点的机制,通过进步并发发送音讯数量(Pipelining 数量),能够无效的升高并发单申请提早,同时在 transmission delay 小于 propagation delay 的时候(高提早高吞吐网络),无效晋升性能。
R 为网络带宽,D 为网络流传提早(propagation delay,约为 RTT/2),经推导可知 Batching(音讯大小:M)和 Pipeling(音讯并发:P)在 M/R * P = D
关系下,达到最高吞吐。
X-Paxos 联合以上实践,通过内置探测,针对不同节点的部署提早,自适应地调整针对每个节点的 Batching 和 Pipeling 参数,达到整体的最大吞吐。因 Pipeling 的引入,须要解决日志的乱序问题,特地是在异地场景下,window 加大,加大了乱序的概率。X-Paxos 实现了一个高效的乱序解决模块,能够对底层日志实现屏蔽乱序问题,实现高效的乱序日志存储。
高效的数据传输
因为 Paxos 的外部状态简单,实现高效的单实例多线程的 Paxos 变成一个十分大的挑战。比方开源产品 phxpaxos、Oracle MySQL Group Replication 中应用的 xcom,都是单线程的实现。phxpaxos 采纳了单调配单线程,多实例聚合的形式晋升总吞吐,然而对单分区的性能十分的无限;xcom 是一个基于协程的单线程实现。单线程的 Paxos 实现,在解决序列化 / 反序列化,散发、发包等逻辑的时候都为串行执行,性能瓶颈显著。
X-Paxos 齐全基于多线程实现,能够在单个分区 Paxos 中齐全地应用多线程的能力,所有的工作都由通用的 worker 来运行,打消了 CPU 的瓶颈。依赖于服务层的多线程异步框架和异步网络层,X-Paxos 除了必要的协定串行点外,大部分操作都能够并发执行,并且局部协定串行点采纳了无锁设计,能够无效利用多线程能力,实现了 Paxos 的单分片多线程能力,单分区性能远超竞品,甚至超过了竞品的多实例性能。
交融的日志模块
X-Paxos 和现有的大部分 Paxos 库很大的不同点就是 X -Paxos 反对可插拔的日志模块。日志模块是 Paxos 中一个重要的模块,它的长久化关系到数据的一致性,它的读写性能很大水平上会影响协定整体的读写性能。以后大部分独立 Paxos 库都是内置日志模块,并且不反对插拔的。这会带来 2 个弊病:
- 默认的日志模块提供通用的性能,很难联合具体的零碎做针对性的优化
- 现有的零碎往往曾经存在了 WAL(Write Ahead Log),而 Paxos 协定中须要再存一份。这使得
- 单次 commit 本地须要 sync 2 次,影响性能
- 双份日志节约了大量的存储,减少了老本
PolarDB- X 存储节点整合了 binary log 和 relay log,实现了对立的 consensus log,既节俭了日志存储的老本,又进步了性能。日志交融的理论改变,后面强一致性保障中曾经详细描述,这里不再开展。
灵便的运维容灾
在线增加节点 / 删除节点 / 切主
X-Paxos 在规范 Multi-Paxos 的根底上,反对在线增加 / 删除多种角色的节点,反对在线疾速将 leadership 节点转移到其余节点(有主选举)。这样的在线运维能力,将会极大中央便分布式节点的有计划性的运维工作,将 RTO 升高到最低。
策略化多数派 / 权重化选主
目前阿里多地架构会有核心机房的诉求,比方:利用因其部署的特点,往往要求在未产生城市级容灾的状况下,仅在核心写入数据库,数据库的 leader 节点在失常状况下只在核心地区;同时又要求在产生城市级容灾的时候(同一个城市的多个机房全副不可用),能够在齐全不失落任何数据的状况下,将 leader 点切换到非核心。
而经典的 Multi-Paxos 并不能满足这些需要。经典实践中,多数派强同步当前即可实现提交,而多数派是非特定的,并不能保障某个 / 某些节点肯定能失去残缺的数据,并激活服务。在理论实现中,往往地理位置较近的节点会领有强统一的数据,而地理位置较远的节点,始终处于非强统一节点,在容灾的时候永远无奈激活为主节点,形同虚设。同时当核心单节点呈现故障须要容灾的时候,往往须要将主节点就近切换到同核心的另外一个节点,而经典实践中同样没有相似的性能。
PolarDB- X 在 X -Paxos 协定中实现了策略化多数派和权重化选主:
- 基于策略化多数派,用户能够通过动静配置,指定某个 / 某些节点必须保有强统一的数据,在呈现容灾需要的时候,能够立刻激活为主节点
- 基于权重化选主,用户能够指定各个节点的选主权重,只有在高权重的节点全副不可用的时候,才会激活低权重的节点
低成本的数据存储
在经典的 Multi-Paxos 实现中,个别每个节点都蕴含了 Proposer/Accepter/Learner 三种性能,每一个节点都是全功能节点。然而某些状况下咱们并不需要所有节点都领有全副的性能,例如:1. 经典的三个正本部署中,咱们能够裁剪其中一个节点的状态机,只保留日志(无数据的纯日志节点,然而在同步中作为多数派计算),此时咱们须要裁剪掉协定中的 Proposer 性能(被选举权),保留 Accepter 和 Learner 性能。2. 咱们心愿能够有若干个节点能够作为上游,订阅 / 生产协定产生的日志流,而不作为集群的成员(不作为多数派计算,因为这些节点不保留日志流),此时咱们裁剪掉协定的 Proposer/Accepter 性能,只保留 Learner 性能。
多正本的技术尽管比主备同步的形式更加高性能和高可用,但多正本自身引入的多份数据存储开销难以避免的痛点。PolarDB- X 多正本存储引擎深入研究了解协定发现,在经典的 Multi-Paxos 实现中,个别每个节点都蕴含了 Proposer/Accepter/Learner 三种性能,每一个节点都是全功能节点。然而某些状况下咱们并不需要所有节点都领有全副的性能,例如:
- 经典的三个正本部署中,咱们能够裁剪其中一个节点的状态机,只保留日志(无数据的纯日志节点,然而在同步中作为多数派计算),此时咱们须要裁剪掉协定中的 Proposer 性能(被选举权),保留 Accepter 和 Learner 性能。
- 咱们心愿能够有若干个节点能够作为上游,订阅 / 生产协定产生的日志流,而不作为集群的成员(不作为多数派计算,因为这些节点不保留日志流),此时咱们裁剪掉协定的 Proposer/Accepter 性能,只保留 Learner 性能。
PolarDB- X 翻新地引入 Learner/Logger 角色正本,通过对节点角色的定制化组合,咱们能够开发出很多的定制性能节点,既节约了老本,又丰盛了性能。
典型的三节点复制模式如下图所示。通过对节点角色的定制化组合,在三正本部署,一个节点持续作为全功能正本 Leader,一个节点持续作为 Follower,另外一个 Follower 节点配置为仅做 Logger 角色,这样能够将三正本的三份数据老本优化为只有两份,同时不影响高可用的保障。再借助 PolarDB- X 残缺兼容的 MySQL Binlog,能够无缝兼容 OSS、DTS、Canal 等业内罕用的 Binlog 增量订阅工具,实现数据的异地低成本备份。
作者:冷香、严华
点击立刻收费试用云产品 开启云上实际之旅!
原文链接
本文为阿里云原创内容,未经容许不得转载。