news 2026/9/14 9:06:40

MySQL主从复制与读写分离实战:从零搭建到故障切换

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
MySQL主从复制与读写分离实战:从零搭建到故障切换

很多做后端开发的朋友都有过这样的经历:单机 MySQL 跑到一定阶段,慢查询变多,备份任务一跑就锁表,业务高峰期主库 CPU 直接飙红。这时候网上搜一圈,满屏都是"主从复制 + 读写分离",感觉像是灵丹妙药。可真到自己动手搭的时候,才发现坑远比想象的多——配置参数一堆,从库数据不一致,主库宕机了不知道怎么办,中间件选型也纠结半天。

这篇博文不跟你讲虚的,直接把我自己从零搭建 MySQL 主从复制、再落地读写分离的完整过程梳理出来。会讲到复制到底是怎么工作的、binlog 和 relay log 的数据流、核心参数怎么配、GTID 和传统位点复制怎么选、读写分离用代码路由还是中间件、主从延迟怎么监控和规避、主库宕机后怎么切换,以及我实测踩过的那些坑。适合已经能熟练操作单机 MySQL、正准备往高可用架构迈一步的工程师,也适合准备面试被问到"主从复制原理"这类问题时想有个系统认知的同学。

1. 主从复制解决了什么问题,又带来了什么新麻烦

先说清楚一件事:主从复制不是万能的,它解决的是特定场景下的问题。你只有先搞清楚它能干什么、不能干什么,后面配置起来才不容易跑偏。

1.1 单机数据库的真实瓶颈

我见过太多团队,业务量还没起来的时候,单库单表跑得挺欢,直到某天出现下面三个信号才开始焦虑:

第一个信号是读压力压垮主库。一个典型业务,读请求和写请求的比例轻轻松松到 10:1 甚至更高。你想想看,用户刷首页、查订单、看商品详情,全都是读操作。这些请求全打到同一个 MySQL 实例上,CPU 和 IO 迟早扛不住。第二个信号是备份影响线上业务。用 mysqldump 做逻辑备份,或者用 XtraBackup 做物理备份,都会对源库产生额外的 IO 负载和锁竞争。凌晨两三点跑备份,业务低峰期还好;可一旦业务是 24 小时全球化的,备份和在线业务直接打架。第三个信号是单点故障。一台机器挂了,整个服务全挂,没有任何冗余。硬件故障、机房断电、运维误操作,任何一个都可能导致服务长时间不可用。

主从复制的核心思路很简单:一个主库负责写,多个从库负责读。写请求依然走主库,读请求分摊到从库。这样主库的压力骤减,备份也可以专门挑一个从库来跑,不影响主库业务,同时从库天然成为了数据的热备份。听起来很美好,对吧?但这个架构一旦引入,你就要接受它带来的一堆新问题。

1.2 复制架构引入后的额外成本

我能想到的最贴切类比是:单机数据库像一个干杂活的个体户,什么都能干,但能力有上限;主从架构就像一个团队,有领导有下属,能接更大的盘子,但团队管理本身就有成本。

第一个成本是数据一致性。主库写入了,从库还没来得及同步,读请求就可能读到旧数据。这个问题叫主从延迟,业务上必须容忍一定的数据滞后。你不能要求刚下单就能立刻在订单列表里看到,虽然大多数情况下这个延迟只有几十毫秒。

第二个成本是架构复杂度。原来连接一台数据库就行,现在要维护主库和从库两套环境,复制链路断了要排查,从库数据跟主库不一致要修复重做,主库挂了要把从库提升为主库……这些都是运维层面的额外负担。

第三个成本是脑裂风险。如果网络分区或者运维误操作,可能出现两个节点都认为自己是主库的情况,这时候两个节点都在写入,数据就会产生不可修复的分叉。这是主从架构里最危险的问题之一,容不得半点马虎。

搞清楚了这些,你才能理解后面每一步操作背后的动机。主从复制的配置本身不难,难的是把整个链路的细节都照顾到。

