MySQL Shell 8.4  /  MySQL InnoDB ClusterSet  /  InnoDB ClusterSet 控制切换

8.7 InnoDB ClusterSet 控制切换

控制切换使选定的副本集群成为 InnoDB ClusterSet 部署的主集群。在控制切换过程中,可以确保数据一致性。该过程会验证所选副本集群是否与主集群同步(如果存在复制延迟,则可能需要稍等片刻),然后将该集群设为 InnoDB ClusterSet 的主集群。原始主集群降级为工作只读副本集群。然后,如果需要,您可以使原始主集群脱机,修复任何问题,并将其恢复到 InnoDB ClusterSet 部署中运行。

如果 InnoDB ClusterSet 部署中的主集群正常运行,但您需要执行维护或修复一些小问题以改进主集群的功能,请按照控制切换过程进行操作。当您使用 MySQL Shell 中的 AdminAPI 的 clusterSet.status() 命令检查主集群时,如果其正常运行,则其全局状态为 OK

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

如果您无法通过处理主集群来解决问题(例如,因为您无法联系到它),则需要执行紧急故障转移。紧急故障转移专为在主集群突然不可用时进行灾难恢复而设计。该过程存在丢失事务和为 InnoDB ClusterSet 造成脑裂情况的风险。如果您确实需要执行紧急故障转移,请按照第 8.8 节“InnoDB ClusterSet 紧急故障转移”中的过程进行操作,以确保风险得到管理。

该图显示了在示例 InnoDB ClusterSet 部署中进行控制切换的效果。罗马数据中心的主集群需要维护,因此已执行控制切换,以使布鲁塞尔数据中心中的副本集群成为 InnoDB ClusterSet 部署的主集群,并将罗马集群降级为副本集群。罗马集群上的 ClusterSet 复制通道已由控制切换过程激活,并且正在复制来自布鲁塞尔集群的事务。现在罗马集群是一个副本集群,如果需要执行维护工作,则可以安全地使成员服务器或整个集群脱机。

图 8.2 InnoDB ClusterSet 切换

The InnoDB Cluster in the Rome datacenter is now a replica cluster, and the InnoDB Cluster in the Brussels datacenter is now the primary cluster. The asynchronous replication channel is now sending transactions from the Brussels cluster to the Rome cluster. 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 can continue to send traffic to it because it is only sending read traffic.

在示例 InnoDB Cluster 部署中,设置为跟随主集群的 MySQL Router 实例已将读写流量路由到布鲁塞尔集群,该集群现在是主集群。当布鲁塞尔集群是副本集群时,按名称将读取流量路由到该集群的 MySQL Router 实例会继续将流量路由到该集群,并且不受该集群现在是主集群而不是副本集群这一事实的影响。同样,按名称将读取流量路由到罗马集群的 MySQL Router 实例可以继续这样做,因为副本集群仍然接受读取流量。

