GitHub上的MySQL高可用性

GitHub将MySQL用作与git不相关的所有内容的主要数据仓库,因此MySQL的可用性是GitHub正常运行的关键。 网站本身,GitHub API,身份验证系统以及许多其他功能都需要访问数据库。 我们使用几个MySQL集群来处理各种服务和任务。 它们根据经典方案进行配置,其中一个节点可用于记录及其副本。 副本 (其他群集节点)异步地复制对主节点的更改并提供读取访问权限。


主机站点的可用性至关重要。 没有主节点,群集将不支持记录,这意味着您无法保存必要的更改。 解决交易,注册问题,创建新用户,存储库,评论等等将是根本不可能的。


为了支持记录,需要一个相应的可访问节点-群集中的主节点。 但是,识别或检测此类节点的能力同样重要。


在当前主节点出现故障的情况下,重要的是要确保及时出现新服务器以替换它,并能够迅速将这一更改通知所有服务。 总停机时间包括检测故障,故障转移和通知新主节点所花费的时间。



该出版物描述了一种确保GitHub中MySQL的高可用性并发现主要服务的解决方案,该解决方案使我们能够可靠地执行涵盖多个数据中心的操作,在其中一些中心不可用时保持可操作性,并在发生故障时保证最小的停机时间。


高可用性目标


本文描述的解决方案是在GitHub上实现的先前高可用性(HA)解决方案的新改进版本。 随着我们的成长,我们需要调整MySQL HA策略以进行更改。 我们努力在GitHub上针对MySQL和其他服务采用类似的方法。


为了找到正确的解决方案以实现高可用性和服务发现,您应该首先回答一些具体问题。 这是其中的一个示例列表:


  • 对于您而言,最大的停机时间不重要?
  • 故障检测工具的可靠性如何? 误报(过早的故障处理)对您来说至关重要吗?
  • 故障转移系统的可靠性如何? 哪里会发生故障?
  • 该解决方案在多个数据中心的效果如何? 该解决方案在低延迟和高延迟网络中的有效性如何?
  • 如果整个数据中心(DPC)发生故障或网络隔离,该解决方案是否可以继续工作?
  • 哪种机制(如果有)可以防止或减轻群集中独立记录的两个主服务器的出现所带来的后果?
  • 数据丢失对您来说至关重要吗? 如果是这样,到什么程度?

为了演示,让我们首先考虑先前的解决方案,并讨论为什么我们决定放弃它。


拒绝使用VIP和DNS进行发现


作为先前解决方案的一部分,我们使用了:


  • 协调器,用于故障检测和故障转移;
  • VIP和DNS用于主机发现。

在这种情况下,客户端通过名称来发现记录节点,例如mysql-writer-1.github.net 。 该名称用于确定主节点的虚拟IP地址(VIP)。


因此,在通常情况下,客户只需要解析名称并连接到接收到的IP地址,主节点已经在该IP地址上等待着他们。


考虑以下跨越三个不同数据中心的复制拓扑:


图片


如果主节点发生故障,则必须将新服务器分配到其位置(副本之一)。


orchestrator检测到故障,选择一个新的主节点,然后分配名称/ VIP。 客户端实际上并不知道主节点的身份,他们仅知道名称,该名称现在应指向新节点。 但是,请注意这一点。


VIP地址是共享的,数据库服务器本身会请求并拥有它们。 要接收或释放VIP,服务器必须发送ARP请求。 拥有VIP的服务器必须先释放它,新的主服务器才能访问该地址。 这种方法导致一些不良后果:


  • 在正常模式下,故障转移系统将首先联系发生故障的主节点,并请求其释放VIP,然后转到新的主服务器并请求VIP分配。 但是,如果第一个主节点不可用或拒绝释放VIP地址的请求该怎么办? 鉴于服务器当前处于故障状态,它不太可能能够及时响应请求或完全响应请求。
    1. 结果,当两个主机要求他们对同一VIP的权利时,可能会出现这种情况。 根据最短的网络路径,不同的客户端可以连接到任何这些服务器。
    2. 在这种情况下,正确的操作取决于两个独立服务器的交互,并且这种配置不可靠。
  • 即使第一个主节点响应请求,我们也浪费了宝贵的时间:在与旧的主服务器联系时不会切换到新的主服务器。
  • 而且,即使在重新分配VIP的情况下,也无法保证旧服务器上的现有客户端连接将被断开。 同样,我们冒着处于具有两个独立主节点的情况的风险。

在我们的环境中,到处都有VIP地址与实际位置相关联。 它们被分配给交换机或路由器。 因此,我们只能将VIP地址重新分配给与原始主机位于同一环境中的服务器。 特别是在某些情况下,我们将无法在另一个数据中心中分配VIP服务器,并且需要对DNS进行更改。


  • 将更改分发到DNS需要更长的时间。 客户端将DNS名称存储一段预定的时间。 涉及多个数据中心的故障转移需要更长的停机时间,因为向所有客户提供有关新主节点的信息会花费更多时间。