2. 复制机制核心拆解:binlog 与 relay log 的数据流转

配置 MySQL 主从之前,你得先明白 replication 到底做了什么事。这个机制不算复杂,但每个角色各司其职,环环相扣。

2.1 三个线程的接力赛

MySQL 主从复制本质上是三个线程的协作:

主库上的Binlog Dump Thread负责把主库的二进制日志(binlog)发送给从库。从库上的I/O Thread负责接收主库发来的 binlog,并写入到从库本地的中继日志(relay log)。从库上的SQL Thread负责读取 relay log 中的事件,并逐个在从库上重放执行。

用大白话说:主库是一个出版社,binlog 是它印好的报纸;从库的 I/O Thread 是快递员,把报纸从出版社搬回自己家的仓库(relay log);从库的 SQL Thread 是读者,把仓库里的报纸一份份拆开看(重放执行)。搬报纸和读报纸是两个独立的过程,这就意味着从库接收 binlog 的速度和重放 SQL 的速度是可以不一致的——这也是主从延迟产生的最底层机制。

MySQL 8.0 之后,实际上是把 SQL Thread 进一步拆成了 Coordinator(协调线程)和多个 Worker(工作线程),这就是多线程复制(MTS),目的是加快 relay log 的重放速度,从而降低主从延迟。这个机制我后面会专门讲。

2.2 binlog 的三种格式与选型

binlog 是复制的基础,它的记录格式直接决定了复制的正确性和效率。MySQL 支持三种格式:

  • STATEMENT:记录原始 SQL 语句。日志量小,但某些非确定性函数(如 NOW()、UUID())会导致主从数据不一致。
  • ROW:记录每行数据的变更前后镜像。最安全、最准确,但日志量会成倍增加。
  • MIXED:MySQL 自动判断,默认用 STATEMENT,遇到不安全语句自动切换为 ROW。算是一种折中。

我的建议是:直接上 ROW 格式。虽然日志会大一些,但 ROW 格式在数据一致性上最可靠。尤其是涉及 UPDATE 或 DELETE 影响多行数据时,STATEMENT 格式在从库重放可能因为索引选择不同而产生意外;而 ROW 格式是按主键或实际影响行来重放,几乎没有歧义。磁盘不值钱,数据错乱可是要命的。

2.3 复制方式的演进:位点复制 vs GTID 复制

理解了 binlog 之后,另一个关键概念是复制定位方式。

早期 MySQL 采用基于日志文件位点(File+Position)的复制。从库需要记录主库当前 binlog 的文件名和偏移量(position),复制链路从那个位点开始。这种方式配置比较繁琐,尤其是从库落后太多、或者换新从库时,要找到正确的位点非常麻烦,特别容易出错。

MySQL 5.6 引入了GTID(Global Transaction Identifier,全局事务标识符)复制。每个事务在提交时会被分配一个全局唯一的 ID,由UUID:序号组成。从库通过 GTID 就能知道哪些事务已经执行过、哪些还没执行,主从重连或者切换时,不需要再关心 binlog 文件名和位置。

如果你是从零开始搭建新环境,务必直接使用 GTID 复制。我后面演示的配置就是 GTID 方式。它不光配置简单,更重要的是在主从切换、故障恢复时比位点复制省心太多。

3. 从零搭建一主一从:基于 MySQL 8.0 的完整实操

现在进入正题。我用的是 MySQL 8.0 版本,操作系统是 CentOS 7/8 这类 Linux 环境。如果你用的是免安装版或者压缩版,配置文件的路径可能不太一样,但核心配置项是一样的,跟着改就行。

3.1 环境准备与基础配置

假设有两个节点:

  • 主库:192.168.1.101,端口 3306
  • 从库:192.168.1.102,端口 3306

两台机器都装了 MySQL 8.0,建议版本尽量一致。如果版本不一致,至少要保证从库版本不低于主库,否则可能出现 binlog 格式不兼容的问题。我在测试环境里就遇到过主库 8.0.36、从库 8.0.43 的情况,高版本从库复制低版本主库,工作正常;反过来低版本从库接收高版本主库的 binlog 就报错,当时排查了半天。

