MySQL 8.0 主从复制搭建与故障切换演练
主从复制是 MySQL 高可用的基础:主库承接写入,从库分担读流量并在主库故障时顶上去。本文以 GTID 复制为主线,完整走一遍 MySQL 8.0 的搭建、检查和切换流程,并把计划外切换时的风险点单独拎出来讲——切换本身不难,难的是切之前确认什么、切之后旧主怎么处理。
适用环境:MySQL 8.0.28 及以上,两台主机 db-01(192.0.2.21,主)与 db-02(192.0.2.22,从),操作系统为 Linux。文中口令均以占位符表示,实际使用请替换为强口令并通过安全通道下发。
前置条件
- 两台主机已安装同版本 MySQL,数据目录、端口(3306)规划一致;
- 主机间网络互通,防火墙放行 3306,时间已同步(chrony 或 ntpd);
- 主库为新建实例或已有数据但可短暂停写做全量导出;
- 两台主机的 server_id 全局唯一,且规划好后续扩容编号。
第一步:配置主库参数
在 db-01 的 /etc/my.cnf 的 [mysqld] 段加入以下参数后重启 MySQL:
[mysqld]
server_id = 101
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = mysql-bin
binlog_format = ROW
binlog_expire_logs_seconds = 604800
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
说明:GTID 模式开启后,每个事务有全局唯一编号,从库换源、切换后重新挂接都靠它自动定位,是 8.0 时代的默认选择,不要再用文件加位置的老方式。sync_binlog=1 与 innodb_flush_log_at_trx_commit=1 是数据安全的双保险,性能敏感场景放宽前先想清楚丢数据的代价。binlog 默认保留 7 天,磁盘紧张时缩短,但要覆盖最长的从库停机维护窗口。
第二步:创建复制账号
CREATE USER 'repl'@'192.0.2.%' IDENTIFIED WITH caching_sha2_password BY 'CHANGE_ME_STRONG';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.0.2.%';
FLUSH PRIVILEGES;
授权网段只写从库所在网段,不要图省事写 %。caching_sha2_password 是 8.0 默认认证插件,复制连接走它需要 TLS 或允许 RSA 公钥交换;图省事也可以对复制账号单独用 mysql_native_password,但更推荐给复制链路配置 SSL。
第三步:初始化从库并启动复制
从库 my.cnf 同样开启 GTID,server_id 设为 102,并建议加 read_only 与 super_read_only 防误写。有存量数据时,先在主库做一致性备份再导入从库:
# 主库导出(含 GTID 信息与源信息)
mysqldump -uroot -p --single-transaction --set-gtid-purged=ON \
--source-data=2 --all-databases > /backup/full.sql
# 从库导入后建立复制
mysql -uroot -p < /backup/full.sql
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='192.0.2.21',
SOURCE_PORT=3306,
SOURCE_USER='repl',
SOURCE_PASSWORD='CHANGE_ME_STRONG',
SOURCE_AUTO_POSITION=1,
GET_SOURCE_PUBLIC_KEY=1;
START REPLICA;
SOURCE_AUTO_POSITION=1 表示按 GTID 自动找同步点,这是 GTID 模式下最关键的一行;漏了它或从库导入的备份不含 GTID 集合,复制会直接报错。新库无数据时可跳过导出导入,直接 CHANGE 后启动即可全量拉取(仅适合数据量小的场景)。
第四步:读懂复制状态
SHOW REPLICA STATUS\G
重点看这几个字段:
- Replica_IO_Running / Replica_SQL_Running:都应为 Yes,一个拉日志、一个回放日志,任一为 No 先看同段的 Last_IO_Error / Last_SQL_Error。
- Seconds_Behind_Source:延迟秒数。只能作参考:IO 线程断开时它会显示 NULL,大事务回放时数值会跳变,不能单独作为告警依据。
- Retrieved_Gtid_Set / Executed_Gtid_Set:已接收与已执行的 GTID 集合,两者差集就是还没回放的事务,这才是判断追平的硬指标。
- Auto_Position:应为 1,确认走的是 GTID 自动定位。
延迟监控建议双管齐下:一是定期比对主从 Executed_Gtid_Set 的差距,二是在主库写心跳表(每秒更新一行带时间戳的记录),从库读出时间差即为真实延迟,比 Seconds_Behind_Source 稳定。业务侧的延迟容忍度要在切换标准里写死,例如「延迟超过 30 秒的从库不参与故障切换」。
第五步:计划内切换的标准动作
计划内切换(维护、升级)按以下顺序执行,前后约几分钟:
- 通知业务方进入维护窗口,应用侧先停写或切到只读;
- 在主库执行 FLUSH TABLES WITH READ LOCK 或直接停止应用写入,确认 binlog 不再增长;
- 在从库反复查 Executed_Gtid_Set,直到与主库的 gtid_executed 完全一致,即确认追平;
- 从库执行 STOP REPLICA,并 RESET REPLICA ALL 清除旧复制关系,随后 SET GLOBAL read_only=OFF、super_read_only=OFF 提升为可写;
- 原主库改为指向新主库的从库:CHANGE REPLICATION SOURCE TO ... SOURCE_HOST='192.0.2.22' ... 后 START REPLICA,并设为只读;
- 应用连接指向新主库(改 VIP 漂移、DNS 或连接串,见第七步),恢复写入;
- 观察 10–15 分钟:错误日志、复制状态、业务关键接口成功率。
第六步:计划外故障切换的风险
主库宕机时的切换与计划内完全不同,核心风险是数据不一致,动作顺序要反着来,先确认再提升:
- 先确认主库真的不可用:区分进程崩溃、主机宕机与网络分区。网络分区下原主库可能还在接写入,冒然提升从库会造成双写脑裂,两边数据无法自动合并。
- 比对多个从库再选新主:有多个从库时,选 Executed_Gtid_Set 最全的那台提升;其余从库切换后会自动按 GTID 补齐或丢弃多余事务,但提升的那台若不是数据最全的,已确认的事务可能丢失。
- 旧主处理:旧主修复后绝不能直接对外提供写服务。它上面可能有未同步到新主的事务,应先只读启动,导出差异数据与新主核对,业务确认后再决定是丢弃还是回补;确认完毕后将其作为从库重新挂到新主下(GTID 会自动处理冲突事务,多余的本地事务需用空事务跳过或重建该从库)。
- 全过程留痕:故障时间点、GTID 比对结果、提升命令、谁在什么时间执行的决策,都要记进故障单,复盘时这是唯一依据。
第七步:应用连接指向
切换做得再标准,应用还连着旧库就等于没切。三种常见做法:
- VIP 漂移:keepalived 管理一个虚拟 IP,切换时把 VIP 绑到新主。动作快、对应用透明,但要注意 ARP 缓存与长连接不会自动断开,连接池要配合连接有效性检测。
- DNS / 配置中心:改解析或配置项,简单但生效慢,适合计划内切换。
- 中间件:ProxySQL、MySQL Router 等按健康状态自动路由,是规模化后的正解,但引入了新的组件与故障域。
无论哪种,都要在切换脚本里把「旧主设为只读」做成强制步骤,防止应用因连接缓存继续往旧主写。
演练记录清单
- 演练日期、参与人、演练类型(计划内 / 模拟宕机);
- 切换前主从 GTID 集合与延迟基线;
- 每个步骤的执行时间、命令与结果截图或日志片段;
- 切换总时长、业务中断时长、数据比对结果(行数校验、抽样校验和);
- 发现的问题与配置修正项,指定责任人与完成期限;
- 回切验证结果:演练环境应完整走一遍切回流程。
验证
-- 主库写入测试
CREATE DATABASE IF NOT EXISTS drill;
CREATE TABLE drill.t (id INT PRIMARY KEY AUTO_INCREMENT, note VARCHAR(64));
INSERT INTO drill.t (note) VALUES ('replication-check');
-- 从库应能立即查到,且 SHOW REPLICA STATUS 两个线程均为 Yes
SELECT * FROM drill.t;
SHOW REPLICA STATUS\G
常见问题
- 报错 1236(binlog 被清理):从库要的 binlog 已在主库过期删除。先确认 binlog 过期时间设置是否过短;已发生时只能重做从库(重新全量备份导入),所以从库长时间停机前务必评估主库 binlog 保留期。
- 报错 1032 / 1062(回放找不到行或主键冲突):通常是从库被误写产生了脏数据,或主从数据本来就不一致。用 pt-table-checksum 校验、pt-table-sync 修复,根治办法是给从库开 super_read_only 并回收从库写权限。
- 延迟突然变大且不回落:先看是大事务(一次更新百万行)在单线程回放堵住,还是从库硬件瓶颈。8.0 可开启多线程回放(replica_parallel_workers)并配合 replica_preserve_commit_order 缓解,但业务侧拆分大事务才是根本。
- caching_sha2_password 导致复制连不上:报错含 "Authentication requires secure connection"。给 CHANGE 命令加 GET_SOURCE_PUBLIC_KEY=1,或为复制链路开启 REQUIRE SSL,二选一即可。
小结:GTID 让 MySQL 复制的搭建和重新挂接都简化了很多,但切换的纪律性没有变:计划内切换赢在顺序,计划外切换赢在确认。把演练做成每季度一次的固定动作,并留下清单记录,真出故障时才不会在凌晨三点临场发明流程。







