公司动态
InnoDB Cluster高可用测试实战:主从切换与故障恢复验证
1. 引言为什么需要 InnoDB Cluster 高可用测试在分布式数据库的落地过程中建立一套高可用架构只是第一步。真正决定系统能否在生产环境稳定运行的关键在于高可用机制是否经过充分的故障演练与验证。很多团队在完成 InnoDB Cluster 部署后往往只验证了「节点可以启动、状态看起来正常」却从未真正模拟过主节点宕机、网络分区、磁盘写满等真实故障场景。当真实故障到来时自动切换是否能够按时触发、数据是否会出现丢失、应用连接是否能够无感知恢复这些问题都暴露在黑夜中。InnoDB Cluster 作为 MySQL 官方推出的高可用解决方案集成了 MySQL 组复制、MySQL Shell 和 MySQL Router 三大组件提供了完整的高可用闭环能力。但它并不是一个「开启即可高枕无忧」的黑盒组复制的选举机制、多数派判定、流量切换策略以及客户端重连行为都与实际业务可用性密切相关。本文将以实战为驱动围绕「测试」而不是「部署」这一核心系统地验证 InnoDB Cluster 在主从切换、计划内维护切换、主节点宕机、网络抖动、脑裂防护、数据一致性、故障恢复与回切等场景下的真实表现。文章会给出每一步的操作命令、预期结果、观察要点以及与常见误区相关的说明并最终提炼出一套可复用、可量化的高可用测试清单。全文约两万字适合具备一定 MySQL 基础、正在搭建或已部署 InnoDB Cluster 的 DBA、运维工程师以及后端架构师阅读。需要特别说明的是本文采用的验证环境为 MySQL 8.0.35、MySQL Shell 8.0.35 与 MySQL Router 8.0.35操作系统为 Rocky Linux 9.3。不同小版本之间的行为可能存在差异但整体架构、测试思路与方法论是通用的。2. InnoDB Cluster 高可用架构再认识2.1 核心组件与协同关系InnoDB Cluster 由三个官方组件组成它们的分工非常明确。MySQL 组复制负责底层的数据同步与主节点选举它基于 Paxos 变体协议实现一致性MySQL Shell 负责集群的部署、配置与管理同时提供 AdminAPI 供运维人员操作MySQL Router 则承担应用访问层的流量路由职责将读写请求发送到主节点将只读请求分发到从节点并在主节点切换时快速更新路由表。理解这三者的协同方式对于故障测试非常重要。例如当主节点发生故障时组复制首先完成新主的选举随后只有在新主可写之后Router 才会将写入流量切到新主。这中间存在一个时间窗口如果应用没有配置合理的超时与重试策略就可能在这个窗口内出现报错。组复制默认采用单主模式即同一时刻只有一个节点可以对外提供读写服务。这种模式与经典的异步复制主从架构在思路上存在根本差异。异步复制中主节点故障后从节点需要手动提升且可能丢失已经提交但尚未同步的事务而组复制通过 Paxos 协议保证多数派确认后事务才提交因此在多数派节点存活的前提下故障切换不会丢失已经确认提交的数据这是其高可用能力的核心价值。2.2 单主模式下的角色划分在单主模式中每个成员节点都有明确的角色。主节点称为 PRIMARY负责接收全部读写请求并产生事务其他节点称为 SECONDARY持续从主节点接收事务并应用。组复制内部使用 GTID 追踪事务执行状态保证各节点数据最终一致。此外还有一个 ONLINE 与 RECOVERING 的状态概念。当节点加入集群或者从故障中恢复时它会先进入 RECOVERING 状态通过增量同步或全量克隆补齐数据随后才进入 ONLINE 状态。测试时必须区分「节点恢复在线」和「节点重新加入集群」两个阶段很多看似异常的现象其实是恢复流程尚未完成导致的。还有一个容易混淆的概念是 OFFLINE 模式。通过 MySQL Shell 可以将某个节点安全地置为 OFFLINE使其暂时退出集群但不销毁数据。这个特性在计划性维护测试中非常有用可以验证集群在成员主动退出时的行为。2.3 一致性级别与故障切换的关系组复制提供多种一致性级别包括 EVENTUAL、BEFORE_ON_PRIMARY_FAILOVER、BEFORE 和 AFTER。在默认情况下组复制的一致性级别是 EVENTUAL这意味着读操作可能读到尚未全局同步的数据。对于主从切换测试而言关键参数在于切换瞬间新主节点的数据状态。当开启 BEFORE_ON_PRIMARY_FAILOVER 级别时在主节点故障切换发生前集群会尽量保证待提升节点已经应用了所有已确认事务从而进一步降低切换时出现数据滞后的概率但会带来一定的性能开销。在故障恢复验证中我们需要明确当前集群的一致性级别并结合测试结果判断该参数是否满足业务要求。2.4 多数派与可用的边界条件组复制遵循「多数派可用」原则。在三节点集群中只要两个节点存活并可以互相通信集群就能够选出主节点并继续对外服务。若存活节点少于多数派集群会进入不可写状态这是为了阻止脑裂场景下出现双主同时写入导致数据冲突。这个边界条件是故障测试的重点。很多测试者会提出疑问三节点集群挂掉两台后剩下一台为什么不能继续写原因是如果允许少数派继续写当分区恢复后少数派与多数派之间会产生数据冲突最终导致数据不一致。因此不可写不是缺陷而是分布式共识机制下的正确行为。3. 测试目标与测试矩阵设计3.1 高可用测试的核心理念高可用测试不同于功能测试。功能测试关注的是系统在正常输入下能否产生正确输出而高可用测试关注的是系统在异常输入、组件失效、网络异常等条件下是否仍能维持可接受的服务水平。因此高可用测试需要引入「故障注入」的思想即主动制造故障观察系统反应再恢复故障验证系统自愈能力。一次合格的高可用测试必须能够回答三个问题。第一故障发生后多长时间能够恢复服务即恢复时间目标。第二故障期间有多少请求受到影响是否出现数据丢失。第三故障恢复后集群是否真正回到健康状态而不是表面在线但实际存在隐患。3.2 测试范围与前置条件本文的测试范围覆盖计划内主从切换、主节点宕机故障、网络分区、从节点故障、成员主动退出与重新加入、故障恢复后的数据校验、Router 流量切换以及应用连接重试表现。每个测试场景都会记录前置条件、操作步骤、预期结果与实际观察。测试环境包含三个数据节点和两台 Router。为了观察切换期间应用层的真实表现还需要一个持续写入的客户端以及一个持续读取的客户端。测试数据表需要包含自增主键、唯一键、文本字段以及时间字段以覆盖不同类型的数据校验。所有节点应关闭 SELinux 干扰、统一时区与时间同步并保证防火墙规则允许组复制通信端口和数据端口。测试前应使用 MySQL Shell 确认集群状态为在线且所有成员均处于 ONLINE 状态。3.3 测试指标定义为了让测试结果可量化需要提前定义一组关键指标。切换时长指从主节点故障注入到 Router 将新主节点写入流量切换完成的时间。故障检测时间指从故障发生到集群判定主节点失效的时间。不可写入时长指应用端观察到的写入失败总时长。数据一致性偏差指故障恢复后各节点数据差异行数。连接恢复时间指应用连接断开到重新建立可用连接的时间。这些指标能够帮助我们在不同参数配置、不同故障类型下进行横向对比。测试过程中应使用时间戳记录关键事件有条件时可以使用统一的时间基准例如通过 MySQL 的 NOW(6) 获取微秒级时间避免人为记录带来的误差。3.4 测试环境的角色规划本文使用以下规划。ic-node-1 的 IP 为 192.168.56.11作为初始主节点ic-node-2 的 IP 为 192.168.56.12作为第一个从节点ic-node-3 的 IP 为 192.168.56.13作为第二个从节点。Router 分别部署在应用服务器 192.168.56.21 和 192.168.56.22 上暴露读写端口 6446 和只读端口 6447。应用侧使用一个 Python 脚本持续执行插入操作保持每 100 毫秒写入一行并记录每次写入的成功状态、耗时和错误信息。这样一个持续写入的探针能够在切换发生时立即捕捉到故障窗口为后续的恢复时间分析提供数据支撑。4. 环境部署与集群初始化4.1 节点基础配置在开始高可用测试之前需要确保三个 MySQL 节点的配置满足组复制要求。每个节点的配置文件中需要启用 GTID 并设置唯一 server-id、binlog 相关参数以及组复制插件相关配置。下面给出 ic-node-1 的核心配置片段。[mysqld] server_id1 gtid_modeON enforce_gtid_consistencyON binlog_checksumNONE log_binmysql-bin log_slave_updatesON binlog_formatROW master_info_repositoryTABLE relay_log_info_repositoryTABLE transaction_write_set_extractionXXHASH64 plugin_load_addgroup_replication.so group_replication_group_nameaaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa group_replication_start_on_bootOFF group_replication_local_address192.168.56.11:33061 group_replication_group_seeds192.168.56.11:33061,192.168.56.12:33061,192.168.56.13:33061 group_replication_bootstrap_groupOFF report_host192.168.56.11其中transaction_write_set_extraction 设置为 XXHASH64 是组复制捕获写集合的必要条件group_replication_local_address 必须使用与 MySQL 数据端口不同的端口并且三个节点之间网络要互通group_replication_group_seeds 填写所有成员的组通信地址。配置完成后重启三个 MySQL 实例。需要注意的是所有节点在加入集群前必须保证 binlog 没有外部写入否则在加入集群时可能因为 GTID 冲突而失败。对于新环境初始化的数据目录应保持干净。4.2 使用 MySQL Shell 部署集群部署集群统一使用 MySQL Shell 的 AdminAPI。先连接到第一个节点执行 dba.createCluster() 创建集群。该命令会检查配置、创建集群元数据并初始化组复制。\c root192.168.56.11:3306 var cluster dba.createCluster(prodCluster, {localAddress: 192.168.56.11:33061}) cluster.status()createCluster 成功后再分别添加另外两个节点。添加节点时可以使用 clone 方式从现有节点克隆数据这是最常用且可靠的方式。克隆过程会通过 MySQL Clone 插件将数据完整同步到新节点完成后自动启动组复制并将节点带入 ONLINE 状态。cluster.addInstance(root192.168.56.12:3306, {localAddress: 192.168.56.12:33061}) cluster.addInstance(root192.168.56.13:3306, {localAddress: 192.168.56.13:33061}) cluster.status()执行完成后使用 cluster.status() 查看集群状态正常时应显示三个节点均为 ONLINE且其中一个节点带有 R/W 标记表示当前主节点其余节点显示 R/O 标记。测试过程中要养成每一步操作后都执行 status 确认状态的习惯。4.3 初始化测试数据在主节点上创建测试库和测试表。测试表需要能够覆盖自增主键、普通索引、唯一键、大字段和时间字段以便后续校验不同数据类型的同步一致性。CREATE DATABASE IF NOT EXISTS ha_test; USE ha_test; CREATE TABLE t_order ( id BIGINT NOT NULL AUTO_INCREMENT, order_no VARCHAR(64) NOT NULL, user_id BIGINT NOT NULL, amount DECIMAL(18,2) NOT NULL, status TINYINT NOT NULL DEFAULT 0, remark TEXT, create_time DATETIME(6) NOT NULL DEFAULT CURRENT_TIMESTAMP(6), PRIMARY KEY (id), UNIQUE KEY uk_order_no (order_no), KEY idx_user_id (user_id) ) ENGINEInnoDB DEFAULT CHARSETutf8mb4;测试表中 order_no 使用唯一键可用于检测切换过程中是否出现重复写入或事务重复执行。create_time 精确到微秒便于在故障注入点前后进行时间划线。测试数据可以使用存储过程批量生成也可以在持续写入脚本中动态生成。4.4 部署与配置 MySQL RouterMySQL Router 的配置推荐通过 bootstrap 命令完成它会自动从集群元数据中获取节点信息并生成与组复制联动的路由策略。mysqlrouter --bootstrap root192.168.56.11:3306 --usermysqlrouter --namehaRouterbootstrap 完成后会生成配置文件默认暴露 6446 端点用于读写6447 端点用于只读。启动 Router 后可以通过连接 6446 端口验证读写链路是否正常。mysql -h127.0.0.1 -P6446 -uroot -p -e SELECT hostname, port, super_read_only;在正常状态下通过 6446 连接会落在主节点上且 super_read_only 为 OFF通过 6447 连接会落在从节点上super_read_only 为 ON。这个验证是后续所有切换测试的基础只有在初始路由状态下确认无误后才能准确地观察切换过程。5. 测试工具与观测体系搭建5.1 持续写入探针的设计只有通过持续流量才能准确捕捉切换窗口。测试工具需要具备以下能力持续写入并记录每条插入的时间、耗时和错误持续读取并记录读取延迟与异常自动生成全局唯一的 order_no能够将原始测试数据落盘以便事后分析。下面给出一个简化的 Python 写入探针示例。它通过 Router 的 6446 端口连接循环插入数据并记录每次操作的结果。该探针同时开启自动重连与事务重试以模拟真实应用在切换期间的行为。import time import uuid import mysql.connector from mysql.connector import errorcode config { host: 192.168.56.21, port: 6446, user: app_user, password: AppPass123!, database: ha_test, autocommit: True, connection_timeout: 3, } def insert_one(cursor): order_no ORD- uuid.uuid4().hex[:16] sql ( INSERT INTO t_order(order_no, user_id, amount, status, remark) VALUES(%s, %s, %s, 0, probe) ) cursor.execute(sql, (order_no, 1001, 99.99)) while True: started time.time() try: conn mysql.connector.connect(**config) cursor conn.cursor() insert_one(cursor) duration (time.time() - started) * 1000 print(fOK {time.time():.3f} {duration:.2f}ms) except Exception as exc: duration (time.time() - started) * 1000 print(fERR {time.time():.3f} {duration:.2f}ms {exc}) finally: try: if cursor: cursor.close() if conn: conn.close() except Exception: pass time.sleep(0.1)在实际测试中建议将探针输出重定向到日志文件时间戳使用微秒级记录。测试结束后通过脚本统计错误次数、错误持续时间以及错误类型分布从而量化切换期间对业务的实际影响。5.2 只读探针与长连接观察只读探针连接 6447 端口持续执行 SELECT 查询并记录返回延迟。它用于验证从节点故障时 Router 是否会把只读流量重新路由到健康的从节点。只读探针的执行频率应比写入探针更高以便捕捉从节点退出时的短暂影响。除了短连接探针还需要建立一条长时间保持的连接观察主节点切换时已建立连接的行为。真实应用中很多连接池会复用长连接切换发生后旧主节点的连接会被强制断开应用必须捕获连接异常并重连。长连接测试能够验证应用重连逻辑是否健全。5.3 集群状态监控命令测试过程中需要持续监控集群状态。MySQL Shell 的 cluster.status() 提供了成员状态、角色和版本信息但频繁执行会占用连接资源因此建议结合 performance_schema 中的组复制表进行观察。SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members;该查询在任何成员节点上都能看到完整的成员状态列表。当节点故障后故障节点的 MEMBER_STATE 会从 ONLINE 变为 UNREACHABLE再由集群自动踢出。通过循环执行这条查询可以准确记录故障检测的时间点。还可以通过组复制统计表观察提交事务数量、消息传输情况等信息。例如查看各个节点的已应用事务 GTID 可以判断数据同步是否追平。SELECT hostname AS host_name, port AS port, RECEIVED_TRANSACTION_SET, GLOBAL.gtid_executed AS executed_set FROM performance_schema.replication_connection_status JOIN performance_schema.replication_group_members ON replication_connection_status.CHANNEL_NAME group_replication_applier ORDER BY hostname;测试中需要重点关注主节点故障后其余节点是否能够快速完成事务应用以及新主节点的 gtid_executed 是否覆盖了故障前已确认的全部事务。5.4 日志与时间戳的统一故障切换测试对时间精度要求很高建议所有节点开启 NTP 时间同步并在撰写测试记录时统一使用同一台跳板机的时间戳。如果能够在探针、Router 日志和 MySQL 错误日志中记录毫秒或微秒时间就可以在事后将多个数据源对齐还原故障发生的完整时间线。MySQL 错误日志建议开启 log_error_verbosity3以记录连接、系统状态等详细信息。Router 默认的日志级别为 INFO但在深入排查路由切换问题时可以临时调整为 DEBUG测试结束后再恢复避免产生过多日志。6. 计划内主从切换测试6.1 测试目的与场景说明计划内切换是指在集群健康状态下运维人员主动将主节点角色切换到另一个节点。典型场景包括主节点服务器需要升级内核、更换硬件、执行数据库补丁维护等。计划内切换应该稳定、可控、对业务影响最小并且不允许产生数据丢失。本测试要达成的目标包括验证 AdminAPI 的 setPrimaryInstance 切换流程是否平滑验证新旧主节点角色是否正确互换验证 Router 是否自动更新路由验证持续写入探针在切换期间的表现验证切换前后数据量没有丢失。6.2 执行计划内切换首先记录当前集群状态和测试表当前数据量然后启动持续写入探针。准备就绪后在 MySQL Shell 中执行角色切换命令将主节点切换到 ic-node-2。cluster.setPrimaryInstance(192.168.56.12:3306) cluster.status()setPrimaryInstance 会先确认目标节点具备成为主节点的条件然后在组复制层面执行优雅的主角色变更。执行期间旧主节点会停止接受写入新主节点在确认应用完旧主节点已提交事务后开始对外提供写入。命令执行成功后cluster.status() 应该显示 ic-node-2 成为新的 R/W 节点。此时可以继续在主节点执行写入验证新主节点已经可以正常写入。6.3 观察写入探针与 Router 行为在计划内切换场景下写入探针通常只会观察到短暂的成功率下降甚至可能完全没有错误。这是因为 Router 会提前感知集群角色变化并将新的写入请求快速路由到新主节点。已建立的旧连接会被断开但如果应用重连及时几乎不会出现业务感知。通过只读探针可以观察到 6447 端点的连接也会经历一次短暂的路由更新。切换完成后原主节点变为只读节点Router 会将其纳入只读路由池。需要特别关注的是切换瞬间是否有事务在旧主节点提交成功但未同步到新主节点。由于计划内切换前会执行事务排空正常情况下不会出现这种情况但测试仍应通过 GTID 对比进行确认。对比切换前后主节点的 gtid_executed 集合确保新主的已执行事务完全覆盖旧主切换前已确认提交的事务。6.4 数据校验与结论切换完成后停止写入探针并统计切换前后的数据行数。可以使用以下 SQL 对比各节点数据量。SELECT COUNT(*) AS total_rows, COUNT(DISTINCT order_no) AS distinct_orders, MAX(id) AS max_id, MAX(create_time) AS last_insert_time FROM ha_test.t_order;三个节点上查询结果应完全一致。同时检查 error log 中是否有复制错误或组通信告警。计划内切换的标准结论是切换过程控制在数秒内应用写入不中断或仅出现个位数毫秒级错误数据零丢失所有节点最终回到 ONLINE 状态。7. 主节点宕机与自动故障切换测试7.1 残酷的故障注入直接杀进程与计划内切换不同主节点宕机测试模拟的是没有任何预告的硬件失效或进程崩溃。故障注入方式应尽量贴近真实场景建议直接 kill -9 主节点的 mysqld 进程而不是执行正常的 SHUTDOWN。正常关闭属于优雅退出无法暴露自动故障检测和切换的真实表现。kill -9 $(pgrep -f mysqld | head -n 1)在执行故障注入前需要同步启动写入探针和只读探针并确保记录开始时间。同时在另外两个节点上高频查询 performance_schema.replication_group_members以便准确记录节点状态从 ONLINE 变为 UNREACHABLE 再到被踢出的时间点。7.2 组复制故障检测过程主节点被 kill 后其余节点不会立即感知故障。组复制通过节点间的心跳探测判断成员是否仍然存活。在默认配置下主节点疑似失效后集群会进入一个短暂的怀疑期等待更多证据确认故障。这个过程的目标是避免因为瞬时网络抖动而误判。当多数派成员确认主节点失联后集群会启动重新配置流程将失效节点从成员列表中移除。随后在剩余成员中根据权重和成员排序选出新的主节点。新主节点在被提升前必须确认已经应用了旧主节点最后一次多数派确认的事务。在测试中可以观察到一个典型现象故障发生后的前几秒内写入探针开始报错随后组复制完成重配置新主节点产生Router 更新路由写入探针重新恢复成功。整个过程中写入不可用窗口通常为几秒到十几秒具体取决于组复制成员超时参数和 Router 的检测周期。7.3 Router 路由切换行为验证主节点切换完成后Router 不会立即把写入流量导向新主节点。Router 通过周期性查询集群元数据来感知主节点变化这个周期由配置参数决定。在新主节点产生到 Router 完成路由表刷新的这段时间里写入探针可能仍然指向旧的主节点地址从而出现连接拒绝或连接超时。验证 Router 行为的方法是观察其日志。切换成功后日志中会记录路由刷新事件通过时间戳可以精确计算 Router 感知延迟。对业务来说这个延迟与组复制选举延迟叠加构成完整的写入不可用窗口。如果业务对切换时间要求极高可以考虑调小 Router 的元数据刷新周期但也要权衡其对配置中心的查询压力。默认配置在大多数场景下已经能够在十余秒内完成整体切换。7.4 宕机切换后的数据一致性验证等写入探针恢复稳定后对比新主节点与存活从节点的数据。需要重点检查 max(create_time) 与写入探针日志中的最后成功时间是否一致。如果故障前最后一批事务已经获得多数派确认那么这些事务在切换后必须存在如果某些事务仅写入旧主节点本地但尚未复制它们可能被回滚或无法恢复这正是组复制与半同步复制在行为上的区别。验证 SQL 如下在三节点都执行并比对结果。SELECT COUNT(*) AS total_rows, MAX(id) AS max_id, MAX(create_time) AS max_time FROM ha_test.t_order;多数派节点应完全一致。如果发现新主节点比从节点多出部分本地事务需要结合探针日志确认这些事务在故障前是否已向客户端返回成功。若未返回成功则可认为这些事务不满足业务一致性承诺。7.5 恢复故障节点与回切将宕机节点的 mysqld 重新启动。节点启动后会发现自己已不在集群成员列表中此时需要将其重新加入集群。可以使用 MySQL Shell 的 rejoinInstance 命令。cluster.rejoinInstance(root192.168.56.11:3306) cluster.status()rejoinInstance 优先尝试增量同步。若节点落后不多几秒内即可追平并恢复 ONLINE若落后过多或存在无法修复的差异则需要使用 clone 方式重新克隆。重新加入后ic-node-1 会以 SECONDARY 角色回到集群当前主节点保持在 ic-node-2。是否回切需要根据业务策略决定。如果希望恢复原始主从结构可以再次执行 setPrimaryInstance 进行计划内切换。需要强调的是主节点宕机恢复后不建议默认自动回切以免引入不必要的第二次切换风险。8. 网络分区与脑裂防护测试8.1 分区场景构造网络分区是最复杂也最具迷惑性的故障类型。节点进程都存活但网络被隔离导致节点之间无法通信。这种场景下最容易出现脑裂必须验证组复制的多数派机制是否能够阻止双主同时写入。可以使用 iptables 或 firewall-cmd 构造分区。假设将 ic-node-1 与另外两个节点的组通信端口 33061 全部阻断形成「1 节点与 2 节点」的分区拓扑。注意不仅要阻断组通信端口还要阻断 MySQL 数据端口 3306否则应用通过直连 IP 仍然可能往少数派节点写入测试数据。iptables -A INPUT -p tcp --dport 33061 -s 192.168.56.12 -j DROP iptables -A INPUT -p tcp --dport 33061 -s 192.168.56.13 -j DROP iptables -A OUTPUT -p tcp --dport 33061 -d 192.168.56.12 -j DROP iptables -A OUTPUT -p tcp --dport 33061 -d 192.168.56.13 -j DROP分区注入后观察三个节点的 behavior。多数派一侧即 ic-node-2 与 ic-node-3 仍能互相通信会继续选出主节点并对外服务少数派一侧即 ic-node-1 无法与集群通信若它原本是主节点则会在超时后自动降级并进入不可写状态。8.2 少数派节点的表现与脑裂防护验证在分区期间少数派节点即使进程存活也不允许继续接收写入。它会在错误日志中记录无法达成多数派的错误同时设置 super_read_only。可以通过直接连接少数派节点执行写入来验证这一点。SET GLOBAL super_read_onlyOFF; INSERT INTO ha_test.t_order(order_no, user_id, amount) VALUES(ORD-PARTITION, 2001, 1.00);上述 INSERT 应失败并返回类似 ERROR 3100 的组复制错误提示节点不属于多数派成员。即使尝试关闭 super_read_only组复制也会拒绝写入。这正是脑裂防护的核心结果。需要特别提醒的是不能尝试手工在少数派节点关闭组复制后继续写入。一旦少数派节点在分区期间写入本地数据恢复通信后该节点会因为 GTID 分叉而无法重新加入集群必须通过 clone 恢复。8.3 分区恢复后的自动合并验证清除 iptables 规则后网络恢复。少数派节点会自动重新与集群建立连接并在不需要人工干预的情况下恢复到 ONLINE 状态。通过 performance_schema.replication_group_members 可以观察到该节点短时间内进入 RECOVERING再变为 ONLINE。恢复完成后再从三个节点分别查询数据量结果应一致。整个过程应能在较短时间内自动完成当多数派节点在分区期间持续写入时少数派节点恢复通信后需要先通过增量同步补齐这些已确认事务再重新进入 ONLINE 状态。验证完成后应确认所有节点重新回到同一成员列表且不存在残留的错误分组或双主迹象。9. 从节点故障与成员主动退出测试9.1 从节点故障场景与预期从节点故障不会引发主节点选举因此对写入链路的影响通常远小于主节点宕机。测试重点转向只读流量的路由收敛、主节点写入的稳定性以及故障节点恢复后的数据补齐能力。预期结果是主节点持续正常写入只读路由在故障后短暂报错或延迟升高随后 Router 将只读流量从故障节点摘除重启并重新加入后该节点通过增量同步追上数据。9.2 从节点宕机对业务的影响以 ic-node-3 为对象注入故障使用与主节点测试相同的严格 kill 方式。执行前同样启动写入探针和只读探针并记录时间。kill -9 $(ssh 192.168.56.13 pgrep -f mysqld | head -n 1)故障注入后写入探针应保持零错误或仅出现个位数异常因为主节点和写入路由未发生变化。只读探针可能在短时间内出现连接失败随后 Router 会将该节点移出只读候选列表将只读请求路由到剩余健康从节点。监控时仍以 performance_schema.replication_group_members 为主重点关注故障节点的 MEMBER_STATE 变化。主节点上可执行以下 SQL 查看成员状态SELECT MEMBER_HOST, MEMBER_PORT, MEMBER_STATE, MEMBER_ROLE FROM performance_schema.replication_group_members ORDER BY MEMBER_HOST;9.3 成员主动退出与重新加入计划性维护常常需要让某个节点暂时退出集群。可以通过 MySQL Shell 的 removeInstance 将节点移出或使用 offlineInstance 暂时下线但保留组复制配置。下面演示将 ic-node-3 主动退出后重新加入的流程。cluster dba.getCluster() cluster.removeInstance(root192.168.56.13:3306) cluster.status()removeInstance 会从集群元数据和组复制成员列表中移除该节点期间主节点和其他从节点继续提供服务。维护完成后再通过 addInstance 将该节点重新加入。cluster.addInstance(root192.168.56.13:3306, {localAddress: 192.168.56.13:33061}) cluster.status()重新加入时MySQL Shell 会优先选择增量恢复若节点已退出较久或 binlog 缺口过大则会自动使用 clone 补齐数据。测试时建议分别验证短时间退出和较长时间退出两种情形以确认恢复策略能够正确选择。9.4 数据补齐与校验节点恢复 ONLINE 后在该节点与主节点分别执行数据校验 SQL对比行数、最大 id 和最大 create_time。SELECT COUNT(*) AS total_rows, MAX(id) AS max_id, MAX(create_time) AS max_time FROM ha_test.t_order;结果应与主节点一致。若存在短暂不一致通常是因为增量同步尚在追赶状态等待其进入 ONLINE 后再校验即可。还需观察从节点错误日志中是否存在 apply 错误确保恢复后没有复制中断残留。10. 总结与可复用的高可用测试清单10.1 各场景切换指标汇总将前文测试数据汇总到一张表中可以更直观地对比不同故障的影响范围和恢复表现。以下表格中的数值为典型环境的参考区间实际结果会随组复制超时参数、Router 刷新周期、事务大小和机器性能而变化。测试场景写入影响只读影响恢复方式数据一致性计划内主从切换短暂或无影响短暂路由更新自动完成零丢失主节点宕机数秒到十余秒不可写短暂不可用后恢复自动选举多数派事务一致网络分区少数派截断多数派可写视分区拓扑而定分区恢复后自动合并多数派一致从节点宕机基本无影响短暂路由收敛手动重启并 rejoin恢复后补齐成员主动退出无影响路由池自动调整手动 addInstance恢复后补齐10.2 生产落地前的关键建议一致性级别对一致性敏感的业务建议评估 BEFORE_ON_PRIMARY_FAILOVER并接受其性能开销对性能敏感的场景仍需保留 EVENTUAL但要有配套的读校验机制。客户端重试应用连接池必须开启自动重连与事务重试并设置合理的连接超时和读写超时才能充分利用 Router 的切换能力。Router 参数根据业务的 RTO 要求调整 Router 的元数据刷新周期同时监控配置中心查询压力避免过度调低周期。数量与拓扑生产环境至少保留三个数据节点组通信端口与数据端口网络必须稳定跨机房部署时要谨慎评估脑裂风险。定期演练高可用机制必须在预生产或生产维护窗口内反复演练及时验证参数变更、版本升级对切换时间的影响。10.3 可复用的高可用测试清单确认三个节点状态均为 ONLINE主节点可写从节点只读。部署并验证 Router 的 6446 与 6447 路由端点。建立持续写入探针、只读探针和长连接观察脚本。执行计划内主从切换记录应用影响与 GTID 对比结果。注入主节点宕机记录故障检测、选举、Router 刷新和写入恢复时间点。注入网络分区验证少数派不可写与分区恢复后的自动合并。注入从节点宕机验证只读路由收敛与数据补齐。验证成员主动退出与重新加入区分增量同步与 clone 恢复场景。汇总所有数据形成切换时间、数据一致性和恢复结果报告。完成以上项目后团队就拥有一套可重复执行、可线上对齐的高可用验证基线能够更早发现架构配置、网络策略和应用重连逻辑中的隐患。