主库的my.cnf增加以下配置:

[mysqld] # 服务唯一标识,集群内必须唯一 server_id = 101 # 开启 binlog,命名前缀自定义 log_bin = mysql-bin # 使用行格式记录,保证数据一致性 binlog_format = ROW # binlog 保留天数,按磁盘容量调整 binlog_expire_logs_seconds = 604800 # 开启 GTID 模式 gtid_mode = ON enforce_gtid_consistency = ON # 作为主库,其他节点可以从本机复制

从库的my.cnf增加以下配置:

[mysqld] # 服务唯一标识,不能和主库相同 server_id = 102 # 开启 relay log,名字自己起 relay_log = mysql-relay-bin # 只读模式,防止应用误写从库 read_only = ON # 同样开启 GTID gtid_mode = ON enforce_gtid_consistency = ON

两个很容易忽略的细节需要特别说明一下:

第一,server_id绝对不能重复。我在跟别人一起排查问题时,遇到过两台机器server_id都配成 1 的情况,结果从库日志里一直报Slave I/O thread连接中断,主库那边也不断报错。这个参数不需要全局唯一,但同一个复制拓扑里必须每个节点不同,哪怕是多级复制链也同理。

第二,read_only不等于super_read_onlyread_only对普通用户生效,但对具有 SUPER 权限的用户不生效。DBA 日常维护还是要用超级账号写入的,所以如果想让从库绝对不能被任何客户端写入,加上super_read_only = ON更保险。不过要注意,复制线程本身不受这几个参数影响,从库的 SQL Thread 重放 relay log 时照样能写进数据。

配置文件改完,重启 MySQL:systemctl restart mysqld

3.2 在主库创建专用复制账号

复制链路需要一个账号去主库拉取 binlog。千万别图省事直接用 root,用最小权限账号是基本原则。这个账号在从库连接主库时用到:

CREATE USER 'repl'@'192.168.1.%' IDENTIFIED BY '强密码_请替换'; GRANT REPLICATION SLAVE ON *.* TO 'repl'@'192.168.1.%'; FLUSH PRIVILEGES;

这里只授予了REPLICATION SLAVE权限,这个权限只允许该账号请求 binlog dump,没有其他任何操作权限,安全风险可控。注意192.168.1.%这个网段限制,别偷懒写成%,把账号暴露在公网上是给自己埋雷。

3.3 初始化从库数据,避免直接复制数据目录

这是最容易踩坑的一步。很多新手直接拿主库的数据目录打个 tar 包丢到从库,然后配置复制开始。这不是不行,但前提是你必须保证打包数据那一刻和复制起始位点严格对应,否则从库应用 binlog 的时候会出现找不到行的错误。而且 8.0 版本的数据字典和 redo log 内部结构复杂,直接拷贝文件时如果有版本差异,基本必炸。

正确做法是使用mysqldump或者XtraBackup做一次一致性快照。从库还没启动复制前,先用工具把主库的数据导出来,导入从库,然后从快照对应的 binlog 位点开始复制。

mysqldump的操作步骤是:

在主库执行:

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

参数解释:

  • --single-transaction:使用 InnoDB 事务的快照进行一致性备份,不影响业务写入,也不需要锁表。这个参数只对 InnoDB 表有效,如果你的库里还有 MyISAM 表,那还是会在备份期间锁表的。
  • --master-data=2:在备份文件的头部注释里记录备份时刻的 binlog 位点信息,方便定位复制起点。
  • --set-gtid-purged=ON:GTID 模式下推荐开启,这样从库导入时就知道哪些事务已经在数据里了,复制启动后会自动从缺失的 GTID 开始执行。

然后把备份文件传到从库,导入:

mysql -uroot -p < backup.sql

