MySQL 数据库从诞生以来就以简单、易用、开源为主打特点,成为不少开发者首选的数据库系统。阿里集团在 2008 年开始提出"去 IOE"的口号,迈入了 MySQL 数据库的时代。系统使用大量的 MySQL,配合业务的改造替代原有的商业版 Oracle 系统。
根据阿里交易型应用的特点,以及双十一这样业界罕有的需求推动下,我们在官方的 MySQL 基础上增加了非常多实用的功能、性能补丁,打造了 AliSQL 这个 MySQL 分支品牌。
时间很快走到 2014 年,随着业务高速的增长,同城主备 AliSQL 部署的方式已经无法满足阿里对可扩展的部署、国际化以及容灾方面的需求。“异地多活”成为了公司应用的新标准。
“异地多活”也给底层的数据库提出了新的容灾要求。传统的 Master-Slave 架构下,主备如果不使用强同步模式就会存在数据丢失的可能,然而强同步下一旦有节点异常则整体不可服务。
而且,这套架构下需要 HA 工具来进行选主的仲裁和控制。过去阿里 DBA 们开发了高效可靠的 HA 以及一整套工具和流程来做主备切换后数据和日志的校验和订正。
我们相信技术的发展能带来更大的运维便利性以及更好的用户体验,以 Google Spanner 以及 Amazon Aruora 为代表的 NewSQL 系统为数据库的数据一致性给出了与以往不同的思路:基于一致性协议搭建分布式的多副本数据库。
AliSQL X-Cluster 介绍
说到 AliSQLX-Cluster 就不能不提其分布式核心和一致性协议。
X-Paxos 是阿里巴巴自主研发的一致性协议库,目标是填补市面上高性能、易接入的一致性协议库的空白。而市面上已开源的一致性协议实现,包括 etcd 以及其他厂商等都存在或性能不够或功能上无法满足复杂的现实应用场景需求的问题。
有了 X-Paxos,可基于它打造一套强一致的分布式系统,X-Cluster 是第一个接入 X-Paxos 生态的重要产品,利用 X-Paxos 实现了自动选主,日志同步,集群内数据强一致,在线集群配置变更等功能。
同时 X-Cluster 基于 MySQL 生态,兼容最新版本的 MySQL 5.7,集成了 AliSQL 过去的各种功能增强。MySQL 的用户可以零成本迁移到 X-Cluster 上。
AliSQL X-Cluster 的整体架构
上图展示的是一个部署三个实例的 Cluster 集群。X-Cluster 是一个单点写入,多点可读的集群系统。在同一时刻,整个集群中至多会有一个 Leader 节点来承担数据写入的任务。
相比多点写入,单点写入不需要处理数据集冲突的问题,可以达到更好的性能与吞吐率。
X-Cluster 的每个实例都是一个单进程的系统,X-Paxos 被深度整合到了数据库内核之中,替换了原有的复制模块。集群节点之间的增量数据同步完全是通过 X-Paxos 来自驱动,如何复制,从哪个点回放不再需要运维人员或者外部工具来介入。
X-Cluster 为了追求最高的性能,利用 MySQL 的 Binlog 进行深度改造和定制来作为 X-Paxos 的 Consensus 日志,实现了一系列的 X-Paxos 日志接口,赋予 X-Paxos 直接操纵 MySQL 日志的能力。
为了保证集群数据的一致性以及全球部署的能力,在事务提交、日志复制回放以及恢复上,X-Cluster 都进行了重新设计。
事务提交、复制流程
X-Cluster 的复制流程是基于 X-Paxos 驱动 Consensus 日志进行复制。
Leader 节点在事务 prepare 阶段会将事务产生的日志收集起来,传递给 X-Paxos 协议层后进入等待。X-Paxos 协议层会将 Consensus 日志高效地转发给集群内其他节点。
当日志在超过集群半数实例上落盘后, X-Paxos 会通知事务可以进入提交步骤。否则如果期间发生 Leader 变更,prepare 的事务会根据 Paxos 日志的状态进行相应的回滚操作。
相比原生 MySQL,日志传输采用了多线程、异步化、Batching、Pipelining 等优化手段,特别是在长传链路的场景中,效率提升明显。
Follower 节点也使用 X-Paxos 进行日志的管理操作,为提升接收效率,收到 Leader 传递过来的日志以后将日志内容 Append 到 Consensus Log 末尾,Leader 会异步的将达成多数派的日志的消息发送给 Follower。
Follower 的协调者线程会负责读取达成多数派的日志并加以解析,并传递给各个回放工作线程进行并发的数据更新。
Follower 的并发回放可以有多种方式,包括按照 Leader 上的 Group Commit 维度或者是按照表级别的维度,未来会引入最新的writeset方式来精确控制最大并发。
Failover
X-Cluster 只要半数以上的节点存活就能保证集群正常对外服务。因此当出现少数的follower节点故障时并不影响集群的服务能力。
当 Leader 节点故障时会自动触发集群的重新选主流程。选主流程由 X-Paxos 驱动,在 Paxos 协议的基础上,结合优先级推选出新的 Leader 节点。
对于 X-Cluster 而言,failover_time =election_time + apply_time。
election_time 代表协议选主的时间,一般在 10s 左右;apply_time 是数据应用日志的时间,取决于回放的速度,优秀的并行回放算法能把应用日志的时间控制在 10s 之内。
相对来说 Leader 节点故障之下是一个相对复杂的场景,故障包括了实例崩溃、服务器宕机、网络隔离等等。
如上图所示,一个三节点的 X-Cluster 集群,左边的 Case 是原 Leader A 节点宕机,因此 B 节点和 C 节点会在较长的时间内收不到 Leader 的心跳。
因此在一个选举超时周期后,B 节点开始尝试推选自己为 Leader,并且 C 节点同意后,B 会成为新的主节点,恢复其服务能力。
右边的 Case 是原 Leader A 节点发生网络分区,此时在选举超时后,BC 两个节点的行为和之间的 Case 类似。
A 节点由于无法将心跳和日志发送给 BC 两个节点在超时后会降级,然后不断尝试选自己为主,但是因为没有其他节点的同意,达不成多数派,一直都不会成功。当网络分区恢复后,A 收到 B 节点的心跳,触发 Leader stickness 机制,A 自动加回集群。
AliSQL X-Cluster 的优化特性
跨地域部署
集群的动态配置和选举
X-Cluster 支持在线集群配置变更,包括:
增加节点下线节点。
修改节点类型为一致性节点或者是只读节点。
修改节点优先级。
修改集群的 Leader。
修改只读节点复制源。
所有的上述修改配置的过程是在线进行的,不会阻塞业务的正常运行,集群配置的变化也会严格按照 Paxos 协议进行,记录日志并且推动对应的状态机变更,还有完善的恢复机制。
保证最终集群内配置达成一致,不会因为集群配置变更过程中的异常导致脑裂或者其他配置出现终态不一致的问题。
X-Cluster 集群的节点从功能上看有两个类型,包括参与选主与多数派协议的一致性协议节点还有只读节点。一致性协议节点是 X-Cluster 的基础。
目前一个 X-Cluster 集群支持至少 1 个一致性节点,至多 99 个一致性节点。只读节点可以无限扩展。用户可以从一开始的单节点集群开始,后续不断根据需求扩展不同类型的节点。
优先级
优先级功能主要包括以下两方面:
权重化选主。
策略化多数派。
权重化选主代表选主的顺序权重。只要在选举的时候没有网络隔离,选举 Leader 的顺序会按照集群存活节点的权重顺序进行。权重越高的节点,就有更大的优先级被选为 Leader。
我们实现了两段式的选举时间,第一阶段是集群内统一的租约时间,而第二阶段是根据权重来决定,权重越大的节点时间越短,也就是会越早发起自选举。
除此之外,还有一重权重检测机制来保证权重优先级,节点上任意时间会广播检测一遍所有能够联通的集群内节点,如果发现权重更高的节点会主动发起一次 Leader Transfer 将 Leader 角色过继过去的命令。
权重化选主在跨地域部署的场景下尤其重要。跨地域的部署业务和数据库之间的访问延时会非常敏感,如果 Leader 节点随机的切换到了另一个地域的机房可能会导致应用大规模的访问异地实例,大幅增加客户端的响应时间。
权重化选主可以完美解决此问题。按照应用的部署需求进行动态设置,非常灵活。
策略化多数派是指在事务提交日志同步过程中,哪些节点必须要日志复制完成。复制优先级分为两档,强复制和弱复制。
标准的 Paxos 只要超过半数的节点同步日志即可推进状态机,但是由于每个连接会自动分配路由的问题,可能在跨 Region 的访问中 RTT 时间会有误差。
为了缩短网络/节点故障后,按照选主优先级重新选主并继续服务的时间间隔,我们可以配置在规定日志复制到多数节点的基础上必须还要复制到所有强复制的节点才可以推进状态机并返回客户端事务提交成功的响应。
这是一个类 Max protection 模式的设计,如果检测到强一致节点的宕机,可选择适当的降级。
低成本副本管理
之所以要创建不同类型的副本,还是出于应用需求以及成本控制的考虑。相比传统的两节点主备复制,X-Cluster 的常规同城部署方式是三节点。
日志型副本是作为降低部署成本的一种选择。日志型副本只存储日志,不需要存储数据,也不需要回放日志更新数据。
因此无论是存储还是 CPU 的开销,日志型副本相比普通副本都有很大的优势。在实际应用规划中,非常适合用来作容灾型的节点部署。
只读节点管理
如上图所示,X-Cluster 集群中的只读节点可以从任何一个一致性节点复制日志,这不仅是考虑到如果所有节点的日志都从 Leader 节点复制会对 Leader 节点造成过大的网络和 IO 瓶颈。
而且由于跨区域部署下不同地域的数据状态机可能会有延时,设置了读写分离的用户在特定的场景下需要有特定的只读状态延时的要求。
但是这时的问题就是如果某个一致性节点发生了宕机,那么和它建立复制关系的只读节点应该如何进行灾备联动?
作为一个自运维的数据库服务,X-Cluster 自然要解决好这个问题。X-Cluster 定义了 Learner Source Group。每个 Group 是一个只读节点的容灾单元。
当 Group 内某个一致性节点发生意外状况(宕机或者网络隔离),集群会根据 Group 的配置,将挂载在故障节点下的只读节点配置到 Group 中另外一个正常工作的节点下进行数据同步。
高性能日志
MySQL 系统在开启主备复制的情况下,除了会记录 Binlog 之外,在备库上还会记录一份 RelayLog,即从库通过指定对应主库的 Binlog 位置去同步一份二进制日志写入 RelayLog 供复制线程读取和回放。
在 X-Cluster 中,只使用一份日志进行节点间的同步,利用 X-Paxos 的插件式日志模块的特性,每个节点有一份 Consensus 日志。
这样既方便了对 Consensus 日志的管理,也降低了日志存储以及读写的开销。
Consensus Log 拥有 Append,Get,Truncate 以及 Purge 等基本接口,它的控制权完整地交给了 X-Paxos,由 X-Paxos 进行控制。
除此之外,X-Cluster 为 Consensus Log 设计了日志索引和日志缓存、预读机制,极大的提升了日志模块的性能以保证一致性协议运作的高效性。
异步化事务提交
传统的 MySQL 都是 One Thread perConnection 的工作模式,在引入线程池后是以一个线程池孵化一定数量的工作线程,每个线程负责处理一次 query 的解析、优化、修改数据、提交、回传网络包等等。
集群需要跨地域部署下,一次事务的提交由于需要在集群之间同步事务日志,受限于网络的 RTT 的限制,会达到数十毫秒的级别,那么对于一个普通的写事务来说,大量的时间会耗费在同步节点日志等待事务提交的过程。
在大压力下,很快数据库内部的工作线程会耗尽,吞吐达到瓶颈。如果一味的放大数据库内部的工作线程数目,那么线程上下文的代价会大幅增加。
如果将整个事务的提交异步化,将工作线程从等待 X-Paxos 日志同步中解放出来,去处理新的连接请求,在大负载下可以拥有更高的处理能力。
异步化改造的说明示意图如下所示:
X-Cluster 的异步化提交核心思想是将每个事务的请求分成两个阶段:
提交之前阶段。
提交和回包阶段。
两个阶段都可以由不同的工作线程来完成。为了完成异步化的改造,X-Cluster 增加了等待同步队列和等待提交队列,用于存储处于不同阶段的事务。前者队列中的事务是等待 Paxos 多数派日志同步的事务,后者是等待提交的事务。
当用户发起 Commit/Rollback/XA_Prepare 时,处理用户连接的线程池 Worker 产生事务日志并将事务上下文存储到等待同步的队列中。等待同步队列的消费由少量数目的 Worker 线程来完成,其余工作线程可以直接参与其他任务的处理。
事务等待多数派完成后会被推入等待提交队列。这个队列里的事务都是可以被立即提交的。所有的 Worker 线程发现该队列里有事务,就可以顺道取出来执行提交操作。
这样一来,系统中只有少数的线程在等待日志同步操作,其余的线程可以充分利用 CPU 处理客户端的请求。
X-Cluster 以这样的思路为指导原则,结合 MySQL 的 Group Commit 逻辑,将原有需要等待的操作全部异步化,让 Worker 线程可以去执行新的请求响应。
在测试中,异步化改造在同城部署的场景中相比同步提交有 10% 的吞吐率提升,跨区域的部署后有几倍的吞吐提升。
热点更新
为了解决此问题,X-Cluster 在单机版 AliSQL 的热点功能之上优化了复制,使得在保证数据强一致的情况下,热点更新性能提升 200 倍。
如上图所示,X-Cluster 针对热点行更新的基本思路是合并多个事务对同一行的更新。
为了让批量的更新事务能够同时进行提交,X-Cluster 增加了一种新的行锁类型——热点行锁。在热点行锁下,热点更新的事务之间是相容的。
X-Cluster 为了保证数据的一致性,对同一批的热点更新事务日志打上特殊标志,X-Paxos 会根据这些标志将这一整批事务的日志组成一个单独的网络包进行集群间的数据同步,保证这些事务是原子的提交/回滚。
除此之外为了提升日志回放的效率,X-Cluster 将每个批次事务中对于热点行的更新日志也做了合并。
一体化的客户端和服务端
X-Cluster 有完整的 Client-Server 生态。所以整个系统不需要外部组件的介入,能够自封闭的成为一个生态闭环。作为客户端的 X-Driver 能够订阅 Server 端发生的一切改变,从而进行自动寻主,实例列表动态维护等功能。
客户端的元数据就保存在 X-Cluster 服务内部。相比外置的元数据中心,这套自封闭体系能够以最快的时间获取到准确的集群变化,降低集群变更对用户的感知程度。
优化的备份以及数据订阅体系
基于强大的 X-Paxos 体系,日志备份以及数据订阅系统都能够以日志订阅者的方式接入进来。
由于有了 X-Paxos 的全局唯一位点的支持,这些订阅系统的 Failover 不会再有难以找到准确位点的困扰。而且由于 X-Paxos 是流式的推送日志消息,因此数据的实时性也能大幅改进。
AliSQL X-Cluster 的实战部署方案
如上图,X-Cluster 的同城部署三副本能够方便的实现零数据丢失的实例容灾以及机房级容灾。相比主备方式,额外增加了一个日志节点,换取强一致以及可用性。
如上图,三地五实例(四数据、五日志)能够保证城市级容灾,任何一个城市的节点全部宕机都不会影响到集群可用性,5 个节点中至少还有 3 个节点能够正常运行。
在日常运行中,5 节点在每次事务提交的时候必定需要将日志同步到 3 个节点,因此必然会出现一次跨域的网络同步,这也就是长传链路网络场景,X-Cluster 对于慢网络的优化正是应对类似这样的需求。
AliSQL X-Cluster 的性能表现
作为对比,我们使用了最新的开源单机版 MySQL 5.7.19 以及该版本下的 Group Replication。Group Replication 在测试中关闭限流,测试机均是 64core 256G 内存 PCIE SSD。
测试同域下的集群,Insert 我们使用 300 并发线程、 OLTP 使用 400 并发线程,热点更新使用 300 并发线程。
在同一个域下,X-Cluster 的吞吐和响应时间表现都是非常出色的,甚至略好于单机版本的 MySQL 5.7.19。
相比 Group Replication,在本次测试的压力下,Insert case X-Cluster 有超过一倍的吞吐以及 55% 左右的响应时间,OLTP case X-Cluster 有超过 5% 的吞吐以及接近 70% 的响应时间表现。
测试跨域下的集群需要大量的连接来保证吞吐,因此 Insert 使用 2000 并发线程,OLTP 使用 700 并发线程,热点更新使用 2500 并发线程。
当集群部署在不同域时,X-Cluster 和 Group Replication 相比同域的部署下吞吐都有下降,响应时间受到物理网络延迟的影响也有显著提高。
然而在 Insert case 下,X-Cluster 仍然可以领先 Group Replication 5 倍,响应时间只有 GR 的四分之一。OLTP case 下,X-Cluster 的吞吐领先 Group Replication 接近 4 倍,响应时间只有三分之一。
热点更新是 X-Cluster 的一大亮点功能,根据测试结果,无论是同域还是跨域部署, X-Cluster 的吞吐和响应时间表现都要远远超过单机 MySQL 和 Group Replication。
AliSQL X-Cluster 的正确性保障
X-Cluster 最大的挑战就是保证基于分布式一致性协议实现的正确性。经过实践证明,灰盒测试是最有效的手段。
X-Cluster 集成了 X-Paxos,X-Paxos 项目本身有一系列的测试框架用于发现和回归。除此之外,X-Cluster 基于 tc、systemtap 等工具构建了多种多样模拟网络异常、实例宕机、I/O 异常的环境。
在这套环境下网络分区、丢包、各种 I/O 异常,各种实例宕机可以随机组合。同时使用 benchmark 工具对每个节点施加大压力的读写,定期的去校验集群中不同节点的数据以及日志的一致性。
一致性相关所有的操作都会记录在 X-Cluster 专门的日志中,方便追溯集群节点间的交互行为。数据和日志的最终一致性校验由外部系统来完成。阿里内部有专门的分片校验系统可以做 X-Cluster 不同节点的全量数据校验。
Consensus 日志解析工具可以快速解析日志内容进行比对。这套测试环境帮助我们发现了非常多的系统 Bug,包括实例恢复的 Bug,网络异常导致的 Bug 等等。
我们认为一个稳定版本的标准是一定需要通过这个场景长时间的测试,并且各种表现要符合预期。
除了数据和日志的最终一致性,对于数据的线性一致,事务隔离性,我们引入了 Jepsen 工具。
Jepsen 帮助大量分布式系统发现了分布式协议和实现的正确性问题。我们为 X-Cluster 专门构造了一系列的测试用例来尽可能覆盖各种异常场景,来发现系统在隔离性和一致性上的问题。
AliSQL X-Cluster与同类的对比
Galera
Galera 的集群通信用了一种基于单令牌环的 Totem 组播协议。为了能支持多点写入,主机在收到写请求后,会原子广播到组内所有的机器,由它们各自的事务管理层来决定是否提交或者回滚。
组播由于是 P2P 的通信,随着节点数增加,延时会放大,响应时间会变慢,并且只适用于低延时的局域网。
除此之外,组播还有一个问题,如果组内的某台机器宕机,组播会超时,在踢掉 fail 的机器重新确定组内成员关系之前,整个集群不可服务。
Galera 采用了专门的文件 gcache 进行增量状态复制,gcache 不做任何他用,因此 gcache 本身需要额外的计算和存储代价进行维护。
Group Replication
Group Replication 的协议层复制是 XCOM,且在复制中强依赖 GTID。在测试中的性能表现,特别是跨域部署下还达不到需求,目前的版本中也仍然有大量的 Bug 在修复,完全可用于生产环境还有待后续版本的稳定性和性能提升。
总结
参考文献
1.Group Replication is GA with MySQL 5.7.17 – comparison with Galera http://lefred.be/content/group-replication-vs-galera/
2.MySQL HighAvailability Blog
http://mysqlhighavailability.com/tag/mysql-group-replication/
3.Introduction to Galera
https://www.slideshare.net/henrikingo/introduction-to-galera
4.GALERA CLUSTER DOCUMENTATION
http://galeracluster.com/documentation-webpages/
作者:胡炜
编辑:王雪燕、陶家龙、孙淑娟
技术编辑:王雪燕,关注架构、算法,运维等技术领域,有投稿、寻求报道意向技术人请联络 wangxy@51cto.com
胡炜
X-Cluster 的核心开发成员
2016 年加入阿里巴巴,数据库技术团队 AliSQL 内核贡献者,X-Cluster 的核心开发成员。毕业于浙江大学,专攻数据库方向。从业以来一直深耕于数据库领域,擅长 RDBMS,NOSQL 等技术方向。
精彩文章推荐: