news 2026/10/23 7:07:58

MySQL 8.0.35 主从复制SOP:从参数选型到故障处置全流程指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL 8.0.35 主从复制SOP:从参数选型到故障处置全流程指南

MySQL 8.0.35 主从复制搭建(SOP)——如果你在一个维护着十几套数据库的团队待过,就会明白“标准化作业程序”这几个字的含金量。主从复制本身不难搭,难的是每次都搭得一模一样、参数有据可查、出了问题能按文档一步步回溯。这篇文件就是我在 CentOS 7 环境里把 MySQL 8.0.35 从零拉到主从可用的完整过程,按 SOP 格式整理:每一步都有执行命令、参数含义、验证方式,以及我踩过之后不想让你再踩一遍的坑。适合正要搭主从的 DBA、运维,也适合自己折腾服务器、想给业务加一层读能力的后端同学参考。

1. 为什么主从复制必须做成 SOP

1.1 一次“搭完就忘”的教训

我最早接触主从复制是五年前,那时候搭完主从、show slave status 看到两个 Yes 就算完工,命令是东抄一条西抄一段,参数也是谁顺眼用谁。结果三个月后从库磁盘被 relay log 撑爆,我翻历史记录才发现当初根本没设置 relay_log_purge,甚至不知道从库的 server-id 跟另一套测试环境撞了号。那次之后我学乖了:凡是重复性高、涉及多台机器的操作,一律写成 SOP。主从复制恰恰是最典型的场景——主库一台、从库一台、可能还要加只读副本,每台都要执行几乎相同的操作,任何一步遗漏都会在后续运行中暴雷。

1.2 一份合格 SOP 应该覆盖什么

按我的定义,SOP 不是简单把命令抄一遍,而是要把“为什么这么做”也写进去。具体到主从复制,至少得包含五个部分:环境巡检、参数选型、主库配置、从库配置、验证与排错。环境巡检解决“这台机器能不能搭”的问题,参数选型解决“用位点还是 GTID、ROW 还是 STATEMENT”的问题,配置阶段是最机械的部分,反而最不需要动脑。真正的分水岭在验证与排错:只有把常见的 1062、1872、1236 错误处理流程也写进去,这份 SOP 才算闭环。

1.3 主从复制的边界:它能做什么,不能做什么

很多刚接触的同学容易把主从复制当成万能药——既能高可用,又能备份,还能缓解写压力。这里我必须泼一盆冷水:传统主从复制默认是异步的,它在“主库崩溃但数据还没传到从库”这个时间窗口里会丢数据,所以它不是高可用方案,更不是备份方案。它真正擅长的是两件事:一是把读流量从主库剥离出去,比如报表查询、数据分析、备份任务都打到从库;二是在主库需要维护时,提供一个数据基本一致的冷备节点。理解了这条边界,你再看后面的参数选型,思路会清晰很多。

2. 搭之前的环境巡检与版本决策

2.1 CentOS 7 上安装 MySQL 8.0.35 的三种方式

CentOS 7 自带的软件源里默认没有 MySQL 8.0,最多只有 MariaDB 5.5,所以第一步就得解决安装源的问题。我实际用过的有三种方式,按推荐程度排:

  1. 官方 Yum 源安装:下载 mysql80-community-release-el7 的 rpm 包装上,然后 yum install mysql-community-server。优点是省事、方便用 systemctl 管理,缺点是官方源在国内某些网络环境下很慢,而且它默认启用 8.0 系列的最新小版本,想锁定 8.0.35 需要额外配置。

  2. 二进制 tar 包安装:下载 mysql-8.0.35-linux-glibc2.12-x86_64.tar.xz,解压到 /usr/local/mysql,然后手动初始化。这种方式锁定版本最精确,不依赖网络源,适合内网环境,也是我在这份 SOP 里最推荐的方式。

  3. Docker 容器:虽然简单,但生产环境如果坚持用物理机或虚拟机部署数据库,容器化反而引入一层不必要的复杂度,这里不展开。