用 XtraBackup 的方式稍微不同,它是物理备份,速度更快,适合大数据量场景。核心步骤大概是:

# 在主库执行全量备份 xtrabackup --backup --target-dir=/data/backup --host=127.0.0.1 --user=root --password=xxx # 做恢复准备 xtrabackup --prepare --target-dir=/data/backup # 把备份目录传到从库,替换从库数据目录 xtrabackup --copy-back --target-dir=/data/backup

无论哪种初始化方式,最后你都要从备份里找到对应的 GTID 位点。mysqldump--master-data=2会把位点信息写在 SQL 文件头部的注释里,类似这样:

-- CHANGE MASTER TO MASTER_LOG_FILE='mysql-bin.000003', MASTER_LOG_POS=154;

如果开了 GTID,还会看到SET @@GLOBAL.GTID_PURGED='uuid:1-100'这样的行。从库导入数据时 MySQL 会自动设置gtid_purged,所以在从库执行CHANGE MASTER TO时,不用再手动指定 binlog 文件名和位置了。

3.4 在从库配置复制链路

数据初始化好了,接下来在从库执行复制配置命令:

CHANGE MASTER TO MASTER_HOST='192.168.1.101', MASTER_PORT=3306, MASTER_USER='repl', MASTER_PASSWORD='强密码_请替换', MASTER_AUTO_POSITION=1;

注意MASTER_AUTO_POSITION=1,这就表示走 GTID 自动定位,不需要手动指定MASTER_LOG_FILEMASTER_LOG_POS。这个参数是 GTID 复制的精髓,你以后做从库提升、failover 切换时都会受益。

然后启动复制:

START SLAVE;

这里有个细节需要提醒:MySQL 8.0.22 之前的版本用的是START SLAVESHOW SLAVE STATUS;8.0.22 之后官方推荐用START REPLICASHOW REPLICA STATUS,并且SLAVE开头的命令被标记为 deprecated(虽然还能用)。为了长期兼容,建议你直接在 8.0 环境里用REPLICA系列的写法。

检查复制状态:

SHOW REPLICA STATUS\G

重点观察两列:

  • Replica_IO_Running: Yes:I/O 线程正常,说明已经在从主库拉取 binlog 并写入 relay log。
  • Replica_SQL_Running: Yes:SQL 线程正常,说明 relay log 里的语句正在被重放。

如果两边都是Yes,恭喜你,复制链路已经跑通了。Seconds_Behind_Source这一列会显示从库落后主库多少秒,刚启动时可能会有一个短暂的较大延迟,等追平后就会变成 0 或者一个很小的值。

为了验证复制真的生效,你可以在主库建一张测试表,插几行数据,然后到从库查一下:

-- 主库执行 CREATE DATABASE test_repl; USE test_repl; CREATE TABLE t_user (id INT PRIMARY KEY AUTO_INCREMENT, name VARCHAR(50)); INSERT INTO t_user (name) VALUES ('zhangsan'), ('lisi');

然后到从库:

USE test_repl; SELECT * FROM t_user;

能看到zhangsanlisi两行,说明整个链路完全打通了。千万不要跳过这一步,我见过太多人配置完不验证,过了两天发现数据根本没同步,原因是 binlog 没开或者网络不通,白白浪费时间。

4. 读写分离落地选型:应用层路由还是中间件

主从搭好了,下一步就是把读写请求分流了。这一节我把实际工程里用过的两条路线都讲清楚,你根据自己团队的情况选。

4.1 应用层路由:侵入业务代码的方案

最简单粗暴的读写分离方式,是在应用代码里维护主库和从库两套数据源。可以用 Spring 之类的框架配合动态数据源切换实现,核心逻辑是:写操作和事务操作走主库数据源,读操作走从库数据源。

我见过很多小型项目用这种方式,优点非常明显:不引入额外组件,架构简洁,排查问题直接看应用日志就行。缺点也很突出:读写分离逻辑和业务代码耦合在一起,每个需要走从库的查询都要显式指定或者靠 AOP 切面判断;一旦从库数量变化、或者某个从库挂了,应用层要感知并处理故障,代码量会迅速膨胀。

