MySQL Shell 9.0  /  MySQL InnoDB ClusterSet  /  InnoDB ClusterSet 紧急故障转移

8.8 InnoDB ClusterSet 紧急故障转移

紧急故障转移会将选定的副本集群设为 InnoDB ClusterSet 部署的主 InnoDB 集群。当当前主集群无法工作或无法联系时,可以使用此过程。在紧急故障转移过程中,数据一致性无法保证,因此为了安全起见,在故障转移过程中,原始主集群会被标记为无效。如果原始主集群保持在线,则应在可以联系到它后立即将其关闭。之后,您可以将无效的主集群修复并重新加入 InnoDB ClusterSet 拓扑,前提是您可以修复问题。

当 InnoDB ClusterSet 部署中的主 InnoDB 集群出现问题或您无法访问它时,请勿立即对副本集群实施紧急故障转移。相反,您应该始终尝试先修复当前活动的主集群。

重要

**为什么不直接进行故障转移?** InnoDB ClusterSet 拓扑中的副本集群正在尽最大努力保持与主集群同步。但是,根据事务量以及主集群和副本集群之间网络连接的速度和容量,副本集群在接收事务和将更改应用于其数据时可能会落后于主集群。这称为复制延迟。在大多数复制拓扑中,预计会出现一些复制延迟,并且在集群在地理上分散且位于不同数据中心的 InnoDB ClusterSet 部署中很可能出现这种情况。

此外,主集群也可能因网络分区而与 InnoDB ClusterSet 拓扑的其他元素断开连接,但仍保持在线状态。如果发生这种情况,某些副本集群可能会保留在主集群中,并且某些实例和客户端应用程序可能会继续连接到主集群并应用事务。在这种情况下,InnoDB ClusterSet 拓扑的分区区域开始彼此分离,每组服务器上都有不同的交易集。

当存在复制延迟或网络分区时,如果触发紧急故障转移到副本集群,则主集群上任何未复制或不同的交易都可能丢失。在网络分区的情况下,故障转移可能会造成脑裂情况,其中拓扑的不同部分具有不同的交易集。因此,在触发紧急故障转移之前,您应该始终尝试修复或重新连接主集群。如果主集群无法快速修复或无法访问,则可以继续进行紧急故障转移。

该图显示了在示例 InnoDB ClusterSet 部署中紧急故障转移的影响。罗马数据中心的主集群已脱机,因此已执行紧急故障转移,以使布鲁塞尔数据中心的副本集群成为 InnoDB ClusterSet 部署的主 InnoDB 集群。罗马集群已标记为无效,并且其在 InnoDB ClusterSet 部署中的状态已降级为副本集群,尽管它目前无法复制来自布鲁塞尔集群的事务。

图 8.3 InnoDB ClusterSet 故障转移

The InnoDB Cluster in the Rome datacenter is now offline and invalidated, and the InnoDB Cluster in the Brussels datacenter is now the primary cluster. Asynchronous replication between the two is not taking place because the Rome cluster is not available. The MySQL Router instances that targeted the primary or the Brussels cluster are sending traffic to the Brussels cluster. The instance that specifically targeted the Rome cluster cannot send traffic to the cluster.

设置为跟随主服务器的 MySQL Router 实例已将读写流量路由到现为主服务器的布鲁塞尔集群。当布鲁塞尔集群是副本集群时,通过名称路由到该集群的读取流量的 MySQL Router 实例继续路由到该集群的流量,并且不受该集群现在是主集群而不是副本集群这一事实的影响。但是,通过名称将读取流量路由到罗马集群的 MySQL Router 实例当前无法向其发送任何流量。此示例中的报告应用程序不需要报告本地数据中心何时脱机,但如果应用程序确实仍需要运行,则应更改 MySQL Router 实例的路由选项,以跟随主服务器或向布鲁塞尔集群发送流量。