用 tar 包安装时有一个高频坑:MySQL 8.0 初始化的命令跟 5.7 完全不一样。5.7 可以用 mysql_install_db,8.0 必须用 mysqld --initialize 或者 mysqld --initialize-insecure,前者会在日志里生成随机临时密码,后者生成一个空密码的 root 账号。我习惯在测试环境用 --initialize-insecure,省去翻日志的麻烦,生产环境则老老实实用 --initialize 并第一时间改密码。

2.2 巡检清单:装完系统后先做这几件事

在动 MySQL 之前,我会花十分钟把系统层面检查一遍,这几项看似跟复制无关,但不出事则已,出事全是连环坑:

  • 时间同步:主从两台机器务必用 chronyd 做时间同步。复制本身不要求时钟一致,但 relay log 的落盘时间、错误日志的时间戳、以及后续排查延迟问题时,时间错乱会带来极大干扰。执行 timedatectl set-ntp true 基本能搞定。

  • server-id 唯一性:这是主从复制里最基础也最容易被忽略的约束。同一个复制拓扑里,所有实例的 server-id 必须不同,而且尽量不要用默认值 1。我的习惯是直接用 IP 最后一段换算成数字,比如 192.168.1.10 就是 110,这样一眼就能看出是哪台机器。

  • 防火墙和 SELinux:CentOS 7 默认 firewalld 是开着的,如果不放行 3306,主库那边配置得再完美,从库也连不上。测试环境直接 systemctl stop firewalld 最省事,生产环境建议 firewall-cmd --permanent --add-port=3306/tcp 精确放行。SELinux 同理,要么配置好策略,要么在确认安全的前提下 setenforce 0,最怕的是两个都开着、两边各有各的拦截,报错还看不出来。

  • 数据目录和日志目录的属主:用 tar 包装的话,/data/mysql、/var/log/mysql 这些目录必须先创建并 chown 给 mysql 用户,否则 mysqld --initialize 会直接报错。这一步写进任何一份 SOP 都不丢人,因为至少三分之一的新手都卡在这。

2.3 复制方式选型:GTID 还是传统位点

MySQL 8.0 里的 GTID 已经非常成熟,而且从 8.0.35 这个版本来看,官方对 GTID 的支持力度明显大于传统位点。GTID 的核心价值在于:每个事务都有一个全局唯一的 ID,从库不需要记录“我读到主库 binlog 的哪个文件哪个位置”,只要告诉主库“我执行到哪个 GTID 了”,主库就能自动把缺的事务推送过来。这对切换和故障恢复是革命性的简化。相比之下,传统位点方式要求你手动记录 File 和 Position,一旦主从切换、或者从库落后太多导致 binlog 被清理,恢复过程极其痛苦。

所以在这份 SOP 里,我直接采用 GTID 模式,从库用 MASTER_AUTO_POSITION=1 自动定位。如果你的环境里有 MySQL 5.6 或 5.7 的存量实例想要混搭,那就要考虑 GTID 兼容性,但今天我们讨论的是 8.0.35 全新搭建,没有任何理由不用 GTID。

3. 主库配置:开启 binlog 与创建复制账号

3.1 my.cnf 关键参数逐项说明

主库的配置文件是整个复制链路的起点,binlog 没开、或者格式不对,后面全白搭。我用的是下面这一组参数,每一行都值得你理解它为什么存在:

[mysqld] server-id=110 log-bin=mysql-bin binlog_format=ROW gtid_mode=ON enforce_gtid_consistency=ON binlog_expire_logs_seconds=604800 max_binlog_size=256M skip_name_resolve=ON

server-id 前面说过,保证全局唯一。log-bin 开启二进制日志,文件名前缀可以自定义,我用默认的 mysql-bin。

binlog_format=ROW 是我特别想强调的一项。MySQL 的 binlog 有三种格式:STATEMENT、ROW、MIXED。STATEMENT 记录的是 SQL 语句本身,日志量小,但对非确定性函数(比如 UUID()、NOW())在主从执行结果不一致时容易出问题;ROW 记录的是每一行数据的变更前后值,日志量偏大,但执行结果完全确定,不会因为主从数据环境细微差异导致复制错乱。主从复制这种场景,我坚决用 ROW,宁可磁盘多占一点,也要换一个“绝对能对上”的结果。