适合场景:团队规模小、没有专职 DBA、业务并发量还没到需要横向扩展从库的程度,过渡期用一用完全 OK。

4.2 数据库中间件:对业务透明的方案

当业务增长到一定规模,应用层路由的维护成本会逐渐失控,这时候就该上数据库中间件了。市面上主流的中间件我在下面表里列一下,方便你横向对比:

中间件协议兼容性读写分离支持分库分表治理能力备注
MyCatMySQL 协议支持支持一般老牌中间件,社区活跃度下降,新项目慎选
ShardingSphere-JDBC原生 JDBC 接入支持支持以 SDK 形态嵌入应用,代码侵入小,配置灵活
ShardingSphere-Proxy透明 MySQL 协议支持支持独立部署代理,对应用完全透明,适合多语言
ProxySQLMySQL 协议支持不支持轻量、性能好,专为读写分离和连接池优化

如果只在 MySQL 生态内做读写分离、不想过渡设计,ProxySQL 是我用得最顺手的一个。它的配置灵活,支持在线启停、查询路由规则、连接池管理,还能根据实例健康状态自动剔除故障节点。缺点是不支持分库分表,但这不是它该干的活。

ShardingSphere-Proxy 适合那种既要读写分离、又预见到未来要分库分表的团队。它可以让应用层始终连一个标准 MySQL 协议端口,后面集群怎么变对应用无感知。缺点是多了中间层,链路变长,对排障能力要求高。

4.3 我的选型建议

给一个直接的结论:

  • 如果你的业务库读写比小于 5:1,从库最多 2 个,团队也小,用应用层路由就够了,别为了架构而架构。
  • 如果读写比很高,从库要扩到 3 个以上,而且希望自动故障转移,直接上 ProxySQL,日后再觉得不够再上 ShardingSphere。
  • 如果你们明确未来会碰到单表数据量过大、需要水平拆分的点,那就一步到位用 ShardingSphere 的生态。

4.4 ProxySQL 读写分离配置速览

如果你选了 ProxySQL,最简单的配置方式是在 ProxySQL 里定义两个组:写组和读组。然后插入一条 query rule,把SELECT语句路由到读组,其余语句路由到写组。

-- 添加后端节点到 ProxySQL INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (10, '192.168.1.101', 3306); INSERT INTO mysql_servers (hostgroup_id, hostname, port) VALUES (20, '192.168.1.102', 3306); -- 配置读写组 INSERT INTO mysql_replication_hostgroups (writer_hostgroup, reader_hostgroup) VALUES (10, 20); -- 设置监控账号(ProxySQL 用它检查后端健康状态) UPDATE global_variables SET variable_value='monitor_user' WHERE variable_name='mysql-monitor_username'; UPDATE global_variables SET variable_value='监控密码' WHERE variable_name='mysql-monitor_password'; -- 路由规则:SELECT 默认走读组 INSERT INTO mysql_query_rules (rule_id, active, match_pattern, destination_hostgroup, apply) VALUES (1, 1, '^SELECT', 20, 1); -- 应用修改 LOAD MYSQL SERVERS TO RUNTIME; SAVE MYSQL SERVERS TO DISK; LOAD MYSQL QUERY RULES TO RUNTIME; SAVE MYSQL QUERY RULES TO DISK;

这里有很多细节可以深化。比如match_pattern用的是正则,一个简单的^SELECT会把SELECT ... FOR UPDATE也路由到读组,这是致命的——FOR UPDATE是加锁读,必须走主库。所以规则要写成^SELECT.*FOR UPDATE单独建一条规则并优先匹配,或者用 ProxySQL 的digest精确匹配。

另外,事务内的读也应该走主库,否则会出现"同一个事务里先写后读,读到的是旧值"这种尴尬。用 ProxySQL 的话,可以在连接层做判断,也可以在应用层把事务连接固定到写库。这些都是生产环境里真实会遇到的问题,配的时候别只图简单。