要对主 InnoDB Cluster 执行控制切换,请按照以下过程进行操作

  1. 使用 MySQL Shell,使用 InnoDB Cluster 管理员帐户(使用 cluster.setupAdminAccount() 创建)连接到主集群或其中一个副本集群中的任何成员服务器。您还可以使用 InnoDB Cluster 服务器配置帐户,该帐户也具有所需的权限。使用 dba.getClusterSet()cluster.getClusterSet() 命令获取 ClusterSet 对象。务必使用 InnoDB Cluster 管理员帐户或服务器配置帐户,以便存储在 ClusterSet 对象中的默认用户帐户具有正确的权限。例如

    mysql-js> \connect [email protected]:3310
    Creating a session to '[email protected]:3310'
    Please provide the password for '[email protected]:3310': ********
    Save password for '[email protected]:3310'? [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 52
    Server version: 8.0.27-commercial MySQL Enterprise Server - Commercial
    No default schema selected; type \use <schema> to set one.
    <ClassicSession:[email protected]:3310>
    mysql-js> myclusterset = dba.getClusterSet()
    <ClusterSet:testclusterset>

    在此示例中:

    • admin2@127.0.0.1:3310 是集群中任何在线成员服务器实例的类 URI 连接字符串。

      类 URI 连接字符串由以下元素组成:

    • admin2 是 InnoDB Cluster 管理员帐户的用户名。

    • 127.0.0.1:3310 是成员服务器实例的主机和端口,如 cluster.status() 命令所示。

    • 返回的 ClusterSet 对象分配给变量 myclusterset

  2. 使用 MySQL Shell 中的 AdminAPI 的 clusterSet.status() 命令检查整个 InnoDB ClusterSet 部署的状态。使用 extended 选项查看部署中所有集群的详细信息,并检查是否存在任何问题。例如

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

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

  3. 确定一个合适的副本集群,该集群可以接管为主集群。副本集群是否有资格进行控制切换取决于其全局状态,如 clusterSet.status() 命令报告的那样:

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

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

    全局状态为 OK_NOT_CONSISTENT 的副本集群在集群上具有一组事务(GTID 集),该事务集与主集群上的 GTID 集不一致。InnoDB ClusterSet 不允许对处于此状态的集群进行控制切换,因为客户端将访问不正确的数据。如果集群在可用选项中具有最新的事务集,则可以进行紧急故障转移。

  4. 通过连接到 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 实例会将流量发送到当前在 InnoDB ClusterSet 部署中充当主集群的任何集群。如果所有 MySQL Router 实例都设置为跟随主集群("target_cluster": "primary"),则流量将在切换后的几秒钟内自动重定向到新的主集群。如果未为 MySQL Router 实例显示路由选项(如上例中的 Rome2),则表示该实例未设置该策略,并且遵循全局策略。

    如果任何实例都设置为按名称将流量定向到当前的主集群("target_cluster": "name_of_primary_cluster"),则它们不会将流量重定向到新的主集群。在这种情况下,如果适合应用程序,您可以使用 clusterSet.setRoutingOption() 命令更改这些实例的路由策略。您可以将这些实例更改为跟随主集群("target_cluster": "primary"),在这种情况下,现在可以设置该选项。例如

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

    在此示例中,myclustersetClusterSet 对象的变量,而 Rome1 是 MySQL Router 实例的名称。

    或者,您可以指定将接管为主集群的副本集群,在这种情况下,在切换发生后,当您验证切换已成功时,设置选项("target_cluster": "name_of_new_primary_cluster")。

  5. 发出 clusterSet.setPrimaryCluster() 命令,命名将接管为新的主集群的副本集群。使用您使用 InnoDB Cluster 管理员帐户通过 dba.getClusterSet()cluster.getClusterSet() 命令检索到的 ClusterSet 对象。例如

    mysql-js> myclusterset.setPrimaryCluster('clustertwo')
    Switching the primary cluster of the clusterset to 'clustertwo'
    * Verifying clusterset status
    ** Checking cluster clustertwo
      Cluster 'clustertwo' is available
    ** Checking cluster clusterone
      Cluster 'clusterone' is available
    
    * Refreshing replication account of demoted cluster
    * Synchronizing transaction backlog at 127.0.0.1:4410
    ** Transactions replicated  ############################################################  100%
    * Updating metadata
    
    * Updating topology
    ** Changing replication source of 127.0.0.1:3330 to 127.0.0.1:4410
    * Acquiring locks in replicaset instances
    ** Pre-synchronizing SECONDARIES
    ** Acquiring global lock at PRIMARY
    ** Acquiring global lock at SECONDARIES
    
    * Synchronizing remaining transactions at promoted primary
    ** Transactions replicated  ############################################################  100%
    * Updating replica clusters
    Cluster 'clustertwo' was promoted to PRIMARY of the clusterset. The PRIMARY instance is '127.0.0.1:4410'

    对于 clusterSet.setPrimaryCluster() 命令:

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

    • 如果要在不实际执行更改的情况下执行验证并记录更改,请使用 dryRun 选项。

    • 使用 timeout 选项设置在切换发生之前等待副本集群与主集群同步的最长时间(以秒为单位)。如果超时,则切换将被取消。

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

    当您发出 clusterSet.setPrimaryCluster() 命令时,MySQL Shell 会检查目标副本集群是否符合接管主集群的要求,如果不符合,则返回错误。如果目标副本集群满足要求,MySQL Shell 将执行以下任务

    • 检查是否有任何未指定为 invalidateReplicaClusters 的不可访问或不可用副本集群。

    • 等待目标副本集群通过应用来自主集群的任何未完成事务与当前主集群同步。如果 timeout 选项设置的超时时间在副本集群完成应用事务之前过期,则切换将被取消。

    • 通过发出 FLUSH TABLES WITH READ LOCK 语句并在所有成员服务器上设置 super_read_only 系统变量来锁定当前主集群,以防止在切换过程中发生进一步更改。禁用组复制成员操作 mysql_disable_super_read_only_if_primary,以便在故障转移后 super_read_only 保持设置状态。

    • 协调当前主集群和副本集群之间视图更改事件的差异,以便 GTID 集相同。这些组复制内部事务由 group_replication_view_change_uuid 系统变量指定的 UUID 标识。MySQL Shell 在所有副本集群上注入空事务,以匹配主集群上的视图更改事件。

      注意

      对于运行 MySQL Server 8.3.0 或更高版本的集群,这不是必需的。

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

    • 在目标集群的主服务器上禁用 super_read_only,并启用组复制成员操作 mysql_disable_super_read_only_if_primary,以处理该集群中主服务器的任何更改。

    • 在旧主集群的主服务器上禁用组复制成员操作 mysql_disable_super_read_only_if_primary,以便它保持只读状态,并在该服务器上启用组复制成员操作 mysql_start_failover_channels_if_primary,以便为 ClusterSet 复制通道上的副本启用异步连接故障转移。

    • 在 ClusterSet 元数据中将目标集群设置为主要集群,并将旧主集群更改为副本集群。

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

  7. 如果您有任何 MySQL Router 实例要切换到以新主集群为目标,请立即执行此操作。例如:

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

    在此示例中,myclustersetClusterSet 对象的变量,Rome1 是 MySQL Router 实例的名称,clustertwo 是要定位的特定集群的名称。完成后,发出 clusterSet.routingOptions() 命令,检查所有 MySQL Router 实例现在是否都正确路由。

  8. 现在,您可以使用旧主集群来修复问题或执行维护。如果在切换过程中必须使任何副本集群无效,则也可以修复这些副本集群并将其重新添加到 InnoDB ClusterSet 中。第 8.9 节“InnoDB ClusterSet 修复和重新加入”说明了如何修复集群问题、如何将集群重新加入 InnoDB ClusterSet 以及如何使集群再次成为主集群。