gtid_mode=ON 和 enforce_gtid_consistency=ON 是配套的,前者开启 GTID,后者强制要求所有事务都能被 GTID 唯一标识,否则会拒绝执行。这两个参数必须在主库从库都设置,而且不能只开一半。

binlog_expire_logs_seconds=604800 表示 binlog 保留 7 天,这是为了给从库留出足够的追平窗口。这里我要提醒一个常见误区:很多人习惯用 expire_logs_days,但 MySQL 8.0 中这个参数已经废弃,官方推荐用 binlog_expire_logs_seconds,单位是秒。如果你从老文档里抄了 expire_logs_days,8.0.35 会打 warning 但不会报错,容易造成“明明配置了却不生效”的错觉。

skip_name_resolve=ON 关闭域名解析,强迫所有连接都用 IP 直连,避免因 DNS 抖动导致复制连接时断时续。但这个参数开了之后,复制账号的授权也必须用 IP,不能用域名,后面我会提到。

3.2 创建复制专用账号

主库配置好之后,重启 MySQL 让参数生效,然后创建复制账号。理论上复制账号可以复用 root,但生产环境千万别这么干。我习惯创建一个权限最小、名字一看就知道用途的账号:

CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY 'YourStrongPassword'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES;

这里有三点值得展开。第一,MySQL 8.0 默认的认证插件是 caching_sha2_password,不是老版本的 mysql_native_password。如果你从网上抄了老教程,里面往往会有 IDENTIFIED WITH mysql_native_password BY,在 8.0.35 里依然能跑,但这是被官方标记为废弃的插件。更稳妥的做法是直接用默认插件,然后确保从库连接时使用 SSL 或 RSA public key 来完成加密传输。不过内网环境很多同学嫌配置 SSL 麻烦,也可以暂时用 mysql_native_password 过渡,前提是你清楚它的安全边界。

第二,授权范围我写的是 '192.168.1.%',只允许内网网段连接。不要图省事写成 'repl'@'%',一旦密码泄露等于把复制权限暴露给全网。

第三,REPLICATION SLAVE 是复制账号唯一需要的权限,不需要 SELECT、不需要 ALL,多一个权限都是攻击面。

3.3 主库数据初始化:从零开始还是从存量开始

如果你是从零搭建,主库上还没有业务数据,那这一步可以直接跳过。但绝大多数场景是主库已经跑了一段时间、有存量数据,需要在从库上把数据先追平,再启动复制。

我用的备份命令是:

mysqldump -uroot -p \ --single-transaction \ --master-data=2 \ --set-gtid-purged=ON \ --all-databases > /backup/full_backup.sql

--single-transaction 是 InnoDB 下做一致性快照的关键,不加它,备份过程中数据在变化,恢复出来的库跟主库对不上。--master-data=2 会在 dump 文件头部注释掉 CHANGE MASTER 语句,方便你恢复后手动指定主库信息。--set-gtid-purged=ON 会把当前主库已执行的 GTID 集合写进 dump 文件,这样从库恢复后就知道自己已经执行到哪个位置,启动复制时不会重复执行旧事务。

大表特别多的情况下,mysqldump 会很慢,可以考虑用 Percona XtraBackup 做物理备份,速度更快,但恢复流程也复杂不少。SOP 里我默认先用 mysqldump,够用且最容易理解,等到单表超过 50GB 再切换物理备份方案。

4. 从库配置与复制链路建立

4.1 从库 my.cnf:相对主库多了哪些考量

从库的 my.cnf 跟主库有相似之处,也有一些专属配置。我用的配置如下:

[mysqld] server-id=120 log-bin=mysql-bin binlog_format=ROW gtid_mode=ON enforce_gtid_consistency=ON relay_log=mysql-relay-bin relay_log_purge=ON read_only=ON super_read_only=ON

几点说明:

从库也开 log-bin,很多人不理解。其实从库开启 binlog 有两个理由:一是从库未来可能成为新主库,比如主从切换场景;二是便于在从库上继续搭建级联复制。备份任务如果打到从库上,也需要 binlog 配合。