5. 主从延迟:成因、监控与规避手段

主从复制搭完,最大的敌人就是延迟。从库数据落后主库,读请求就会读到旧数据,轻则用户体验下降,重则业务逻辑出错。这一节我把延迟的成因和应对方法讲透。

5.1 为什么会有延迟

延迟的根源可以从两个维度理解:网络传输和 SQL 重放。

网络传输方面的延迟一般很小,除非主从机房跨地域带宽受限。真正的大头在 SQL 重放。主库是并发写入的,比如有 8 个连接同时执行 INSERT,8 个事务并行提交;而传统复制里从库只有单线程重放,就相当于一条流水线要处理 8 条流水线的活,自然就积压了。这就是 MySQL 5.6 之前从库延迟特别严重的根本原因。

MySQL 5.7 引入了基于库级别并行的多线程复制,MySQL 8.0 的 MTS(Multi-Threaded Slave)基于 Writeset 进一步优化,同一个事务组内没有冲突(没有改同一行)的事务可以并行重放,延迟问题得到了很大缓解。但 Writeset 有个前提:表必须有主键。没有主键的表,更新要全表扫描找目标行,从库性能直线下降,这是很多线上从库延迟飙升的隐形凶手。

5.2 延迟的监控方法

先泼一盆冷水:SHOW REPLICA STATUS里的Seconds_Behind_Source字段并不是一个完全可信的指标。它是靠从库当前执行时间和 I/O 线程接收时间的差值估算的,一旦 SQL 线程卡住或者 relay log 特别大,这个值可能为 0,但实际数据差了一大截。

我常用的监控策略是组合拳:

第一招:对比主从 GTID 位置。

-- 主库执行 SHOW MASTER STATUS; -- 从库执行 SHOW REPLICA STATUS\G

看从库的Retrieved_Gtid_SetExecuted_Gtid_Set,如果两者差值持续增大,说明从库接收得很快但重放跟不上,SQL 线程是瓶颈。

第二招:窗口比较法。在从库创建一张心跳表,定时更新一个时间戳,再用业务查询读到的时间戳和当前时间比较。比如每隔 1 秒在主库写入UPDATE heartbeat SET ts=NOW(),从库读出ts,和本地时间的差值就是相对精确的复制延迟。这个方法能精确反映业务可见的延迟,比看内部状态字段直观得多。

第三招:监控 relay log 积压量。看从库的Relay_Log_File对应的 relay log 文件大小,以及Relay_Log_Pos的增长速度。如果文件持续膨胀,意味着 SQL 线程卡住或者速度太慢。

5.3 延迟的规避方案

延迟完全消除不现实,但把它控制到业务可接受范围内是能做到的。

最核心的一条:尽量让所有业务表都有主键。这不仅是延迟问题,也关系到复制稳定性和数据一致性。我查过不少从库报错Could not execute Write_rows event on table ...,十有八九是目标表没有主键,ROW 格式下无法唯一定位行。

第二条:开启从库多线程复制。MySQL 8.0 默认基于 Writeset 的并行复制,需要确认:

SHOW VARIABLES LIKE 'slave_parallel_workers'; SHOW VARIABLES LIKE 'slave_parallel_type';

如果slave_parallel_workers还是默认的 0,改成 4 或者 8(按 CPU 核心数调),slave_parallel_type设为LOGICAL_CLOCK。改完要重启从库生效。

第三条(也很常见):避免在从库上执行大事务。虽然从库是只读的,但如果你不小心跑了一个大查询,占用了大量 IO 和 CPU,SQL Thread 重放进展会立刻变慢。从库的硬件配置最好不低于主库,读写分离的本质就是把读压力转移到从库,从库磁盘不行,延迟照样高。

第四条:把二级索引建好。ROW 格式的复制在从库重放 UPDATE 和 DELETE 时,需要先定位目标行。如果 WHERE 条件无法走索引,从库会全表扫描,主库可能走索引只锁几行,从库却要扫全表。这种差异在数据量大时非常致命。

