登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  数据库 >  MySQL

MySQL GTID 主从切换的检查清单

来源:17golang原创

时间:2026-10-16 22:28:29 391浏览 收藏

MySQL 主库需要切换时,最容易漏掉的不是一条 SQL,而是三个状态没有同时对齐:候选节点到底执行到了哪些 GTID、旧主库是否还允许客户端写入、应用连接池是否已经离开旧地址。GTID 的价值是让副本按事务集合自动定位,但它不会替你完成角色保护和应用摘流。

官方文档:https://dev.mysql.com/doc/refman/8.4/en/

可以把切换拆成一张小清单:先对比候选节点的执行集合,再冻结旧主库写入;然后提升候选节点、用 SOURCE_AUTO_POSITION 让其它副本重新跟随,最后切换应用写入口并重建连接池。任何一项没有完成,都不要把切换当成结束。

先看候选节点有没有资格接管

我处理这类切换时,第一眼不会看“延迟几秒”,而是看候选节点的 GTID 执行集合。GTID 自动定位会让副本把自己已经接收或提交的事务集合发给源库,源库只发送缺少的事务;因此检查重点是候选节点是否已经覆盖业务要求,而不是记一个旧主库的 binlog 文件名和 position。

-- 切换前读取候选节点的 GTID 与只读状态,先保存结果再做角色变更。
SELECT @@GLOBAL.gtid_mode,
       @@GLOBAL.gtid_executed,
       @@GLOBAL.read_only,
       @@GLOBAL.super_read_only;

-- 查看复制线程和执行集合;\G 便于在运维终端逐项阅读。
SHOW REPLICA STATUS\G

如果候选节点仍有明显未应用事务,先不要提升。尤其要留意 Retrieved_Gtid_Set 与 Executed_Gtid_Set 的差别:前者表示收到的范围,后者才更接近已经执行的范围。候选节点可以暂时保持 read_only=ON 和 super_read_only=ON,复制线程仍可以应用来自源库的更新。

MySQL GTID 切换前旧主库、候选副本、执行集合与只读状态的静态关系说明图
图1:GTID 切换前状态说明图,查看执行集合与只读边界;这是静态结构图,不是运行截图。

先挡住旧主库的写入窗口

确认候选节点能接管后,下一步是让旧主库停止接受业务写入。只停应用入口还不够,旧节点上的人工连接、后台任务或遗留连接池仍可能写入。super_read_only 会禁止客户端更新,即便连接拥有 CONNECTION_ADMIN 或旧的 SUPER 权限;复制线程仍可在副本上应用复制更新。

-- 在旧主库执行:先停复制,再阻止客户端继续写入。
STOP REPLICA;
SET GLOBAL super_read_only = ON;
SET GLOBAL read_only = ON;

-- 再次读取变量,确认角色保护已经落地。
SELECT @@GLOBAL.read_only, @@GLOBAL.super_read_only;

这里的关键不是把变量改成 ON 就结束,而是确认应用没有继续向旧地址发写请求。切换窗口里如果旧主库仍能被业务连接写入,就可能出现两个节点各自产生新事务,后续即使 GTID 能识别事务,也不能替你解决业务分叉。

提升候选节点并重新挂接副本

候选节点成为新主库后,先解除它对客户端写入的限制。MySQL 文档说明,将 super_read_only 设为 ON 会同时打开 read_only;而关闭 read_only 时也会关闭 super_read_only。为了让检查记录更直观,可以把两个变量都显式写出。

-- 在新主库执行:关闭客户端只读保护,允许业务写入。
SET GLOBAL super_read_only = OFF;
SET GLOBAL read_only = OFF;

-- 在其它副本执行:改为从新主库按 GTID 自动定位。
STOP REPLICA;
CHANGE REPLICATION SOURCE TO
  SOURCE_HOST = 'new-primary.example',
  SOURCE_PORT = 3306,
  SOURCE_USER = 'repl_user',
  SOURCE_PASSWORD = 'replace-with-secret',
  SOURCE_AUTO_POSITION = 1;
START REPLICA;

SOURCE_AUTO_POSITION=1 的含义是让副本依据 GTID 集合找缺少的事务,不再填写旧源的 SOURCE_LOG_FILE 和 SOURCE_LOG_POS。示例中的主机、账号和密码只是占位符,真实环境应从受控配置注入,不能把明文凭据写进脚本仓库。

MySQL GTID 切换后新主库、SOURCE_AUTO_POSITION、副本通道与应用连接的静态拓扑说明图
图2:切换后拓扑关系说明图,展示新主库、复制通道和应用连接的边界;这是静态结构图,不是运行截图。

应用连接要和数据库角色一起切换

数据库角色已经变了,应用不一定马上知道。写连接如果仍指向旧主库,常见结果是连接超时、只读错误,或者旧节点曾短暂恢复后再次产生写入。更稳妥的做法是让应用只依赖一个可变的写入口,例如代理地址、服务发现记录或配置中心键;切换时更新入口,再让连接池主动失效并重建。

读连接可以继续指向副本池,但要给切换后的复制追平留出判断条件。不要仅凭 TCP 连接成功就认为拓扑完成,应同时看到副本线程在运行、执行集合能够继续增长、应用的新写请求确实进入新主库。

最后按四项复查

检查面切换后的期望仍异常时先看什么
GTID新主库继续产生事务,其它副本按 GTID 跟随Executed_Gtid_Set、是否存在已清理但仍需要的 GTID
只读新主库可写,其它副本保持 read_only 与 super_read_only变量值、遗留客户端、后台任务
复制副本 IO/SQL 线程运行且不再跟随旧源SHOW REPLICA STATUS 的 source、线程状态和错误
应用写入口指向新主库,连接池已重建服务发现、连接池缓存、旧地址残留

常见追问

有 GTID 还需要记录 binlog position 吗?

GTID 自动定位场景通常不需要依赖旧源的文件与位置,但切换记录仍应保存切换前后的 GTID 集合,便于解释候选节点是否追平以及排查缺失事务。

只设置 read_only 就够了吗?

如果需要阻止拥有高权限的客户端写入,通常还要启用 super_read_only。副本复制线程仍可应用复制更新,但人工连接和后台任务的行为要单独排查。

为什么数据库已切换,应用还是报错?

最常见原因是应用仍使用旧连接池或固定主机地址。切换数据库角色后,还要更新写入口并让连接池建立新连接,不能把数据库端的角色变更当作应用端的自动重连。

MySQL GTID 主从切换可以记成一句话:先确认执行集合,再封住旧写入;提升新主库后用自动定位重挂副本,最后让应用连接跟着新的写入口移动。把这四个现场检查点写进运行手册,切换时就不容易只完成“数据库命令”而漏掉真正影响业务的状态。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>