relay_log=mysql-relay-bin 指定中继日志文件名前缀。relay_log_purge=ON 表示中继日志在执行完后自动清理,这个默认就是 ON,但正因为是默认值,很多人不看,结果中继日志撑爆磁盘的事件几乎每个月都能在论坛刷到。这里我建议在配置文件里显式写出来,既是一种 SOP 的态度,也让后来的人一眼能看到这个参数是被考虑过的。

read_only=ON 和 super_read_only=ON 会让从库拒绝所有非超级用户的写操作,这是防止有人手滑把数据写到从库的关键防线。super_read_only 比 read_only 更严格,连超级用户也拦,正式环境建议一起开。

4.2 把备份恢复到从库

从库安装完成后,正式启动复制前要先恢复主库的备份:

mysql -uroot -p < /backup/full_backup.sql

恢复过程中如果遇到 max_allowed_packet 不够的错误,比如某条大字段插入超过包大小限制,要在 my.cnf 里临时调大:

max_allowed_packet=256M

这个错我在第一次搭复制时遇到过,dump 文件里只要有一张表带大字段(比如 TEXT/BLOB),默认的 4M 包大小很容易爆掉。别急着改完又来一次,建议直接先把参数加上再恢复。

4.3 CHANGE MASTER TO 完整语句解析

数据恢复完成,接下来就是把从库指向主库。MySQL 8.0.35 这一代有一个明显的语法演进:8.0.23 之前,大家都写 MASTER_HOST、MASTER_USER;8.0.23 及之后,官方引入了新的 “SOURCE” 词汇体系。新语法是:

CHANGE REPLICATION SOURCE TO SOURCE_HOST='192.168.1.10', SOURCE_USER='repl', SOURCE_PASSWORD='YourStrongPassword', SOURCE_PORT=3306, SOURCE_AUTO_POSITION=1, SOURCE_CONNECT_RETRY=10;

如果你手头的老教程写的是 CHANGE MASTER TO MASTER_HOST=...,在 8.0.35 里也能执行,但会提示这个语法已废弃。我建议新环境一律用新语法,至少风格上跟官方文档保持一致。

SOURCE_AUTO_POSITION=1 是 GTID 复制的关键开关。打开后,从库不会去指定“从哪个 binlog 文件的哪个位置开始”,而是基于自己已经执行的 GTID 集合,自动向主库请求缺失的事务。这比传统位点方式省心太多,也基本杜绝了“位置记错导致重复执行或漏执行”的问题。

SOURCE_CONNECT_RETRY=10 表示网络抖动导致连接断开时,每 10 秒重连一次,这是默认值,但显式写出来有助于后来的人理解复制链路是有自愈机制的。

4.4 启动复制并验证两个关键线程

执行完 CHANGE 语句后,启动复制:

START REPLICA;

注意,8.0.22 之前的版本写的是 START SLAVE,这个旧关键字在 8.0.35 中依然兼容可用,但新写法是 START REPLICA。SOP 里我统一用新写法,遇到老版本 MySQL 再对应翻译。

启动后验证状态的命令:

SHOW REPLICA STATUS\G

重点看以下几行:

  • Replica_IO_Running: Yes — IO 线程负责从主库拉取 binlog 到本地 relay log。
  • Replica_SQL_Running: Yes — SQL 线程负责把 relay log 中的事务在从库上重放。
  • Seconds_Behind_Master: 0 — 表示从库跟主库基本同步。

如果 IO 线程不是 Yes,大概率是网络不通或者账号权限问题。如果 SQL 线程不是 Yes,说明数据恢复有问题或者主从数据不一致。这两个线程的状态理解,我认为是判断主从健康度的基本功。

这里补充一个容易踩的坑:当你看到 Seconds_Behind_Master 是 NULL 而不是数字时,不代表从库没有延迟,而是复制线程有一边没在运行,或者尚未建立连接。很多人看到 NULL 以为“没有延迟”,实际上可能是复制已经断了。

5. 复制链路日常体检与高频故障处理

5.1 每天该盯的几个指标

主从复制搭好不是终点,日常监控才是。我常用的体检命令分三层:

第一层,看复制线程状态:

SHOW REPLICA STATUS\G