这些限制足以迫使我们开始寻找新的解决方案,但是我们还必须考虑以下几点:


  • 主节点通过pt-heartbeat独立发送脉冲包,以测量延迟和负载调节 。 服务必须转移到新任命的主节点。 如果可能,应在旧服务器上将其禁用。
  • 同样,主要节点独立控制Pseudo-GTID的操作。 有必要在新的主节点上开始此过程,最好在旧的主节点上停止。
  • 新的主节点变为可写。 旧节点(如果可能)应具有read_only (只读)。

这些额外的步骤导致总的停机时间增加,并增加了自己的故障点和问题。


该解决方案有效,并且GitHub在后台成功处理了MySQL失败,但我们希望按以下方法改进HA的方法:


  • 确保与特定数据中心的独立性;
  • 在数据中心发生故障时保证可操作性;
  • 放弃不可靠的协作工作流程
  • 减少总停机时间;
  • 尽可能执行故障转移而不会造成损失。

GitHub HA解决方案:协调器,领事,GLB


我们的新策略以及随之而来的改进措施消除了上面提到的大多数问题,或减轻了它们的后果。 我们当前的HA系统包含以下元素:


  • 用于故障检测和故障转移的协调器。 我们将Orchestrator / Raft方案与多个数据中心一起使用,如下图所示;
  • Hashicorp Consul用于服务发现;
  • GLB / HAProxy作为客户端和记录节点之间的代理层。 GLB Director 的源代码已打开;
  • 网络路由的anycast技术。

图片


新方案允许完全放弃对VIP和DNS的更改。 现在,当引入新组件时,我们可以将它们分开并简化任务。 此外,我们有机会使用可靠和稳定的解决方案。 下面给出了新解决方案的详细分析。


正常流量


在正常情况下,应用程序通过GLB / HAProxy连接到记录节点。


应用程序不接收主服务器的身份。 和以前一样,它们仅使用名称。 例如, cluster1的主节点将是mysql-writer-1.github.net 。 但是,在我们当前的配置中,此名称解析为任意播 IP地址。


多亏了anycast技术,该名称可以在任何地方解析为相同的IP地址,但根据客户端的位置,流量的定向是不同的。 特别是,我们的每个数据中心都部署了我们的高可用负载均衡器GLB的多个实例。 mysql-writer-1.github.net流量始终路由到本地数据中心的GLB群集。 因此,所有客户均由本地代理服务。


我们在HAProxy之上运行GLB。 我们的HAProxy服务器提供写池 :每个MySQL群集一个。 此外,每个池只有一个服务器(集群的节点)。 所有数据中心中的所有GLB / HAProxy实例都具有相同的池,并且它们都指向这些池中的相同服务器。 因此,如果应用程序希望将数据写入mysql-writer-1.github.net上的数据库,则连接到哪个GLB服务器都没有关系。 无论哪种情况,都将重定向到实际的主群集节点cluster1


对于应用程序,发现在GLB上结束,并且不需要重新发现。 该GLB将流量重定向到正确的位置。


GLB在哪里获得有关要列出哪些服务器的信息? 我们如何更改GLB?


通过领事发现


Consul服务被广泛称为服务发现解决方案,并且还具有DNS功能。 但是,在我们的情况下,我们将其用作键值(KV)的高度可访问的存储。


在Consul的KV存储库中,我们记录主群集节点的身份。 对于每个群集,都有一组KV记录,指向对应的主节点的数据:其fqdn ,端口,ipv4和ipv6地址。


每个GLB / HAProxy节点都会启动一个consul-template ,该服务可跟踪Consul数据的更改(在我们的示例中为主要节点数据的更改)。 consul-template创建一个配置文件,并可以在更改设置时重新加载HAProxy。


因此,有关在Consul中更改主节点身份的信息可用于每个GLB / HAProxy实例。 基于此信息,将执行实例的配置,新的主节点将指示为群集服务器池中的唯一实体。 之后,将重新加载实例以使更改生效。


我们已经在每个数据中心中部署了Consul实例,并且每个实例都提供了高可用性。 但是,这些实例彼此独立。 它们不复制,也不交换任何数据。


领事从哪里获得有关变更的信息,以及如何在数据中心之间分配变更?


协调器/木筏


我们使用orchestrator/raft方案: orchestrator节点通过共识相互通信。 在每个数据中心中,我们都有一个或两个orchestrator节点。


orchestrator负责检测故障,MySQL故障转移并将更改后的主节点数据传输到Consul。 故障转移由单个orchestrator/raft主机管理,但是使用raft机制将群集现在是新的主机的消息更改传播到所有orchestrator节点。


orchestrator节点收到有关主节点数据更改的新闻时,它们中的每个节点都会联系其自己的Consul本地实例并启动KV记录。 具有多个orchestrator实例的数据中心将在Consul中接收多个(相同)记录。


整个流的通用视图


