• 技术文章 >数据库 >mysql教程

    聊聊GitHub做好MySQL高可用性的方法

    青灯夜游青灯夜游2022-11-02 20:18:41转载327

    php入门到就业线上直播课:进入学习

    Github 使用 MySQL 数据库作为所有非 git 事务的数据存储。数据库的可用性对 Github 的正常运行而言至关重要。无论是 Github 网站本身,还是 Github API,身份验证服务等都需要访问数据库。Github 运行了多个数据库集群用于支撑不同的服务于任务。数据库的架构采用的是传统的主从结构,集群中一个节点(主库)支持写访问,其余的节点(从库)同步主库的变更,支持读服务。

    主库的可用性至关重要。一旦主库宕机,集群将不能够支持数据写入服务:任何需要保存的数据都无法写入到数据库保存。最终导致 Github 上任何变更,例如代码提交,提问,用户创建,代码 review,创建仓库等操作都无法完成。

    为了保证业务的正常运行,我们自然需要在集群中有一个可用的支持写入的数据库节点。同时,我们也必须能够快速的发现可用的可写入服务数据库节点。

    就是说,在异常情况下,假如主库宕机的场景,我们必须确保新的主库能够立刻上线支持服务,同时保证集群中其他节点能够快速识别到新的主库。故障检测,主库迁移以及集群其他数据节点识别新主库的总时间构成了服务中断的总时间。

    这篇文章说明了 GitHub 的 MySQL 高可用性和主库服务发现解决方案,该解决方案使我们能够可靠地运行跨数据中心的操作,能够容忍数据中心的隔离,并缩短在出现故障时停机时间。

    高可用性的实现

    本篇文章描述的解决方案是在以前 Github 高可用方案上的改进版本。正如前面说到的一样,MySQL 的高可用策略必须适应业务的变化。我们期望 MySQL 以及 GitHub 上其他的服务都有能够应对变化的高可用解决方案。

    当设计高可用以及服务发现系统方案的时候,从下面几个问题出发,也许能够帮助我们快速找到合适的解决方案:

    为了说明上面的几个问题,我们先来看一下我们之前的高可用方案,以及我们为什么要改进它。

    摒弃基于 VIP 和 DNS 的发现机制

    在之前的方案中,应用了下面的技术方案:

    客户端通过节点名称,例如 mysql-writer-1.github.net,解析成主节点的虚拟 IP 地址 (VIP),从而找到主节点。

    因此,正常情况下,客户端可以通过对节点名称的解析,连接到对应 IP 的主节点上。

    考虑夸三个数据中心的拓扑结构的情况:

    2.png

    一旦主库异常,必须将其中的一个数据副本服务器更新为主库服务器。

    orchestrator 会检测异常,选出新的主库,然后重新分配数据库的名称以及虚拟 IP (VIP)。客户端本身不知道主库的变更,客户端有的信息只是主库的名称,因此这个名称必须能够解析到新的主库服务器。考虑下面的问题:

    VIP 需要协商:虚拟 IP 由数据库本身所持有。 服务器必须发送 ARP 请求,才能够占有或释放 VIP。 在新的数据库分配新的 VIP 之前,旧的服务器必须先释放其占有的 VIP。这个过程会产生一些异常问题:

    在我们实际设置 VIP 时,VIP 还受实际物理位置的约束。这主要取决于交换机或者路由器所在。因此,我们只能在同一本地服务器上重新分配 VIP。特别是在某些情况下,我们无法将 VIP 分配给其他数据中心的服务器,而必须进行 DNS 更改。

    仅这些限制就足以推动我们寻找新的解决方案,但需要考虑的是:

    这些额外的步骤是导致总停机时间的一个因素,并引入了它们自己的故障和摩擦。

    解决方案是有效的,GitHub 已经成功地进行了 MySQL 故障转移,但是我们希望 HA 在以下方面有所改进:

    GitHub 的高可用解决方案:orchestrator ,Consul , GLB

    新策略可以改进,解决或者优化上面提到的问题。现在高可用的组成如下:

    3.png

    新的结构移除了 VIP 和 DNS 。在引入更多的组件的同时,我们能够解藕这些组件,并且简化相关的任务,并易于利用可靠稳定的解决方案。详情如下。

    正常过程

    正常情况,应用通过 GLB/HAProxy 连接到写入节点。

    应用感知不到 master 身份。之前,都是使用名称。例如 cluster1 的 master 是 mysql-writer-1.github.net。现在的结构中,这个名称被 anycast IP 取代。

    通过 anycast,名称被相同的 IP 取代,但流量由客户端的位置来进行路由。特别的,当数据中心有 GLB 时,高可用负载均衡器部署在不同的盒子内。 通向 mysql-writer-1.github.net 的流量都被引流到本地的数据中心的 GLB 集群。这样所有的客户端都由本地代理服务。

    HAProxy 顶层使用 GLB。HAProxy 拥有 写入池 :每个 MySQL 集群都有一个。每个池都有一个后端服务:集群 master 节点。数据中心的所有 GLB/HAProxy 盒子都有相同的池子,表示这些池子有相同的后端服务对应。所以如果应用期望写 mysql-writer-1.github.net,不同关心连接哪个 GLB 服务。它会导向实际的 cluster1 master 节点。

    就应用连接 GLB ,发现服务而言,不需要重新发现。GLB 负责全部流量导向正确的目的地。

    GLB 是怎么知道哪些服务是后端,以及如何告知 GLB 变化的呢?

    Discovery via Consul

    Consul 以服务发现解决方案而闻名,也提供 DNS 服务。 然而,在我们的解决方案中,我们将其用作高度可用的键值 (KV) 存储。

    在 Consul 的 KV 存储中,我们写入集群主节点的身份。 对于每个集群,都有一组 KV 条目指示集群的主设备 fqdn、端口、ipv4、ipv6。

    每个 GLB/HAProxy 节点都运行 consul-template:一个监听 Consul 数据变化的服务(在我们的例子中:集群主数据的变化)。 consul-template 生成一个有效的配置文件,并且能够在配置更改时重新加载 HAProxy。

    因此,每个 GLB/HAProxy 机器都会观察到 Consul 对 master 身份的更改,然后它会重新配置自己,将新的 master 设置为集群后端池中的单个实体,并重新加载以反映这些更改。

    在 GitHub,我们在每个数据中心都有一个 Consul 设置,并且每个设置都是高度可用的。 但是,这些设置彼此独立。 它们不会在彼此之间复制,也不会共享任何数据。

    Consul 如何获知变化,信息如何跨 DC 分发?

    orchestrator/raft

    我们运行一个 orchestrator/raft 设置: orchestrator 节点通过 raft 机制相互通信。 每个数据中心有一个或两个 orchestrator 节点。

    orchestrator 负责故障检测和 MySQL 故障切换,以及将 master 的变更传达给 Consul 。 故障切换由单个 orchestrator/raft leader 节点操作,但是集群现在拥有新 master 的消息通过 raft 机制传播到所有 orchestrator 节点。

    orchestrator 节点收到 master 变更的消息时,它们各自与本地 Consul 设置通信:它们各自调用 KV 写入。 具有多个 orchestrator 代理的 DC 将多次(相同)写入 Consul

    把流程组合起来

    在 master 崩溃的情况下:

    每个组件都有明确的责任归属,整个设计既是解耦的,又是简化的。orchestrator 不知道负载平衡器。 Consul 不需要知道消息的来源。代理只关心 Consul。客户端只关心代理。

    此外:

    其他详细信息

    为了进一步保护流量,我们还有以下内容:

    我们将在以下部分进一步解决问题并追求 HA 目标。

    Orchestrator/RAFT 故障检测

    orchestrator 使用 整体方法 来检测故障,因此非常可靠。我们没有观察到误报:我们没有过早的故障转移,因此不会遭受不必要的停机时间。

    orchestrator/raft 进一步解决了完整的 DC 网络隔离(又名 DC 围栏)的情况。 DC 网络隔离可能会导致混乱:该 DC 内的服务器可以相互通信。是它们与其他 DC 网络隔离,还是其他 DC 被网络隔离?

    orchestrator/raft 设置中,raft 领导节点是运行故障转移的节点。领导者是获得组中大多数人(法定人数)支持的节点。我们的协调器节点部署是这样的,没有一个数据中心占多数,任何 n-1 数据中心都可以。

    在 DC 网络完全隔离的情况下,该 DC 中的 orchestrator 节点会与其他 DC 中的对等节点断开连接。因此,孤立 DC 中的 orchestrator 节点不能成为 raft 集群的领导者。如果任何这样的节点恰好是领导者,它就会下台。将从任何其他 DC 中分配新的领导者。该领导者将得到所有其他能够相互通信的 DC 的支持。

    因此,发号施令的 orchestrator 节点将是网络隔离数据中心之外的节点。如果一个独立的 DC 中有一个主控,orchestrator 将启动故障转移,用其中一个可用 DC 中的服务器替换它。我们通过将决策委托给非隔离 DC 中的法定人数来缓解 DC 隔离。

    更快的广而告之

    通过更快地公布主要更改可以进一步减少总停机时间。如何实现这一点?

    orchestrator 开始故障转移时,它观察可用于提升的服务器队列。理解复制规则并遵守提示和限制,它能够对最佳操作过程做出有根据的决策。

    它可能认识到,一个可用于促销的服务器也是一个理想的候选人,例如:

    在这种情况下, orchestrator 首先将服务器设置为可写的,然后立即宣传服务器的推广 (在我们的例子里是写到 Consul KV 存储中) ,即使异步开始修复复制树,这个操作通常需要几秒钟。

    很可能在 GLB 服务器完全重新加载之前,复制树已经完好无损,但是并不严格要求它。服务器很好接收写!

    半同步复制

    在 MySQL 的半同步复制中,主服务器不会确认事务提交,直到已知更改已发送到一个或多个副本。它提供了一种实现无损故障转移的方法:应用于主服务器的任何更改要么应用于主服务器,要么等待应用于其中一个副本。

    一致性伴随着成本:可用性的风险。如果没有副本确认收到更改,主服务器将阻塞并停止写操作。幸运的是,有一个超时配置,超时后主服务器可以恢复到异步复制模式,从而使写操作再次可用。

    我们已经将超时设置为一个合理的低值: 500ms。将更改从主 DC 副本发送到本地 DC 副本,通常也发送到远程 DC,这已经足够了。通过这个超时,我们可以观察到完美的半同步行为 (没有退回到异步复制) ,并且在确认失败的情况下可以很轻松地使用非常短的阻塞周期。

    我们在本地 DC 副本上启用半同步,在主服务器死亡的情况下,我们期望 (尽管不严格执行) 无损故障转移。完全直流故障的无损故障转移是昂贵的,我们并不期望它。

    在尝试半同步超时的同时,我们还观察到了一个对我们有利的行为:在主要失败的情况下,我们能够影响理想候选对象的身份。通过在指定的服务器上启用半同步,并将它们标记为候选服务器,我们能够通过影响故障的结果来减少总停机时间。在我们的实验中,我们观察到我们通常最终会得到理想的候选对象,从而快速地广而告之。

    注入心跳

    我们没有在升级 / 降级的主机上管理 pt-heart 服务的启动 / 关闭,而是选择在任何时候在任何地方运行它。这需要进行一些修补,以便使 pt-heart 能够适应服务器来回更改 read_only(只读状态) 或完全崩溃的情况。

    在我们当前的设置中,pt-heart 服务在主服务器和副本上运行。在主机上,它们生成心跳事件。在副本上,他们识别服务器是 read_only(只读) 的,并定期重新检查它们的状态。一旦服务器被提升为主服务器,该服务器上的 pt-heart 就会将服务器标识为可写的,并开始注入心跳事件。

    orchestrator 所有权委托

    我们进一步 orchestrator:

    在所有的新 master 的基础上,这减少了摩擦。一个刚刚被提升的 master 显然应该是有生命力,并且可以被接受的,否则我们不会提升它。因此,让 orchestrator 直接讲更改应用于提升的 msater 是有意义的。

    orchestrator 所有权委托

    我们进一步 orchestrator:

    在所有的新 master 的基础上,这减少了摩擦。一个刚刚被提升的 master 显然应该是有活力,并且可以被接受的,否则我们不会提升它。因此,让 orchestrator 将更改直接应用于提升的 msater 是有意义的。

    限制和缺点

    代理层使应用程序不知道主服务器的身份,但它也掩盖了应用程序的主服务器的身份。所有主要看到的都是来自代理层的连接,我们会丢失关于连接的实际来源的信息。

    随着分布式系统的发展,我们仍然面临着未处理的场景。

    值得注意的是,在一个数据中心隔离场景中,假设主服务器位于隔离的 DC 中,该 DC 中的应用程序仍然能够写入主服务器。一旦网络恢复,这可能导致状态不一致。我们正在努力减轻这种分裂的大脑实施一个可靠的 STONITH 从内部非常孤立的 DC。和以前一样,在摧毁初选之前还需要一段时间,而且可能会有一段短时间的脑分裂。避免大脑分裂的操作成本非常高。

    还存在更多的情况:在故障转移时停止领事服务;部分直流隔离;其他情况。我们知道这种性质的分布式系统不可能堵住所有的漏洞,所以我们把重点放在最重要的案例上。

    结论

    我们的协调器 / GLB/Consul 为我们提供了:

    结论

    业务流程 / 代理 / 服务发现范例在分离的体系结构中使用众所周知和受信任的组件,这使得部署、操作和观察变得更加容易,并且每个组件都可以独立向上或向下扩展。我们能不断的测试设置并寻求改进。

    原文地址:https://github.blog/2018-06-20-mysql-high-availability-at-github/

    译文地址:https://learnku.com/mysql/t/36820

    【相关推荐:mysql视频教程

    以上就是聊聊GitHub做好MySQL高可用性的方法的详细内容,更多请关注php中文网其它相关文章!

    声明:本文转载于:learnku,如有侵犯,请联系admin@php.cn删除

    千万级数据并发解决方案(理论+实战):点击学习

    Mysql单表千万级数据量的查询优化与性能分析

    Mysql主从原理及其在高并发系统中的应用

    专题推荐:mysql GitHub
    上一篇:聊聊为什么不要依赖MySQL高可用性进行维护 下一篇:自己动手写 PHP MVC 框架(40节精讲/巨细/新人进阶必看)

    相关文章推荐

    • ❤️‍🔥共22门课程,总价3725元,会员免费学• ❤️‍🔥接口自动化测试不想写代码?• 深入探究MySQL中 UPDATE 的使用细节• 总结分享之mysql慢查询优化的思路• Mysql如何处理大数据表?处理方案分享• 你知道MySQL innodb自增ID BUG有多大影响吗?• 一文带你快速了解MySQL中的慢查询
    1/1

    PHP中文网