数据库容灾 | MySQL MGR 与阿里云 PolarDB-X Paxos 的深度对比
作者:严华、七锋
PolarDB 分布式版 (PolarDB for Xscale,简称“PolarDB-X”) 是阿里云自主设计研发的高性能云原生分布式数据库产品,为用户提供高吞吐、大存储、低延时、易扩展和超高可用的云时代数据库服务。PolarDB-X 于 2021 年正式开源。
开源生态
众所周知,MySQL 主备库(两节点)一般通过异步复制、半同步复制(Semi-Sync)来实现数据高可用,但主备架构在机房网络故障、主机 hang 住等异常场景下,HA 切换后大概率就会出现数据不一致的问题(简称 RPO!=0),因此但凡业务数据有一定的重要性,都不应该选择 MySQL 主备架构(两节点)的数据库产品,推荐选择 RPO=0 的多副本架构。
MySQL 社区,对于 RPO=0 的多副本技术演进:
MySQL 官方开源,推出了基于组复制的 MySQL Group Replication(MGR)高可用解决方案,内部通过 XCOM 封装了 Paxos 协议提供了数据一致性的保障。
阿里云 PolarDB-X,来源于阿里电商双十一、异地多活的业务打磨和验证,在 2021 年 10 月份进行了全内核开源,全面拥抱 MySQL 开源生态。PolarDB-X 定位为一款集中分布式一体化数据库,其数据节点 Data Node(DN)采用了自研的 X-Paxos 协议,高度兼容 MySQL 5.7/8.0,不仅提供了金融级高可用能力,还同时具备高扩展的事务引擎、灵活的运维容灾、低成本的数据存储的特点,参考:《PolarDB-X 开源 | 基于Paxos的MySQL三副本》。
PolarDB-X 集中分布式一体化的理念:数据节点 DN 可以被独立出来作为集中式(标准版)形态,完全兼容单机数据库形态。当业务增长到需要分布式扩展的时候,架构原地升级成分布式形态,分布式组件无缝对接到原有的数据节点,不需要数据迁移,也不需要应用侧做改造,即可享受分布式带来的可用性与扩展性,架构说明:《集中分布式一体化》
MySQL 的 MGR 和 PolarDB-X 的标准版 DN,两者从最底层的原理上都采用了 Paxos 协议,那么在实际使用上,具体的表现和差异如何呢?本文从架构对比、关键差异、测试对比方面进行分别详细阐述。
MGR/DN 简称说明:MGR 代表 MySQL MGR 的技术形态、DN 代表 PolarDB-X 单 DN 集中式(标准版)的技术形态。
TL;DR
详细对比分析比较长,可以先看一下总结和结论,有兴趣的话可以顺着总结在后续文章中找一下线索。MySQL MGR,一般的业务和公司都不建议使用,因为需要有专业的技术知识和运维团队才有机会用好,本文也复现了 MySQL MGR 三个业界流传已久的"暗坑":
暗坑 1:MySQL MGR,XCOM 协议走了全内存模式,默认是不满足 RPO=0 的数据一致性保证(本文后续有 testcase 复现丢数的问题),需要显示配置一个参数才可以保证,目前 MGR 的设计上性能和 RPO 无法兼得
暗坑 2:MySQL MGR 在有网络延迟下性能比较拉胯,文章中测试了 4 钟网络场景的对比(包括同城 3 机房、两地三中心),性能参数配置下跨城只有同城的 1/5,如果再开启 RPO=0 的数据保证,性能更没法看。因此,MySQL MGR 更适合用在同机房场景,跨机房容灾不适合
暗坑 3:MySQL MGR 的多副本架构,备节点的故障都会让主节点 Leader 出现流量跌 0,不太符合常理。文章中重点尝试开启 MGR 的单 Leader 模式(对标 MySQL 以前的主备副本架构),模拟备副本的宕机和恢复的两个动作,备节点的运维操作也会让主节点(Leader)出现流量跌 0(持续 10 来秒),整体的可运维性比较差。因此,MySQL MGR 在主机运维上要求比较高,需要专业的 DBA 团队
PolarDB-X Paxos 相比于 MySQL MGR,在数据一致性、跨机房容灾、节点运维上都没有 MGR 类似的坑,但也有个别小缺点、以及容灾上的优点:
简单的同机房场景下,小并发下的只读性能、高并发下的纯写性能,比 MySQL MGR 略低 5%左右,同时多副本的网络发送,性能上有进一步的优化空间
优点:100%兼容 MySQL 5.7/8.0 的特性,同时在多副本的备库复制、故障切换路径上做了比较多的精简优化,高可用切换 RTO<=8 秒,业界常见的 4 钟容灾场景都表现不错,可以替换 semi-sync(半同步)、MGR 等
1. 架构对比
名词解释
MGR/DN 简称说明:
MGR:MySQL MGR 的技术形态,后续内容简称:MGR
DN:阿里云 PolarDB-X 集中式(标准版)的技术形态,其中分布式下的数据节点 DN 可以被独立出来作为集中式(标准版)形态,完全兼容单机数据库,后续内容简称:DN
MGR
MGR 支持单主、多主模式,完全复用 MySQL 的复制系统,包括 Event、Binlog & Relaylog 、Apply、Binlog Apply Recovery、GTID。与 DN 的关键区别在于 MGR 事务日志多数派达成一致的切入点在主库事务提交之前。
Leader:
事务提交前调用 before_commit 钩子函数 group_replication_trans_before_commit,进入 MGR 的多数派复制
MGR 借助 Paxos 协议,将 THD 上缓存的 Binlog Events 同步所有在线节点
MGR 收到多数派应答后,确定可以提交事务
THD 进入事务组提交流程 ,开始写本地 Binlog 更新 Redo 回复客户端 OK 报文
Follower:
MGR 的 Paxos Engine 持续侦听来自 Leader 的协议消息
经过完整的一次 Paxos 共识过程,确认这个(批)Event 在集群已经达到多数派
将接收的 Event 写入 Relay Log,IO Thread Apply Relay Log
Relay Log 应用走完整的组提交流程,备库会最终会生成自己的 binlog 文件
MGR 采用上述流程的原因,是因为 MGR 默认是多主模式,每个节点都可以写,所以单个 Paxos Group 内 Follower 节点需要将接受的日志先转成 RelayLog,然后结合自身作为 Leader 接收的写事务提交,在两阶段组提交流程中生产 Binlog 文件提交最终事务。
DN
DN 复用了 MySQL 的基础数据结构和函数级代码,但是将日志复制、日志管理、日志回放、崩溃恢复环节跟 X-Paxos 协议紧密结合在了一起,形成了自己的一套多数派复制和状态机机制。与 MGR 的关键区别在于 DN 事务日志多数派达成一致的切入点在主库事务提交过程中。
Leader:
进入事务的组提交流程,在组提交的 Flush 阶段,将各 THD 上的 Events 写入 Binlog 文件,然后再通过 X-Paxos 将日志异步广播给所有 Follower
在组提交的 Sync 阶段,先持久化 Binlog,然后更新 X-Paxos 持久化的位点
在组提交的 Commit 阶段,先要等待 X-Paxos 收到多数派应答后,然后提交这组事务,最后回复客户端 OK 报文
Follower:
X-Paxos 持续侦听来自 Leader 的协议消息
收到一个(组) Events,写入到本地 Binlog,回应答
收到下一个消息,其中携带了已经达成多数派的位点 Commit index
SQL Apply 线程后台持续应用接收到的 Binlog 日志,最多只应用到多数派位点位置
这种设计的原因是,DN 当前只支持单主模式,所以 X-Paxos 协议层面的日志就是 Binlog 本身,Follower 也省去了 Relay Log,其持久化的日志和 Leader 等的日志的数据内容是等价相同的。
2. 关键差异
2.1. Paxos 协议效率
MGR
MGR 的 Paxos 协议基于 Mencius 协议实现,属于 Multi-Paxos 理论,区别在于 Mencius 在降低主节点负载提高吞吐量上做了优化改进
MGR 的 Paxos 协议的由 XCOM 组件实现,支持多主和单主模式部署,单主模式时 Leader 上 Binlog 向 Follower 节点的原子广播,每批消息(一个事务)的广播是标准的一次 Multi-Paxos 过程
一个事务的多数派的满足,XCOM 至少需要经历 Accept+AckAccept+Learn 三个报文交互,即至少 1.5 个 RTT 开销。最多需要经历 Prepare+AckPrepare+Accept+AckAccept+Learn 三个报文交互,即最多一共 2.5 个 RTT 开销
由于 Paxos 协议是在 XCOM 模块内高内聚完成的,MySQL 复制系统不感知, 所以 Leader 必须等待完整的 Paxos 过程完毕才能进行事务本地提交,包括 Binlog 的持久化和组提交
Follower 在完成多数派提交后,会异步进行 Events 的持久化到 Relay Log,然后由 SQL Thread 应用和组提交生产 Binlog
由于 Paxos 同步的日志是进入组提交流程前没有排序的 Binlog,所以 Leader 上 Binlog Event 的顺序,和 Follower 节点上 Relay Log 的 Event 顺序未必相同
DN
DN 的 Paxos 协议是基于 Raft 协议实现,也属于 Multi-Paoxs 理论,区别在于 Raft 协议更强 Leadership 保障和工程稳定性保证
DN 的 Paxos 协议由 X-Paoxs 组件完成,默认是单主模式,单主模式时 Leader 上 Binlog 向 Follower 节点的原子广播,每批消息的广播是标准的一次 Raft 过程。
一个事务的多数派的满足,X-Paoxs 只需要经历 Append+AckAppend 两个报文交互,只有 1 个 RTT 开销
Leader 发给 Follower 日志后,只要多数派满足,它就提交事务,不等待第二阶段的 Commit Index 广播
Follower 在完成多数派提交的前提,需要要全部事务日志必须持久化,这点与 MGR 的 XCOM 有显著差别, MGR 只需要在 XCOM 内存中接收到即可
Commit Index 在后续消息和心跳消息中带过去,Follower 在 CommitIndex 推高后,再进行 Apply Event
Leader 和 Follower 的 Binlog 内容顺序一致,Raft 日志无空洞,并且用 Batching/Pipeline 机制加大日志复制吞吐量
相比 MGR,事务提交时 Leader 始终只有一次来回的延迟,对延迟敏感的分布式应用十分很关键
2.2. RPO
理论上 Paxos 和 Raft 都可以保证数据一致性,以及 Crash Recovery 后已经达成多数派的日志不丢失,但是在具体工程上还是有区别。
MGR
XCOM 完全封装了 Paxos 协议,而它的所有协议数据又都是先缓存在内存中,默认情况事务达成多数派不要求日志持久化。在多数派宕机、Leader 故障的情况下,在会有 RPO != 0 严重问题。假设一极端场景:
MGR 集群由三个节点 ABC 组成, 其中 AB 同城独立机房,C 是跨城。A 是 Leader, BC 是 Follower 节点
在 Leader A 节点上发起事务 001, Leader A 将事务 001 的日志广播给 BC 节点,通过 Paxos 协议满足多数派即可认为事务可以提交。AB 节构成了多数派,C 节点由于跨城网络延迟并没有收到事务 001 的日志
下一个时刻,Leader A 提交了事务 001 并返回 Client 成功,此时表示事务 001 已经提交到数据库
此刻 B 节点的 Follower 上,事务 001 的日志还在 XCOM 缓存中,还没来得及刷到 RelayLog 中;此刻 C 节点的 Follower 上仍然没有接收到 A 节点的 Leader 的发过来的事务 001 日志
此时,AB 节点宕机, A 节点故障长时间不能恢复,B 节点很快重启恢复, BC 两节点继续提供读写服务
由于宕机时事务 001 日志并没有持久化到节点 B 的 RelayLog 中,也没有被节点 C 接收到,因此此刻 BC 节点其实都已经丢失了事务 001,并且无法找回
这种多数派宕机的场景下,导致了 RPO!=0
社区默认参数下,事务达成多数派不要求日志持久化,不保证 RPO=0,可以认为是 XCOM 工程实现中为了性能的取舍。要想保证绝对的 RPO=0, 需要将控制读写一致性的参数 group_replication_consistency 配置为 AFTER,但这样的话,事务达成多数派除了需要 1.5 个 RTT 网络开销外,还需要一次日志 IO 开销,性能会很差。
DN
PolarDB-X DN 采用 X-Paxos 实现分布式协议, 与 MySQL 的 Group Commit 流程深度绑定,在一个事务进行提交时,强制要求多数派确认落盘持久化后,才能允许真正提交。这里多数派落盘是指主库的 Binlog 落盘,备库的 IO 线程接收到主库的日志并落盘持久化到自己 Binlog 中。因此即使在极端场景下所有节点故障,数据也不会丢失,也能保证 RPO=0。
2.3. RTO
RTO 时间与系统本身冷重启的时间开销密切相关,反映到具体基础功能上,就是:故障检测机制->崩溃恢复机制->选主机制->日志追平
2.3.1. 故障检测
MGR
每个节点周期性向其他节点发送心跳包检测其他节点是否健康,心跳周期固定是 1s,无法调整
当前节点如果发现其他节点超过 group_replication_member_expel_timeout(默认 5s)后没有响应则视为失效节点,并从集群中踢出
像网络闪断或者异常重启这种异常,待网络恢复后,单个故障节点自己会尝试自动加入集群,然后追平日志
DN
Leader 节点周期性向其他节点发生心跳检包检查其他节点是否健康,心跳周期为选举超时时间的 1/5。选举超时时间由参数 consensus_election_timeout 控制, 默认 5s,所以 Leader 节点心跳周期默认 1s
Leader 如果发现其他掉线了,仍然继续周期性想其他所有节点发送心跳包,以确保其他节点崩溃恢复后能及时接入。但是 Leader 节点不再向已经掉线的节点发送事务日志
非 Leader 节点不发送心跳检测包,但是非 Leader 节点如果发现超过 consensus_election_timeout 时间没有收到 Leader 节点的心跳,则触发重新选举
像网络闪断或者异常重启这种异常,待网络恢复后,故障节点自己会自动加入集群
因此在故障检测方面,DN 提供了更多运维配置接口,对于跨城部署场景故障的识别度会更加准确
2.3.2. 崩溃恢复
MGR
XCOM 实现的 Paxos 协议是内存态,多数派的达成不要求持久化,协议状态以存活的多数派节点内存状态为准。如果所有节点都挂掉,也就无法恢复协议了,集群重启后此时需要人工介入进行恢复
如果只是单个节点崩溃恢复,但是 Follower 节点落后 Leader 节点较多事务日志,此刻 Leader 上的 XCOM 缓存的事务日志已经清除了,就只能走 Global Recovery 或 Clone 流程
XCOM 缓存大小由 group_replication_message_cache_size 控制,默认 1GB
Global Recovery 是指节点重新加入集群时,通过从其他节点获取所需的缺失事务日志(Binary Log)来恢复数据。这个过程依赖于集群中至少有一个节点保留了所有需要的事务日志
Clone 依赖 Clone Plugin,用于数据量较大或缺失较多日志时的恢复。它通过将整个数据库的快照复制到崩溃的节点,然后通过最新事务日志进行最终同步
Global Recovery 和 Clone 流程通常是自动化的,但在某些特殊情况下,如网络问题或者其他两个节点 XCOM 缓存都清除了,这时需要人工介入解决
DN
X-Paxos 协议使用 Binlog 持久化,崩溃恢复时,会先完整恢复已提交事务。对于悬挂事务,需要等待 XPaxos 协议层先达成一致确定主备关系后,再进行提交或者回滚处理。整个流程全自动化。即使如果所有节点都挂掉,集群重启也能自动恢复
对于 Follower 节点落后 Leader 节点很多事务日志场景,只要 Leader 上 Binlog 文件没有删除,Follower 节点就一定追上
因此在崩溃恢复方面,DN 是完全不需要人工介入的
2.3.3. 选主
单主模式下, MGR 的 XCOM 和 DN X-Paxos 这种强 Leader 模式的选主,所遵循的基本原则是一样的--集群已共识的日志不能回退。但是到未共识的日志时,存在差异
MGR
选主更多意义上是接下来哪个节点充当 Leader 服务,这个 Leader 当选时不一定拥有最新的共识日志,所以它需要从集群的其他节点同步最新日志,待日志追平后提供读写服务
这样的好处是,Leader 本身的选择是个策略化的产物,比如权重,比如顺序。MGR 通过 group_replication_member_weight 参数控制各节点权重
劣处是新当选的 Leader 本身可能复制延迟较多,需要继续追平日志,或者应用延迟较多,需要继续追平日志应用,才能提供读写服务。这会导致 RTO 时间较长
DN
选主就是协议意义上的,哪个节点拥有集群全部多数派的日志,它就可以当选 Leader,所以这个节点之前可能是 Follower,也可能是 Logger
而 Logger 是不能提供读写服务的,等它把日志同步给其他节点后,自己就主动让出 Leader 角色
为了能确保指定节点成为 Leader,DN 使用乐观权重策略+强制权重策略来限定当主顺序,使用策略化多数派机制确保新主零延迟立刻能提供读写服务
因此在选主方面,DN 不仅支持与 MGR 一样的策略化选择,还支持强制权重策略
2.3.4. 日志追平
日志追平是指主备之间日志存在日志复制延迟,备库需要追平日志。对于重启恢复的节点,通常都是以备库开始恢复,并且已经和主库产生了比较的的日志复制延迟,需要向主库追平日志。对于那些和 Leader 物理距离较远的节点,多数派达成通常和它们没关系,它们总是存在复制日志延迟一直在追平日志。这些情况都需要具体工程实现来确保日志复制延迟的及时解决。
MGR
事务日志都在 XCOM 缓存中,而缓存默认只有 1G,所以复制落后很多的 Follower 节点请求日志的时候,很容易缓存早已被清理
此时这个落后的 Follower 会自动踢出集群,然后以前面崩溃恢复提到 Global Recovery 或 Clone 流程,追平后再自动加入集群。如果遇到如网络问题,或者其他两个节点 XCOM 缓存都清除的情况,这时需要人工介入解决
为什么一定要先踢出集群,因为多写模式故障节点极大影响性能,且 Leader 的缓存对它没有任何作用,异步追平后再加进来
为什么不能使用直接读取 Leader 本地的 Binlog 文件,因为前面提到的 XCOM 协议是全内存态,Binlog 和 Relay Log 中没有任何关于 XCOM 的协议信息
DN
数据都在 Binlog 文件上,只要 Binlog 没有清理,那按需发送就好了,不存在踢出集群的情况
为了降低主库从 Binlog 文件中读取老的事务日志带来的 IO 抖动,DN 优先从 FIFO Cache 中读取最近缓存的事务日志, FIFO Cache 由参数 consensus_log_cache_size 控制,默认 64M
如果 FIFO Cache 中老的事务日志已经更新的事务日志淘汰掉了,DN 会尝试从 Prefetch Cache 中读取之前缓存的事务日志,Prefetch Cache 有参数 consensus_prefetch_cache_size 控制,默认 64M
如果 Prefetch Cache 中也没有需要的老的事务日志,DN 会尝试发起异步 IO 任务,批量从 Binlog 文件中读取指定事务日志前后若干连续的日志,放置在 Prefetch Cache 中,等待 DN 下一次重试读取
因此在追平日志方面,DN 完全不需要人工介入
2.4. 备库回放延迟
备库回放延迟是同一个事务在主库完成提交的时刻与在备库完成事务应用的时刻之间的延迟,这里考验的是备库 Apply 应用日志的性能。它影响的是异常发生时,备库成为新主后需要多久才能自身数据应用完毕可以提供读写服务。
MGR
MGR 备库从主库接收落盘的是 RelayLog 文件,Apply 应用时需要重新将 RelayLog 读取,经历完整两阶段组提交流程,生产对应的数据和 Binlog 文件
这里事务应用效率与主库上事务提交效率相同,默认的双一配置(innodb_flush_log_at_trx_commit、sync_binlog)会导致备库应用同样资源开销较大
DN
DN 备库从主库接收落盘的就是 Binlog 文件,应用时需要重新将 Binlog 读取,只需要经历一阶段组提交流程,生产对应的数据即可
由于 DN 支持完整的 Crash Recover,备库应用不需要开启 innodb_flush_log_at_trx_commit=1,因此实际上不受双一配置的影响
因此在备库回放延迟方面,DN 备库回放效率会远大于 MGR
2.5. 大事务影响
大事务不仅影响普通事务提交,在分布式系统中还影响整个分布式协议运行的稳定性,严重情况下一个大事务就会导致整个集群较长时间的不可用。
MGR
MGR 对大事务的支持没有任何优化, 只是增加了参数 group_replication_transaction_size_limit 控制大事务上限,默认 143M,最大 2GB
当事务日志超过大事务限制后,会直接报错,事务无法提交
DN
针对大事务带来的分布式系统的不稳定问题, DN 采取大事务拆分+大对象拆分的方案进行根治, DN 会将大事务的事务日志进行逻辑拆分+物理拆分的方式拆分为一个个小块的的事务日志,每个小块的事务日志使用完整的 Paxos 提交保证
基于大事务拆分的方案,DN 对大事务的大小不做任何限制,用户可以随意使用, 同样能保证 RPO=0
因此在大事务问题的处理上,DN 能做到不受大事务影响
2.6. 部署形态
MGR
MGR 支持单主、多主的部署模式,多主模式下每个节点可读可写,单主模式时主库可读可写,备库只能只读
MGR 高可用部署至少三节点部署,也即至少三份数据和日志, 不支持日志副本 Logger 形态
MGR 不支持只读节点的扩展,但是支持 MGR+主从复制模式的组合,实现类似拓扑扩展
DN
DN 支持单主模式部署,单主模式时单主模式时主库可读可写,备库只能只读
DN 高可用部署至少三节点部署,但支持日志副本 Logger 形态,也即 Leader、Follower 都是全功能副本,Logger 相比缺少只有日志没有数据,并且没有被选举权。这样的话三节点高可用部署只需要 2 份数据+3 份日志的存储开销,低成本部署
DN 支持只读节点部署,支持只读副本 Learner 形态,相比全功能副本仅是不具备投票权,通过 Learner 副本实现下游对主库的订阅消费
2.7. 特性小结
3. 测试对比
MGR 是 MySQL 5.7.17 开始引入的,但更多 MGR 相关特性都只在 MySQL 8.0 上才有,并且在 MySQL 8.0.22 及之后的版本,整体会更稳定可靠。因此我们选择双方的最新版 8.0.32 版本进行对比测试。
考虑到 PolarDB-X DN 和 MySQL MGR 在对比测试时,存在测试环境差异、编译方式差异、部署方式差异、运行参数差异、测试手段差异,进而可能导致测试对比数据不准确,本文在各项细节上采用如下方式进行:
注:
MGR 默认开启了流控,而 PolarDB-X DN 默认关闭流控。因此对 MGR 的 group_replication_flow_control_mode 单独配置关闭,这样 MGR 的性能会是最好的
点查时 MGR 有明显 so 读取瓶颈,因此对 MGR 的 replication_optimize_for_static_plugin_config 单独配置开启,这样 MGR 的只读性能会是最好的
3.1. 性能
性能测试是大家在选型数据库时首先关注的一点。这里我们使用官方 sysbench 工具,构建 16 张表,每张表 1 千万数据,进行 OLTP 场景的性能测试,测试对比不同 OLTP 场景下不同并发时两者的表现。考虑到实际部署的不同情况, 我们分别模拟下面 4 种部署场景
同机房,一个机房内部署三节点,机器之间互相 ping 带 0.1ms 的网络延迟
同城三中心,同地域三个机房部署三节点,机房之间互相 ping 带 1ms 的网络延迟(比如:上海地域的三个机房)
两地三中心,两地三个机房部署三节点,同城机房之间 ping 带 1ms 的网络,同城和异地之间带 30ms 的网络延迟(比如:上海/上海/深圳)
三地三中心,三地三个机房部署三节点(比如:上海/杭州/深圳),杭州-上海之间 ping 带 5ms 左右的网络延迟,杭州/上海 到深圳距离最远的为 30ms 的网络延迟
说明:
a. 考虑 4 个部署场景性能的横向对比,两地三中心、三地三中心都采用 3 副本的部署模式,真实生产业务可以扩展到 5 副本的部署形态。
b. 考虑到实际使用高可用数据库产品时对 RPO=0 的严格限制,但是 MGR 默认配置 RPO<>0,这里在各部署场景下,我们继续增加 MGR RPO<>0 和 RPO=0 的对比测试。
MGR_0 表示 MGR RPO = 0 情况的数据
MGR_1 表示 MGR RPO <> 0 情况的数据
DN 表示 DN RPO = 0 情况的数据
3.1.1. 同机房
从测试结果可以看出:
在只读场景,无论是对比 MGR_1(RPO<>0)还是 MGR_0(RPO=0),DN 与 MGR 之间的差异稳定在-5%~10%之间,可以认为基本相同。RPO 是否等于 0 对只读事务不影响
在读写混合、只写事务场景,在 DN(RPO=0)相比 MGR_1 时(RPO<>0)性能提升了 5%~47%,并且呈现低并发时 DN 性能优势明显,高并发时优势不明显的特点。这是由于低并发时 DN 的协议效率更高,但高并发下 DN 和 MGR 的性能热点都在刷脏上所致
而在相同的 RPO=0 的前提下,在读写混合、只写事务场景,在 DN 相比 MGR_0 性能提升了 2 倍-46 倍,并且随着并发提高,DN 性能优势加强的特点。也难怪 MGR 默认也要为了性能而舍弃 RPO=0
3.1.2. 同城三中心
从测试结果可以看出:
在只读场景,无论是对比 MGR_1(RPO<>0)还是 MGR_0(RPO=0),DN 与 MGR 之间的差异稳定在-7%~5%之间,可以认为基本相同。RPO 是否等于 0 对只读事务不影响
在读写混合、只写事务场景,在 DN(RPO=0)相比 MGR_1 时(RPO<>0)性能提升了 30%~120%,并且呈现低并发时 DN 性能优势明显,高并发时优势不明显的特点。这是由于低并发时 DN 的协议效率更高,但高并发下 DN 和 MGR 的性能热点都在刷脏上所致
而在相同的 RPO=0 的前提下,在读写混合、只写事务场景,在 DN 相比 MGR_0 性能提升了 1 倍-14 倍,并且随着并发提高,DN 性能优势加强的特点。也难怪 MGR 默认也要为了性能而舍弃 RPO=0
3.1.3. 两地三中心
从测试结果可以看出:
在只读场景,无论是对比 MGR_1(RPO<>0)还是 MGR_0(RPO=0),DN 与 MGR 之间的差异稳定在-4%~7%之间,可以认为基本相同。RPO 是否等于 0 对只读事务不影响
在读写混合、只写事务场景,在 DN(RPO=0)相比 MGR_1 时(RPO<>0)性能提升了 2 倍~16 倍,并且呈现低并发时 DN 性能优势明显,高并发时优势不明显的特点。这是由于低并发时 DN 的协议效率更高,但高并发下 DN 和 MGR 的性能热点都在刷脏上所致
而在相同的 RPO=0 的前提下,在读写混合、只写事务场景,在 DN 相比 MGR_0 性能提升了 8 倍-29 倍,并且随着并发提高,DN 性能优势加强的特点。也难怪 MGR 默认也要为了性能而舍弃 RPO=0
3.1.4. 三地三中心
从测试结果可以看出:
在只读场景,无论是对比 MGR_1(RPO<>0)还是 MGR_0(RPO=0),DN 与 MGR 之间的差异稳定在-5%~0%之间,可以认为基本相同。RPO 是否等于 0 对只读事务不影响
在读写混合、只写事务场景,在 DN(RPO=0)相比 MGR_1 时(RPO<>0)性能提升了 2 倍~5 倍,并且呈现低并发时 DN 性能优势明显,高并发时优势不明显的特点。这是由于低并发时 DN 的协议效率更高,但高并发下 DN 和 MGR 的性能热点都在刷脏上所致
而在相同的 RPO=0 的前提下,在读写混合、只写事务场景,在 DN 相比 MGR_0 性能提升了 2 倍-17 倍,并且随着并发提高,DN 性能优势加强的特点。也难怪 MGR 默认也要为了性能而舍弃 RPO=0
3.1.5. 部署对比
为了明显对比不同部署方式下性能的变化差异,我们选择上述测试中 oltp_write_only 场景 256 并发下不同部署方式下的 MGR 和 DN 的 TPS 数据,以机房测试数据为基线,计算对比不同部署方式时 TPS 数据相比基线的比例,以此感知跨城部署时性能变化差异
从测试结果可以看出:
随着部署方式的扩大化,MGR_1(RPO<>0)的 TPS 下降明显,相比同机房部署,同城跨机房部署性能下降 27.5%, 跨城(两地三中心、三地三中心)部署性能下降 77%~82%,这是由于跨城部署 RT 增加导致
而 DN(RTO=0)则相对稳定,相比同机房部署,同城跨机房、两地三中心部署性能下降 4%~12%, 三地三中心在高网络延迟下部署时性能下降 37%,这也是由于跨城部署 RT 增加导致。不过得益于 DN 的 Batch&Pipeline 机制,跨城带来的影响可以通过提高并发的来解决,比如三地三中心架构下在>=512 并发下基本可以对齐同城、两地三中心下的性能吞吐
由此可见跨城部署对 MGR_1(RPO<>0)的影响很大
3.1.6. 性能抖动
实际使用中,我们不仅关注性能数据如何,还需要关注性能抖动情况。毕竟如果抖动像过山车一样,对实际用户的体验也非常差。我们对 TPS 实时输出数据监控展示,考虑到 sysbenc 工具本身不支持输出性能抖动的监测数据,于是采用数学上的变异系数作为对比指标:变异系数(Coefficient of Variation, CV):
变异系数是标准差除以平均值,通常用来比较不同数据集的波动情况,尤其是当平均值差异较大时。CV 越大,数据相对于平均值的波动越大
以 256 并发下 oltp_read_write 场景为例,我们统计分析 MGR_1(RPO<>0)、DN(RPO=0)在同机房、同城三中心、两地三中心、三地三中心五种部署模式下的 TPS 抖动情况。实际抖动图如下,实际各场景抖动指标数据如下
从测试结果可以看出:
MGR 在 oltp_read_write 场景下 TPS 呈现不稳定的状态,中间竟然无缘无故猛跌现象,在多个部署场景多次试验中均发现这个现象。相比下 DN 就十分稳定
计算变异系数 CV, MGR 的 CV 很大 6%~10%,同机房延迟最小的情况时竟然还达到最大值 10%,而 DN 的 CV 为比较稳定 2%~4%, DN 比 MGR 的性能稳定性基本高到 2 倍
由此可见 MGR_1(RPO<>0)的性能抖动比较大
3.2. RTO
分布式数据库的核心特点就是高可用,集群中任何一个节点的故障都不影响整体的可用性。针对同机房场景部署一主两备的 3 节点典型部署形态,我们尝试对对一下三种场景进行可用性的测试:
中断主库,然后重启,观察过程中集群恢复可用性的 RTO 时间
中断任意一个备库,然后重启,观察过程中主库的可用性表现
3.2.1. 主库宕机+重启
无负载情况下, kill leader, 监控集群各节点状态变化以及是否可写,
从测试结果可以看出,在无压力的情况下:
DN 的 RTO 在 8-15s, 降为 2 节点需要 8s,恢复 3 节点需要 15s;
MGR 的 RTO 在 23-37s, 降为 2 节点需要 23s,恢复 3 节点需要 37s
RTO 表现 DN 整体优于 MGR
3.2.2. 备库宕机+重启
使用 sysbench 进行 oltp_read_write 场景下 16 个线程的并发压测,在图中第 10s 的时刻,手动 kill 一个备节点,观察 sysbench 的的实时输出 TPS 数据。
从测试结果图中可见:
中断备库后,MGR 的主库 TPS 大幅下降,持续 20s 左右才恢复正常水平。根据日志分析,这里经历了检测故障节点变成 unreachable 状态、将故障节点踢出 MGR 集群两个过程。这个测试证实了 MGR 社区流传很久的一个缺陷,在 3 节点中即使只有 1 个节点不可用,整个集群就有一段时间的剧烈抖动不可用
针对单主时 MGR 存在单节点故障整个实例不可用的问题,社区从 8.0.27 中引入了 MGR paxos single leader 功能解决,但默认关闭。这里我们将 group_replication_paxos_single_leader 开启后继续验证,这次中断备库后主库性能保持稳定,并且稍微还有所提升了,原因应该与网络负载降低有关
对于 DN,中断备库后,主库 TPS 反而立刻上升约 20%, 随后一直保持稳定,集群也一直处于可用状态。这里和 MGR 相反的表现,原因是中断一个备库后主库每次只用向剩下一个备库发送日志,网络收发包流程效率更高了
继续测试,我们将备库重启恢复,观察主库 TPS 数据变化
从测试结果图中可见:
MGR 在 5s 时刻从 2 节点恢复成 3 节点,但同样存在着主库不可用, 持续时间大约 12s。尽管备库节点最终加入集群,但 MEMBER_STATE 状态一直为 RECOVERING,说明此时正在追数据
对 group_replication_paxos_single_leader 开启后的场景同样进行备库重启的验证,结果 MGR 在 10s 时刻从 2 节点恢复成 3 节点,但仍然出现了持续时间大约 7s 的不可用时间,看来这个参数并不能完全解决单主时 MGR 存在单节点故障整个实例不可用的问题。
对于 DN,备库在 10s 时刻从 2 节点恢复成 3 节点,主库一直保持可用状态。这里 TPS 会有短暂的波动,这个是由于重启后备库日志复制延迟落后较多,需要从主库拉取落后的日志,因此对主库产生少量影响,待日志追评后,整体性能就处于稳定状态。
3.3. RPO
为了构造 MGR 多数派故障 RPO<>0 场景,我们使用社区自带的 MTR Case 方式,对 MGR 进行故障注入测试,设计的 Case 如下:
suite/group_replication/t/rpo_not_zero_when_crash_majority_members.test
suite/group_replication/t/rpo_not_zero_when_crash_majority_members.cnf
Case 运行结果如下:
suite/group_replication/r/rpo_not_zero_when_crash_majority_members.result
复现丢数的 Case 大概逻辑是这样的:
MGR 由 3 个节点组成单主模式,Server 1/2/3,其中 Server 1 为主库,并初始化 1 条记录 c1=1
故障注入 Server 2/3 在写 Relay Log 时会 hang 住
连接到 Server 1 节点,写入了 c1=2 的记录,事务 commit 也返回了成功
然后 Mock server1 的异常 crash(机器故障,不能恢复,无法访问),此时剩下 Server 2/3 形成多数派
正常重启 Server 2/3(快速恢复),但是 Server 2/3 无法恢复集群可用状态
连接 Server 2/3 节点,查询数据库记录,仅看到了 c1=1 的记录(Server 2/3 都丢失了 c1=2)
根据以上 Case 可见,对于 MGR,当多数派宕机,主库不可用,备库恢复后,存在数据丢失的 RPO<>0 的情况,原本已返回客户端 commit 成功的记录丢了。
而对于 DN,多数派的达成需要日志在多数派中都持久化,所以即使在上述场景下,数据也不会丢失,也能保证 RPO=0。
3.4. 备库回放延迟
MySQL 的传统主备模式下,备库一般会包含 IO 线程和 Apply 线程,引入了 Paxos 协议后替换了 IO 线程同步主备库 binlog 的工作,备库的复制延迟主要就看备库 Apply 回放的开销,我们这里成为备库回放延迟。
我们使用 sysbench 测试 oltp_write_only 场景,测试 100 并发下, 不同 event 数量时, 备库回放出现延迟的持续时间。备库回放延迟时间通过监控 performance_schema.replication_applier_status_by_worker 表的 APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP 列来实时查看各 worker 是否工作来断定复制是否结束
从测试结果图中可见:
相同写入数据量下,DN 的备库回放所有日志的完成时间远远优于 MGR,DN 的的耗时仅是 MGR 的 3%~4%。这对主备切换的及时性十分关键。
随着写入数量的增加,DN 相比 MGR 的备库回放延迟优势继续保持,十分稳定。
分析备库回放延迟原因,MGR 的备库回放策略采用 group_replication_consistency 默认值为 EVENTUAL,即 RO 和 RW 事务在执行之前都不等待应用前面的事务。这样可以保证主库写入性能的最大化,但是备库延迟就会比较大(通过牺牲备库延迟和 RPO=0 来换取主库的高性能写入,开启 MGR 的限流功能可以平衡性能和备库延迟,但主库的性能就会打折扣)
3.5. 测试小结
4. 总结
经过深入的技术剖析与性能对比,PolarDB-X DN 凭借其自研的 X-Paxos 协议和一系列优化设计,在性能、正确性、可用性及资源开销等方面展现出对 MySQL MGR 的多项优势,但 MGR 在 MySQL 生态体系内也占据重要地位,但需要考虑备库宕机抖动、跨机房容灾性能波动、稳定性等各种情况,因此如果想用好 MGR,必须配备专业的技术和运维团队的支持。
在面对大规模、高并发、高可用性需求时,PolarDB-X 存储引擎以其独特的技术优势和优异的性能表现,相比于 MGR 在开箱即用的场景下,PolarDB-X 基于 DN 的集中式(标准版)在功能和性能都做到了很好的平衡,成为了极具竞争力的数据库解决方案。
版权声明: 本文为 InfoQ 作者【阿里云数据库开源】的原创文章。
原文链接:【http://xie.infoq.cn/article/a1bf07d528315e5d22d8910f6】。文章转载请联系作者。
评论