6. 故障切换与高频踩坑:主库宕机、数据不一致怎么办

复制架构里做得再好,故障总会来的。这一节把我遇到过的典型故障和对应处理完整走一遍,这些事情在课本和官方文档里写得很简略,但实际做起来处处是坑。

6.1 主库宕机后的手动切换流程

在主从架构下,如果主库物理宕机或者数据损坏,最简单的恢复方案是手动把从库提升为新主库,然后让其他从库(如果有)重新指向它。

流程如下:

第一步,确认主库状态。如果只是网络分区,主库没挂,还在写数据,此时贸然提升从库会造成脑裂。先登录主库看看能不能写,查一下SHOW MASTER STATUS是否正常返回。如果连不上或者异常,才进入切换流程。

第二步,确认从库数据追上主库。在从库上执行SHOW REPLICA STATUS\G,检查Seconds_Behind_Source是否为 0,以及Retrieved_Gtid_Set是否等于Executed_Gtid_Set。如果从库数据落后很多,而主库已经起不来了,那你只能接受丢失最后一段数据的现实,把当前从库顶上去。如果还有另一台健康的从库,可以先把数据从这台顶上之前尽量补齐,再切换。

第三步,停止复制并提升从库为可写:

STOP REPLICA; RESET REPLICA ALL; SET GLOBAL read_only = OFF; SET GLOBAL super_read_only = OFF;

第四步,把业务连接切到新主库。这一步如果用的是 ProxySQL,直接在配置里把主从组的节点对调即可;如果用应用层路由,就改数据源配置。切换后别忘了让其他从库(如果有)指向新的主库:

CHANGE MASTER TO MASTER_HOST='192.168.1.102', MASTER_USER='repl', MASTER_PASSWORD='强密码', MASTER_AUTO_POSITION=1; START REPLICA;

这里有个关键点:GTID 模式下,新主库的Executed_Gtid_Set已经包含了旧主库所有已执行事务,其他从库只要用MASTER_AUTO_POSITION=1去对接,MySQL 会自动跳过那些已经执行过的事务,完成无缝衔接。这就是 GTID 对比位点复制的最大优势之一。

如果你需要把旧主库修复后重新加回集群,它会作为新主库的从库。因为 GTID 包含了整个集群的历史,它启动复制后会自动跳过自身已执行的事务,只拉取新增的数据。整个过程非常顺滑。

6.2 常见故障案例与根因

我把高频踩坑整理成一个表,每一行都是真实发生过的问题:

问题现象直接原因解决方式
Slave_IO_Running: Connecting网络不通、账号权限错误、server_id 重复检查防火墙 3306 端口、确认账号权限、核对 server_id
Slave_SQL_Running: Norelay log 里有错误 SQL,比如表结构不一致、主键冲突SHOW REPLICA STATUSLast_SQL_Error,修复后人工STOP REPLICASTART REPLICA,或跳过后继续
主从数据不一致但复制状态正常binlog_format 为 STATEMENT,或从库有应用写入改用 ROW 格式;给从库加read_only+super_read_only
DDL 在从库执行特别慢主库 8 并发 DDL,从库单线程串行重放低峰期执行 DDL,或者临时调大slave_parallel_workers
大事务(如一次性 DELETE 百万行)导致延迟飙升ROW 格式记录了大量变更事件,重放耗时拆分为分批操作,避免单个事务过大

6.3 数据不一致的检测与修复

复制状态正常并不代表数据一定一致。你可以用pt-table-checksum这个工具做周期性的主从数据一致性校验。它的原理是把大表分成多个 chunk,在每个 chunk 上计算校验和,然后对比主从的校验和结果。发现不一致后,再用pt-table-sync修复。这两个工具是 Percona Toolkit 里最常用的,值得提前装好。

