阿里10年分布式数据库技术沉淀AliSQL X-Cluster的应用实战

2019-02-06 15:21

阿里10年分布式数据库技术沉淀AliSQL X-Cluster的应用实战



  MySQL 数据库从诞生以来就以简单、易用、开源为主打特点,成为不少开发者首选的数据库系统。阿里集团在 2008 年开始提出去 IOE的口号,迈入了 MySQL 数据库的时代。系统使用大量的 MySQL,配合业务的改造替代原有的商业版 Oracle 系统。

  根据阿里交易型应用的特点,以及双十一这样业界罕有的需求推动下,我们在官方的 MySQL 基础上增加了非常多实用的功能、性能补丁,打造了 AliSQL 这个 MySQL 分支品牌。

  时间很快走到 2014 年,随着业务高速的增长,同城主备 AliSQL 部署的方式已经无法满足阿里对可扩展的部署、国际化以及容灾方面的需求。“异地多活”成为了公司应用的新标准。

  “异地多活”也给底层的数据库提出了新的容灾要求。传统的 Master-Slave 架构下,主备如果不使用强同步模式就会存在数据丢失的可能,然而强同步下一旦有节点异常则整体不可服务。

  而且,这套架构下需要 HA 工具来进行选主的仲裁和控制。过去阿里 DBA 们开发了高效可靠的 HA 以及一整套工具和流程来做主备切换后数据和日志的校验和订正。

  我们相信技术的发展能带来更大的运维便利性以及更好的用户体验,以 Google Spanner 以及 Amazon Aruora 为代表的 NewSQL 系统为数据库的数据一致性给出了与以往不同的思路:基于一致性协议搭建分布式的多副本数据库。

  AliSQL X-Cluster(本文中简称 X-Cluster)是阿里巴巴数据库团队推出的兼容 MySQL 5.7,提供数据强一致功能,支持全球部署的分布式数据库集群产品。

  说到 AliSQLX-Cluster 就不能不提其分布式核心和一致性协议。

  X-Paxos 是阿里巴巴自主研发的一致性协议库,目标是填补市面上高性能、易接入的一致性协议库的空白。而市面上已开源的一致性协议实现,包括 etcd 以及其他厂商等都存在或性能不够或功能上无法满足复杂的现实应用场景需求的问题。

  有了 X-Paxos,可基于它打造一套强一致的分布式系统,X-Cluster 是第一个接入 X-Paxos 生态的重要产品,利用 X-Paxos 实现了自动选主,日志同步,集群内数据强一致,在线集群配置变更等功能。

  上图展示的是一个部署三个实例的 Cluster 集群。X-Cluster 是一个单点写入,多点可读的集群系统。在同一时刻,整个集群中至多会有一个 Leader 节点来承担数据写入的任务。

  相比多点写入,单点写入不需要处理数据集冲突的问题,可以达到更好的性能与吞吐率。

  X-Cluster 的每个实例都是一个单进程的系统,X-Paxos 被深度整合到了数据库内核之中,替换了原有的复制模块。集群节点之间的增量数据同步完全是通过 X-Paxos 来自驱动,如何复制,从哪个点回放不再需要运维人员或者外部工具来介入。

  为了保证集群数据的一致性以及全球部署的能力,在事务提交、日志复制回放以及恢复上,X-Cluster 都进行了重新设计。

  Leader 节点在事务 prepare 阶段会将事务产生的日志收集起来,传递给 X-Paxos 协议层后进入等待。X-Paxos 协议层会将 Consensus 日志高效地转发给集群内其他节点。

  当日志在超过集群半数实例上落盘后, X-Paxos 会通知事务可以进入提交步骤。否则如果期间发生 Leader 变更,prepare 的事务会根据 Paxos 日志的状态进行相应的回滚操作。

  相比原生 MySQL,日志传输采用了多线程、异步化、Batching、Pipelining 等优化手段,特别是在长传链路的场景中,效率提升明显。

  Follower 的协调者线程会负责读取达成多数派的日志并加以解析,并传递给各个回放工作线程进行并发的数据更新。

  Follower 的并发回放可以有多种方式,包括按照 Leader 上的 Group Commit 维度或者是按照表级别的维度,未来会引入最新的writeset方式来精确控制最大并发。

  X-Cluster 只要半数以上的节点存活就能保证集群正常对外服务。因此当出现少数的follower节点故障时并不影响集群的服务能力。

  当 Leader 节点故障时会自动触发集群的重新选主流程。选主流程由 X-Paxos 驱动,在 Paxos 协议的基础上,结合优先级推选出新的 Leader 节点。

  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 自动加回集群。

  X-Cluster 拥有一系列的新功能和特性,以满足不同类型的应用对于功能和性能上的需求。

  X-Cluster 的一个显著功能就是能够支持跨地域部署,在跨域的情况下也能保证集群数据强一致,拥有城市级容灾的能力。即使某个城市的机房全部宕机,只要保证集群多数派节点存活,所有的数据都不会丢失。

  依赖 X-Paxos 以及数据库内核中异步化工作线程的改造,在数十毫秒的网络 RTT(RoundTrip Time)下,X-Cluster 依然有非常高的吞吐性能。

  拥有了跨地域部署的能力,X-Cluster 的部署方式是非常灵活的。业务可以根据实际的业务情况以及不同的容灾级别需求,选择同机房容灾、机房容灾、城市容灾部署,并且可以在不同的容灾级别之间灵活切换。

  所有的上述修改配置的过程是在线进行的,不会阻塞业务的正常运行,集群配置的变化也会严格按照 Paxos 协议进行,记录日志并且推动对应的状态机变更,还有完善的恢复机制。

  保证最终集群内配置达成一致,不会因为集群配置变更过程中的异常导致脑裂或者其他配置出现终态不一致的问题。

  X-Cluster 集群的节点从功能上看有两个类型,包括参与选主与多数派协议的一致性协议节点还有只读节点。一致性协议节点是 X-Cluster 的基础。

  目前一个 X-Cluster 集群支持至少 1 个一致性节点,至多 99 个一致性节点。只读节点可以无限扩展。用户可以从一开始的单节点集群开始,后续不断根据需求扩展不同类型的节点。

  应用往往对于容灾后新主节点是有要求的,在原先的主节点意外宕机后,新主如果落在了一个低规格的节点,那么对于应用来说是很难接受的服务降级。

  X-Cluster 支持同一个集群中的节点拥有不同的优先级,用户可以根据实际的部署需要,在配置集群时为每个实例节点设置优先级。

  权重化选主代表选主的顺序权重。只要在选举的时候没有网络隔离,选举 Leader 的顺序会按照集群存活节点的权重顺序进行。权重越高的节点,就有更大的优先级被选为 Leader。

  我们实现了两段式的选举时间,第一阶段是集群内统一的租约时间,而第二阶段是根据权重来决定,权重越大的节点时间越短,也就是会越早发起自选举。

  除此之外,还有一重权重检测机制来保证权重优先级,节点上任意时间会广播检测一遍所有能够联通的集群内节点,如果发现权重更高的节点会主动发起一次 Leader Transfer 将 Leader 角色过继过去的命令。

  权重化选主在跨地域部署的场景下尤其重要。跨地域的部署业务和数据库之间的访问延时会非常敏感,如果 Leader 节点随机的切换到了另一个地域的机房可能会导致应用大规模的访问异地实例,大幅增加客户端的响应时间。

  权重化选主可以完美解决此问题。按照应用的部署需求进行动态设置,非常灵活。

  策略化多数派是指在事务提交日志同步过程中,哪些节点必须要日志复制完成。复制优先级分为两档,强复制和弱复制。

  标准的 Paxos 只要超过半数的节点同步日志即可推进状态机,但是由于每个连接会自动分配路由的问题,可能在跨 Region 的访问中 RTT 时间会有误差。

  为了缩短网络/节点故障后,按照选主优先级重新选主并继续服务的时间间隔,我们可以配置在规定日志复制到多数节点的基础上必须还要复制到所有强复制的节点才可以推进状态机并返回客户端事务提交成功的响应。

  这是一个类 Max protection 模式的设计,如果检测到强一致节点的宕机,可选择适当的降级。

  普通型拥有全部的功能;日志型只拥有日志不包含数据。如果日志型节点还是一个参与 Paxos 投票的一致性节点,那么它只有投票权,没有被选举权。

  之所以要创建不同类型的副本,还是出于应用需求以及成本控制的考虑。相比传统的两节点主备复制,X-Cluster 的常规同城部署方式是三节点。

  日志型副本是作为降低部署成本的一种选择。日志型副本只存储日志,不需要存储数据,也不需要回放日志更新数据。

  因此无论是存储还是 CPU 的开销,日志型副本相比普通副本都有很大的优势。在实际应用规划中,非常适合用来作容灾型的节点部署。

  如上图所示,X-Cluster 集群中的只读节点可以从任何一个一致性节点复制日志,这不仅是考虑到如果所有节点的日志都从 Leader 节点复制会对 Leader 节点造成过大的网络和 IO 瓶颈。

  而且由于跨区域部署下不同地域的数据状态机可能会有延时,设置了读写分离的用户在特定的场景下需要有特定的只读状态延时的要求。

  但是这时的问题就是如果某个一致性节点发生了宕机,那么和它建立复制关系的只读节点应该如何进行灾备联动?

  当 Group 内某个一致性节点发生意外状况(宕机或者网络隔离),集群会根据 Group 的配置,将挂载在故障节点下的只读节点配置到 Group 中另外一个正常工作的节点下进行数据同步。

  MySQL 系统在开启主备复制的情况下,除了会记录 Binlog 之外,在备库上还会记录一份 RelayLog,即从库通过指定对应主库的 Binlog 位置去同步一份二进制日志写入 RelayLog 供复制线程读取和回放。

  在 X-Cluster 中,只使用一份日志进行节点间的同步,利用 X-Paxos 的插件式日志模块的特性,每个节点有一份 Consensus 日志。

  这样既方便了对 Consensus 日志的管理,也降低了日志存储以及读写的开销。

  除此之外,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 面对跨域场景下的长传网络更加是雪上加霜,提交的时间变长,事务占据行锁的时间也显著增加。

  为了解决此问题,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 是流式的推送日志消息,因此数据的实时性也能大幅改进。

  X-Cluster 最为经典的两个部署方案是同城三副本,两份数据一份日志,以及跨地域 5 副本,四份数据一份日志。

  它们分别用于满足机房级容灾和城市级容灾需求。这里的副本概念指的都是一致性节点的部署,只读节点部署不影响容灾能力。

  这两类经典的部署方案都是考虑了可用性以及成本之间的权衡,以较小的代价换来目标的容灾能力。

  如上图,X-Cluster 的同城部署三副本能够方便的实现零数据丢失的实例容灾以及机房级容灾。相比主备方式,额外增加了一个日志节点,换取强一致以及可用性。

  如上图,三地五实例(四数据、五日志)能够保证城市级容灾,任何一个城市的节点全部宕机都不会影响到集群可用性,5 个节点中至少还有 3 个节点能够正常运行。

  在日常运行中,5 节点在每次事务提交的时候必定需要将日志同步到 3 个节点,因此必然会出现一次跨域的网络同步,这也就是长传链路网络场景,X-Cluster 对于慢网络的优化正是应对类似这样的需求。

  我们使用了三节点部署的方式,分别在同域三机房、跨域三机房的网络环境下进行了测试。

  测试工具使用标准的 Sysbench 的 insert/oltp,在 Insert 测试下,并且每个事务中只包含一条插入语句,属于密集的小事务场景,而相反的 OLTP 是读写大事务。

  针对热点环境,测试的场景是改造 update_non_index ,使其更新同一行数据。只读场景不在本次测试的范畴内,原因是只读不涉及到节点的日志、数据同步。

  因此可以认为只读测试对于 X-Cluster 这样的分布式系统是没有意义的。所有的测试,数据量为 10 张表,每张表 20 万条记录。

  测试同域下的集群,Insert 我们使用 300 并发线程、 OLTP 使用 400 并发线 并发线程。

  在同一个域下,X-Cluster 的吞吐和响应时间表现都是非常出色的,甚至略好于单机版本的 MySQL 5.7.19。

  测试跨域下的集群需要大量的连接来保证吞吐,因此 Insert 使用 2000 并发线 并发线 并发线程。

  当集群部署在不同域时,X-Cluster 和 Group Replication 相比同域的部署下吞吐都有下降,响应时间受到物理网络延迟的影响也有显著提高。

  热点更新是 X-Cluster 的一大亮点功能,根据测试结果,无论是同域还是跨域部署, X-Cluster 的吞吐和响应时间表现都要远远超过单机 MySQL 和 Group Replication。

  分布式系统的测试是非常复杂的,因为没有人能够通过穷举来罗列所有可能出现的情况。

  简单的接口测试和性能回归也只能覆盖一小部分场景,无法衡量一个分布式系统版本的质量。只有日复一日的测试以及线上系统的正常运行能够真正地说明分布式系统的鲁棒性。

  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 不是第一个基于 MySQL 的强一致集群方案,然而是最适合阿里这样体量公司的数据库解决方案。对比下面这些同类产品:

  Galara 是 MariaDB 支持的 MySQL 集群版本,支持强同步,支持多点写入,自动的集群配置以及节点 Failover,支持行级别的并行复制,支持原生的 MySQL 客户端。

  在这套架构下,Slave 不会有延时,任意节点读到的都是一致数据,不会有事务数据丢失,读写可扩展。

  Galera 的集群通信用了一种基于单令牌环的 Totem 组播协议。为了能支持多点写入,主机在收到写请求后,会原子广播到组内所有的机器,由它们各自的事务管理层来决定是否提交或者回滚。

  组播由于是 P2P 的通信,随着节点数增加,延时会放大,响应时间会变慢,并且只适用于低延时的局域网。

  除此之外,组播还有一个问题,如果组内的某台机器宕机,组播会超时,在踢掉 fail 的机器重新确定组内成员关系之前,整个集群不可服务。

  Galera 采用了专门的文件 gcache 进行增量状态复制,gcache 不做任何他用,因此 gcache 本身需要额外的计算和存储代价进行维护。

  Group Replication 实现了一个 X-COM 的通信层,它在新版本中已经使用了 Paxos 算法。目前一个 GR 集群中最多可以有 9 个节点,响应延时相对稳定,在节点同步日志层面,GR 使用 Binlog,相比 Galera 更加的通用。

  Group Replication 的协议层复制是 XCOM,且在复制中强依赖 GTID。在测试中的性能表现,特别是跨域部署下还达不到需求,目前的版本中也仍然有大量的 Bug 在修复,完全可用于生产环境还有待后续版本的稳定性和性能提升。

  X-Cluster 是针对数据质量要求较高的用户推出的全新的数据库解决方案。

  X-Cluster 不仅能够享受到开源社区带来的红利,其中涉及一致性的关键技术也能够做到完全的自主、可控,能够针对业务的需求进行灵活的变更。

  未来 X-Cluster 会在此基础上做更多的优化,例如支持多分片的 Paxos,多节点提供强一致读等功能。

  每日头条、业界资讯、热点资讯、八卦爆料,全天跟踪微博播报。各种爆料、内幕、花边、资讯一网打尽。百万互联网粉丝互动参与,TechWeb官方微博期待您的关注。