要对主 InnoDB 集群执行紧急故障转移,请执行以下过程

  1. 使用 MySQL Shell,使用 InnoDB 集群管理员帐户(使用 cluster.setupAdminAccount() 创建)连接到 InnoDB ClusterSet 部署中仍处于活动状态的任何成员服务器。您也可以使用 InnoDB 集群服务器配置帐户,该帐户也具有所需的权限。

    建立连接后,使用 dba.getClusterSet()cluster.getClusterSet() 命令从该成员服务器获取 ClusterSet 对象。您之前从现在已脱机的成员服务器检索到的 ClusterSet 对象将不再起作用,因此您需要从联机的服务器再次获取它。必须使用 InnoDB 集群管理员帐户或服务器配置帐户,以便存储在 ClusterSet 对象中的默认用户帐户具有正确的权限。例如:

    mysql-js> \connect [email protected]:4410
    Creating a session to '[email protected]:4410'
    Please provide the password for '[email protected]:4410': ********
    Save password for '[email protected]:4410'? [Y]es/[N]o/Ne[v]er (default No):
    Fetching schema names for autocompletion... Press ^C to stop.
    Closing old connection...
    Your MySQL connection id is 71
    Server version: 8.0.27-commercial MySQL Enterprise Server - Commercial
    No default schema selected; type \use <schema> to set one.
    <ClassicSession:[email protected]:4410>
    
    mysql-js> myclusterset = dba.getClusterSet()
    <ClusterSet:testclusterset>
  2. 使用 MySQL Shell 中的 AdminAPI 的 clusterSet.status() 函数检查整个部署的状态。使用 extended 选项可以准确查看问题的位置和类型。例如:

    mysql-js> myclusterset.status({extended: 1})

    有关输出的说明,请参阅 第 8.6 节“InnoDB ClusterSet 状态和拓扑”

  3. InnoDB 集群可以容忍某些问题,并且其功能足以继续作为 InnoDB ClusterSet 部署的一部分。根据报告的状态,如果主集群在 InnoDB ClusterSet 部署中正常运行,则在使用 clusterSet.status() 命令检查时,其全局状态为 OK。例如,如果集群中的其中一个成员服务器脱机,即使该服务器是主服务器,底层的组复制技术也可以处理这种情况并重新配置自身。

    如果主集群在 InnoDB ClusterSet 部署中根据报告的状态仍然可以接受地运行,但是您需要执行维护或修复一些小问题以改进主集群的功能,则可以执行到副本集群的受控切换。然后,您可以根据需要使主集群脱机,修复任何问题,并将其重新投入 InnoDB ClusterSet 部署中运行。有关执行此操作的说明,请参阅 第 8.7 节“InnoDB ClusterSet 受控切换”

  4. 如果主集群在 InnoDB ClusterSet 部署中无法正常运行(全局状态为 NOT_OK),但是您可以联系到它,请首先尝试使用 AdminAPI 通过 MySQL Shell 修复任何问题。例如,如果主集群丢失了仲裁,则可以使用 cluster.forceQuorumUsingPartitionOf 命令将其还原。有关执行此操作的说明,请参阅 第 8.9 节“InnoDB ClusterSet 修复和重新加入”

  5. 如果您无法执行受控切换,并且无法通过使用主集群快速解决问题(例如,因为您无法联系到它),请继续进行紧急故障转移。首先确定一个合适的副本集群,该集群可以接管成为主集群。副本集群是否有资格进行紧急故障转移取决于其全局状态,如 clusterSet.status() 命令报告的那样

    表 8.2 按状态允许的集群操作

    InnoDB 集群在 ClusterSet 中的全局状态 可路由 受控切换 紧急故障转移
    OK
    OK_NOT_REPLICATING 是,如果按名称指定为目标集群
    OK_NOT_CONSISTENT 是,如果按名称指定为目标集群
    OK_MISCONFIGURED
    NOT_OK
    INVALIDATED 是,如果按名称指定为目标集群并且设置了 accept_ro 路由策略
    UNKNOWN 已连接的路由器实例可能仍在将流量路由到集群

    您选择的副本集群必须在所有可访问的副本集群中拥有最新的事务集 (GTID 集)。如果多个副本集群有资格进行紧急故障转移,请检查每个集群的复制延迟(这在 clusterSet.status() 命令的扩展输出中显示)。选择复制延迟最小的副本集群,该集群应该具有最多的事务。紧急故障转移过程会检查当前可访问的所有副本集群的 GTID 集,并告诉您是否有其他集群更新,以便您可以使用该集群重试。

  6. 通过连接到 InnoDB ClusterSet 部署中的任何成员服务器并在 MySQL Shell 中发出 clusterSet.routingOptions() 命令,检查为每个 MySQL Router 实例设置的路由选项以及 InnoDB ClusterSet 部署的全局策略。例如:

    mysql-js> myclusterset.routingOptions()
    {
        "domainName": "testclusterset",
        "global": {
            "invalidated_cluster_policy": "drop_all",
            "target_cluster": "primary"
        },
        "routers": {
            "Rome1":  {
                "target_cluster": "primary"
            },
            "Rome2": {}
        }
    }

    如果所有 MySQL Router 实例都设置为跟随主服务器("target_cluster": "primary"),则在故障转移后的几秒钟内,流量将自动重定向到新的主服务器。如果没有为 MySQL Router 实例显示路由选项,如上例中 "target_cluster"Rome2 所示,则表示该实例未设置该策略,并且它遵循全局策略。

    如果任何实例被设置为按名称("target_cluster": "主集群名称")连接到当前主集群,它们将不会将流量重定向到新的主集群。当主集群无法正常工作时,clusterSet.setRoutingOption() 命令无法用于更改路由选项,因此在故障转移到新的主集群完成之前,您无法重定向由该 MySQL Router 实例处理的流量。

  7. 如果可以,请尝试验证原始主集群是否已脱机,如果已在线,请尝试将其关闭。如果它保持在线并继续接收来自客户端的流量,则可能会创建一个脑裂情况,其中 InnoDB ClusterSet 的分离部分发生分歧。

  8. 要继续进行紧急故障转移,请发出 clusterSet.forcePrimaryCluster() 命令,指定将接管为新主集群的副本集群。例如

    mysql-js> myclusterset.forcePrimaryCluster("clustertwo")
    Failing-over primary cluster of the clusterset to 'clustertwo'
    * Verifying primary cluster status
    None of the instances of the PRIMARY cluster 'clusterone' could be reached.
    * Verifying clusterset status
    ** Checking cluster clustertwo
      Cluster 'clustertwo' is available
    ** Checking whether target cluster has the most recent GTID set
    * Promoting cluster 'clustertwo'
    * Updating metadata
    
    PRIMARY cluster failed-over to 'clustertwo'. The PRIMARY instance is '127.0.0.1:4410'
    Former PRIMARY cluster was INVALIDATED, transactions that were not yet replicated may be lost.

    clusterSet.forcePrimaryCluster() 命令中

    • clusterName 参数是必需的,用于指定 InnoDB ClusterSet 中用于副本集群的标识符,如 clusterSet.status() 命令的输出中所示。在本例中,clustertwo 是将成为新主集群的集群。

    • 如果要执行验证并记录更改而不实际执行它们,请使用 dryRun 选项。

    • 使用 invalidateReplicaClusters 选项来命名任何不可达或不可用的副本集群。这些将在故障转移过程中被标记为无效。如果在该过程中发现任何未命名的不可达或不可用的副本集群,则故障转移将被取消。在这种情况下,您必须修复副本集群并重新加入,然后重试该命令,或者在重试该命令时在此选项上命名它们,并在以后修复它们。

    • 使用 timeout 选项来定义在集群的每个实例中等待挂起事务应用的最大秒数。确保 GTID_EXECUTED 具有最新的 GTID 集。默认值是从 dba.gtidWaitTimeout 选项中检索的。

    当您发出 clusterSet.forcePrimaryCluster() 命令时,MySQL Shell 会检查目标副本集群是否符合接管为主集群的要求,如果不符合,则返回错误。

    如果目标副本集群满足要求,MySQL Shell 将执行以下任务

    • 尝试联系当前的主集群,如果实际上可以访问,则停止故障转移。

    • 检查是否有任何未指定为 invalidateReplicaClusters 的不可达或不可用的副本集群,如果找到任何集群,则停止故障转移。

    • invalidateReplicaClusters 中列出的所有副本集群标记为无效,并将旧的主集群标记为无效。

    • 检查目标副本集群是否具有可用副本集群中最新的 GTID 集。这涉及在所有副本集群中停止 ClusterSet 复制通道。

    • 更新所有副本集群上的 ClusterSet 复制通道,以从作为新主集群的目标集群复制数据。

    • 在 ClusterSet 元数据中将目标集群设置为主要集群,并将旧的主集群更改为副本集群,尽管它当前不能作为副本集群运行,因为它被标记为无效。

    在紧急故障转移期间,MySQL Shell 不会尝试将目标副本集群与当前主集群同步,也不会锁定当前主集群。如果原始主集群保持在线,则应尽快将其关闭。

  9. 如果您有任何 MySQL Router 实例要切换到连接新的主集群,请立即执行此操作。您可以将它们更改为跟随主服务器("target_cluster": "primary"),或指定已接管为主服务器的副本集群("target_cluster": "新主集群名称")。例如

    mysql-js> myclusterset.setRoutingOption('Rome1', 'target_cluster', 'primary')
    or
    mysql-js> myclusterset.setRoutingOption('Rome1', 'target_cluster', 'clustertwo')
    Routing option 'target_cluster' successfully updated in router 'Rome1'.

    发出 clusterSet.routingOptions() 命令以检查所有 MySQL Router 实例现在是否都正确路由。

  10. 再次使用 extended 选项发出 clusterSet.status() 命令,以验证 InnoDB ClusterSet 部署的状态。

  11. 如果并且当您可以再次联系到旧的主集群时,首先确保没有任何应用程序流量被路由到它,并将其脱机。然后按照 第 8.9 节“InnoDB ClusterSet 修复和重新加入” 中的过程检查事务并决定如何安排 InnoDB ClusterSet 拓扑。

    在紧急故障转移之后,ClusterSet 的不同部分之间存在事务集不同的风险,您必须对集群进行隔离,使其免受写入流量或所有流量的影响。有关详细信息,请参阅隔离 InnoDB ClusterSet 中的集群

    如果您在切换过程中必须使任何副本集群无效,那么如果并且当您可以再次联系到它们时,可以使用 第 8.9 节“InnoDB ClusterSet 修复和重新加入” 中的过程来修复它们并将它们添加回 InnoDB ClusterSet。