第二层,看复制通道在性能表里的统计,这也是 8.0 更推荐的姿势:

SELECT * FROM performance_schema.replication_connection_status\G SELECT * FROM performance_schema.replication_applier_status\G

第三层,关注从库的磁盘剩余空间。relay log 即使开了自动清理,在从库延迟较大时依然可能临时占用大量磁盘,所以我习惯在监控脚本里加一条磁盘阈值告警。

5.2 三个高频报错的完整处理链路

我把自己在实际维护中遇到过且比较有代表性的三个错误写下来,都是可以复现的排错路径。

错误一:1062 主键冲突。SQL 线程在从库重放时,插入一条记录发现主键已经存在。常见原因是有人手动往从库写了数据,或者从库不是从备份恢复而是半路接入,导致数据不一致。我的处理思路是:先 STOP REPLICA;然后 SET GLOBAL SQL_SLAVE_SKIP_COUNTER = 1;再 START REPLICA,跳过这一条错误事务。但注意,这只是止血,不是治本。跳过之后要用 pt-table-checksum 或业务层面确认主从数据一致性,否则后面可能连续冒出一堆 1062。

错误二:1872 Slave failed to initialize relay log info structure from the repository。这个报错通常出现在 relay log 的元数据损坏,或者从库之前发生过非正常关机。处理方式是:

STOP REPLICA; RESET REPLICA ALL; CHANGE REPLICATION SOURCE TO ...; START REPLICA;

RESET REPLICA ALL 会清掉复制相关的所有配置,需要重新执行 CHANGE 语句。别慌,按照 SOP 重来一遍就行。

错误三:1236 The slave is connecting using CHANGE MASTER TO MASTER_AUTO_POSITION = 1, but the master has purged binary logs containing the slave's GTIDs。这说明从库需要的 binlog 已经被主库清理了,常见于从库停机时间过长、主库 binlog 保留期太短。处理办法是:把备份保留期调长,或者对从库重新做一次全量恢复。这也是为什么我建议 binlog 至少保留 7 天,给运维留出足够的缓冲。

5.3 主库维护时的只读切换演练

虽然传统主从复制不承诺高可用,但它可以帮你完成“主库维护”这种计划内操作。我建议在测试环境至少演练一次手工切换,流程如下:

  1. 主库侧:确保所有事务已经提交,执行 FLUSH TABLES WITH READ LOCK 短暂锁表,然后记录当前 GTID 位置(其实 GTID 模式下不需要记位置)。
  2. 从库侧:等待 Seconds_Behind_Master 变成 0,确保从库已经追平主库。
  3. 从库侧:执行 STOP REPLICA,然后 SET GLOBAL read_only=OFF,把从库提升为可写的新主库。
  4. 业务侧:把应用连接指向新主库。
  5. 原主库:等维护完成后,可以把原主库反向配置为新主库的从库,形成角色互换。

这个流程里最容易出问题的就是第 3 步——忘记关 read_only 就启动写入,结果业务报错“read-only mode”。建议把这条命令写在切换脚本的醒目位置。

6. 从一套 SOP 到更高阶的复制体系

6.1 半同步复制:什么时候值得用

前面提到传统复制是异步的,主库提交事务后不等待从库确认就直接返回,存在数据丢失窗口。如果你的业务对数据丢失零容忍,可以考虑半同步复制机制。在 8.0.35 中启用方式如下:

INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so'; SET GLOBAL rpl_semi_sync_source_enabled = 1;

开启后,主库提交事务时会等待至少一个从库确认收到 binlog,才向客户端返回成功。好处是大幅缩小丢失窗口,代价是从库确认的延迟会直接影响主库写入性能。我的建议是:业务写压力不大、但数据敏感度极高的系统上可以用;写密集的高并发场景要谨慎评估。

6.2 这份 SOP 还有哪些可扩展的方向

模块化是另一个方向。比如把主从复制 SOP 拆成“安装 MySQL 8.0.35”和“配置主从复制”两个独立文档,前者的输出物是完整的 MySQL 实例,后者的输入依赖一个干净可用的实例。这样换一个版本、换一台服务器,只需要替换第一部分而不用动复制部分。我自己维护的文档体系就是这么拆的,版本变更时改动面小很多。