如果主节点发生故障:


  • orchestrator节点检测到故障;
  • orchestrator/raft主启动恢复。 分配了一个新的主节点;
  • orchestrator/raft方案将主要节点更改后的数据传输到raft群集的所有节点;
  • orchestrator/raft每个实例都会收到有关节点更改的通知,并将新的主节点的标识写入Consul中的本地KV存储中;
  • 在每个GLB / HAProxy实例上,启动consul-template服务,该服务监视Consul中KV存储库中的更改,重新配置并重新启动HAProxy;
  • 客户端流量将重定向到新的主节点。

对于每个组件,职责都有明确的分配,整个结构也得到了多样化和简化。 orchestrator器不与负载平衡器进行交互。 领事不需要有关信息来源的信息。 代理服务器仅与Consul一起使用。 客户端只能与代理服务器一起使用。


此外:


  • 无需更改DNS并散布有关它们的信息;
  • 不使用TTL;
  • 线程不等待处于错误状态的主机的响应。 通常,它被忽略。

附加信息


为了稳定流量,我们还应用以下方法:


  • HAProxy hard-stop-after参数设置为非常小的值。 当HAProxy在写池中使用新服务器重新启动时,该服务器会自动终止与旧主节点的所有现有连接。
    1. 设置hard-stop-after参数可以使您不必等待客户端的任何操作,此外,还可以最大程度地减少群集中两个主要节点可能出现的负面影响。 重要的是要了解这里没有魔术,无论如何,要打破旧的纽带需要一段时间 。 但是在某个时间点之后,我们可以停止等待不愉快的惊喜。
  • 我们不需要持续提供领事服务。 实际上,我们需要它仅在故障转移期间可用。 如果领事服务没有响应,则GLB会以最新的已知值继续工作,并且不会采取严厉措施。
  • GLB配置为验证新分配的主节点的身份。 与上下文敏感的MySQL池一样 ,执行检查以确认服务器确实可写。 如果我们不小心删除了Consul中主节点的身份,那么就不会有问题,空记录将被忽略。 如果我们错误地将另一台服务器(而不是主服务器)的名称写到Consul,那么就可以了:GLB不会更新它,并继续使用最后一个有效状态。

在以下各节中,我们着眼于问题并分析了高可用性的目标。


使用Orchestrator /筏进行碰撞检测


orchestrator采取了全面的方法来进行故障检测,从而确保了工具的高度可靠性。 我们不会遇到错误的肯定结果,不会执行过早的故障,这意味着排除了不必要的停机时间。


orchestrator/raft电路还可以应对数据中心完全网络隔离的情况(数据中心围墙)。 数据中心的网络隔离会引起混乱:数据中心内的服务器可以相互通信。 如何了解谁是真正孤立的人- 给定数据中心或所有其他数据中心内的服务器?


orchestrator/raft计划中, orchestrator/raft主服务器是故障转移。 节点成为领导者,该领导者得到组(仲裁)中多数的支持。 我们以这种方式部署了orchestrator节点,使得任何单个数据中心都无法提供多数,而任何n-1数据中心都可以提供。


在数据中心完全隔离的情况下,该中心的orchestrator节点与其他数据中心的类似节点断开连接。 结果,隔离的数据中心中的orchestrator节点无法成为raft群集中的引导节点。 如果此类节点是主节点,则它将失去此状态。 将为新主机分配其他数据中心的节点之一。 该负责人将获得所有其他可以相互交互的数据中心的支持。


这样, orchestrator主机将始终位于网络隔离的数据中心之外。 如果主节点位于隔离的数据中心中,那么orchestrator启动故障转移,以将其替换为可用数据中心之一的服务器。 我们通过将决策委派给可用数据中心的仲裁人数来减轻数据中心隔离的影响。


更快的通知


通过加快主节点中更改通知的时间,可以进一步减少总停机时间。 如何实现呢?


orchestrator启动故障转移时,它将考虑一组服务器,其中一个可以分配为主服务器。 给定复制规则,建议和限制,他能够就最佳操作方案做出明智的决定。


根据以下迹象,他还可以理解,可访问服务器是首选的主要候选服务器:


  • 没有什么可以防止服务器升高(也许用户建议使用此服务器);
  • 预期该服务器将能够使用所有其他服务器作为副本。

在这种情况下, orchestrator首先将服务器配置为可写,然后立即宣布其状态增加(在我们的示例中,它将记录写入Consul中的KV存储库)。 orchestrator , .


, , GLB , , . : !



MySQL , . : , , , .


, . , , . , , , .


: 500 . . ( ), .


( ) . , .


, . , , . , , , .



, / pt-heartbeat / , . , pt-heartbeat , read_only , .


pt-heartbeat , . . . , pt-heartbeat .


orchestrator


orchestrator :


  • Pseudo-GTID;
  • , ;
  • ( read_only ), .

, . , , , . orchestrator .



- , , . , -, .


, .


, , , - . . STONITH . , , , «» - . , , .


: Consul , . . , , , , .



orchestrator/GLB/Consul :


  • ;
  • ;
  • ;
  • ;
  • , ( );
  • ;
  • 10-13 .
    1. 20 , — 25 .

结论


«// » , , . . , .

Source: https://habr.com/ru/post/zh-CN432088/


All Articles