提示:pt-table-sync修改数据之前,务必先备份。工具默认会生成变更语句,你可以先看输出再决定是否执行,别直接一股脑同步过去,否则可能扩大事故范围。

6.4 关于半同步复制的补充

异步复制在极端情况下(主库崩了,binlog 还没来得及传给从库)会丢数据。对数据零容忍的业务,可以启用半同步复制(Semisynchronous Replication)。

半同步复制的原理是:主库提交事务时,需要等待至少一个从库确认收到 binlog 并写入 relay log 后,才向客户端返回提交成功。这样能最大程度保证"主库已提交的事务,不会因为主库挂了就丢失"。代价是写入性能会受影响,因为多了一次网络往返等待。

MySQL 8.0 里半同步是插件式安装。想深入研究的,可以查看官方文档里的INSTALL PLUGIN rpl_semi_sync_sourcerpl_semi_sync_replica相关说明。在性能和数据安全之间怎么取舍,取决于你对 RPO(Recovery Point Objective,恢复点目标)的要求——允许丢最近多少秒的数据,这个问题要在架构设计时就想清楚。

7. 我的实操总结与几个额外忠告

一路写到这里,最后分享几点我反复踩坑后沉淀下来的经验。这些不是官方文档里会教你的东西,但每一条都是真金白银换来的。

第一个忠告:搭建阶段的花费时间是值得的。很多同学急着看效果,跳过数据一致性初始化,直接 CHANGE MASTER 顺手就 START。等到从库Last_Errno报错,又回头重新初始化,反而浪费更多时间。严格按照"先备份一致性快照、再导入从库、再启动复制、最后验证"的流程走,一次成功概率几乎百分之百。

第二个忠告:监控一定要前置。主从复制不是配置完就一劳永逸的,binlog 文件会膨胀、网络会闪断、磁盘会写满、大事务会堵塞重放。配好之后第一时间做监控,至少包括:复制状态(IO/SQL 线程是否 Running)、复制延迟(心跳表检测)、relay log 积压量、主从磁盘空间。监控告警到位了,你才有处理问题的预警时间,而不是等业务反馈数据不对了才去查。

第三个忠告:面试和实战是两回事。网上有很多 MySQL 面试题把主从复制的原理背得滚瓜烂熟,但真要上手配置时各种报错。原理当然要懂,但更重要的是亲手把它搭出来、踩一遍坑、再思考为什么。当你真正经历过一次"主库挂了、手动切到从库、业务恢复"的完整过程,你对这套机制的认知才会真正从"会背"变成"会做"。

关于这套架构后续还能怎么演进,我觉得值得留意的方向是 MySQL 组复制(Group Replication)和 InnoDB Cluster。组复制能做到多主写入、自动选主,在数据一致性和高可用性上比传统主从复制更进一步。如果你是刚接触主从复制,建议先把今天这套单主多从玩明白,然后再往组复制的方向探索——基础不牢的时候上更复杂的架构,只会让你在故障面前手足无措。

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

学习资源推荐系统实战:从交互矩阵到ItemCF协同过滤

简介&#xff1a;基于协同过滤算法的学习资源个性化推荐系统是一份完整的硕士毕业设计项目包&#xff0c;适合计算机及相关专业学生用于毕业设计或课程设计参考。压缩包共232个文件&#xff0c;以Java源码、JavaScript脚本、JSP页面和CSS样式为主&#xff0c;另含SQL数据库脚本…

作者头像 李华
网站建设 2026/9/14 9:00:43

信息系统架构设计:从理论到实践的软考核心指南

1. 信息系统架构概述 信息系统架构是软考中级考试中的核心章节&#xff0c;也是实际工作中系统设计的理论基础。这一章主要探讨如何将业务需求转化为可落地的技术方案&#xff0c;涉及从概念到实现的完整链条。我在备考和实际项目中发现&#xff0c;掌握好这章内容不仅能应对考…

作者头像 李华
网站建设 2026/9/14 8:55:41

高保真建模与协同仿真平台的技术实现与应用

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华