如果团队规模再大一些,可以考虑引入 MHA 或者 Orchestrator 这类工具,把第 5.3 节的手工切换自动化。但工具永远替代不了人对原理的理解,我始终建议先把手工流程跑熟,再考虑自动化,否则工具一旦出故障,你连手工兜底的能力都没有。

6.3 最后的一点个人体会

这套 SOP 前前后后帮我搭过不下二十套主从环境,也帮同事处理过好多次复制中断。我的体会是:主从复制最大的风险往往不是因为参数复杂,而是因为流程不统一——有人用位点、有人用 GTID,有人开 ROW、有人用默认 STATEMENT,东拼西凑最后谁都接不上茬。把 SOP 固定下来,照着执行,再配上第 5 节那些故障处理预案,这套东西才算真正立住了。如果你照着这份文档搭出了自己的主从环境,建议在测试环境刻意断一次网、停一次主库,体会一下从库是怎么重连和追平的——那种直观的理解,比看十遍文档都管用。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/19 13:32:49

ShardingSphere-JDBC水平分片实战:从原理到配置破解单库瓶颈

接手交易系统维护那阵子&#xff0c;最头疼的就是订单表。一千万行数据摆在那里&#xff0c;单库连接数天天报警&#xff0c;慢查询把夜里的大促压得喘不过气。后来用ShardingSphere-JDBC做了水平分片&#xff0c;才真正把单库压力拆开。ShardingSphere-JDBC是一个以JDBC驱动形…

作者头像 李华
网站建设 2026/10/19 15:43:32

MySQL字符串函数实战:从拼接截取到数据清洗的工程指南

这两年我接手的数据清洗和报表需求里&#xff0c;十个有七个都在跟字符串纠缠。要么是从旧系统导出来的字段带着一堆前后空格和换行&#xff0c;要么是手机号、身份证、订单号混在一个字段里需要拆开&#xff0c;要么是编码规则不统一导致排序结果怎么看怎么别扭。每次遇到这种…

作者头像 李华
网站建设 2026/10/19 15:43:31

增长停滞诊断框架:5步定位用户流失与激活问题

一位做增长的朋友跟我说过一句话&#xff1a;做产品最难受的时刻&#xff0c;不是没量&#xff0c;而是“不知道为什么不涨了”。数据上周还在涨&#xff0c;这周突然停下来&#xff0c;团队已经开始做实验&#xff0c;但每个人对原因的判断都不一样。你问产品&#xff0c;他说…

作者头像 李华
网站建设 2026/10/19 15:43:31

反向传播与梯度下降:大模型训练底层原理与工程实践

1. 从一次训练损失不降的排查说起很多人第一次接触大模型&#xff0c;注意力都被参数量、上下文长度、微调数据量这些"看得见"的东西吸引&#xff0c;反而把反向传播和梯度下降当成两个背下来的名词。我带过几个刚入行的同学&#xff0c;他们能说清楚Transformer的注…

作者头像 李华
网站建设 2026/10/19 15:43:32

基于GPT-6的企业级AI工作伙伴OpenWorkMate:RAG架构与权限控制实战

1. 从“只会聊天”到“真能干活”&#xff1a;企业AI工作伙伴到底缺了什么公司里那套AI助手&#xff0c;十有八九你都用过——问它“年假怎么算”&#xff0c;它给你背一遍员工手册&#xff1b;问它“上季度华东区退货率”&#xff0c;它开始一本正经地编数字。问题不在于模型不…

作者头像 李华
网站建设 2026/10/19 15:43:33

Windows 上安装配置 Claude Code 全流程:环境搭建、VSCode 集成与避坑指南

1. 为什么要在 Windows 上认真折腾 Claude Code如果你平时主力开发环境是 Windows&#xff0c;又恰好对命令行 AI 编程助手这类工具感兴趣&#xff0c;那 Claude Code 这个名字大概率已经在你视野里晃过好几轮了。它本质上是一个跑在终端里的 AI 编程代理&#xff0c;能直接读写…

作者头像 李华