一句话总结
MySQL 主从复制基于 binlog,分三步:1)主库写 binlog → 2)从库 IO 线程拉取 binlog 写入 relay log → 3)从库 SQL 线程重放 relay log。binlog 有三种格式:STATEMENT(记录 SQL)、ROW(记录行变更,推荐)、MIXED(混合)。GTID 复制简化了主从切换。主从延迟是常见问题,原因包括从库性能差、大事务、网络延迟。
初级理解
主从复制三步流程
1. 主库写入 binlog:事务提交时,主库将数据变更写入 binlog
2. 从库 IO 线程拉取:从库 IO 线程连接主库,读取 binlog 并写入 relay log(中继日志)
3. 从库 SQL 线程重放:从库 SQL 线程读取 relay log 中的事件,在从库上重放执行
binlog 三种格式对比
| 格式 | 记录内容 | 优点 | 缺点 |
| STATEMENT | SQL 语句 | 日志量小 | 部分函数(NOW/UUID)导致主从不一致 |
| ROW(推荐) | 每行数据变更 | 精确,不会不一致 | 日志量大(UPDATE 全表时) |
| MIXED | 默认 STATEMENT,特殊时 ROW | 折中方案 | 仍有不一致风险 |
# 查看 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';
# 设置 binlog 格式
SET GLOBAL binlog_format = 'ROW';
# 查看 binlog 文件列表
SHOW BINARY LOGS;
# 查看 binlog 内容
SHOW BINLOG EVENTS IN 'mysql-bin.000001' LIMIT 10;
# 用 mysqlbinlog 工具解析
mysqlbinlog --base64-output=decode-rows -v mysql-bin.000001
一句话总结:主从复制 = 主库写 binlog → 从库 IO 线程拉 → 从库 SQL 线程放,ROW 格式最安全。
中级深入
GTID 复制(MySQL 5.6+)
GTID(Global Transaction Identifier)是事务的全局唯一标识,格式:server_uuid:transaction_id。相比传统基于 binlog 文件名+位置的复制,GTID 简化了主从切换,从库自动找同步点。
# 开启 GTID(my.cnf)
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
# 从库配置 GTID 复制
CHANGE MASTER TO
MASTER_HOST = '192.168.1.100',
MASTER_PORT = 3306,
MASTER_USER = 'repl',
MASTER_PASSWORD = 'password',
MASTER_AUTO_POSITION = 1; # 自动找同步位置
# 查看 GTID 执行情况
SHOW MASTER STATUS\G
SHOW SLAVE STATUS\G
# Executed_Gtid_Set: 已执行的 GTID 集合
# Retrieved_Gtid_Set: 已接收的 GTID 集合
半同步复制 — 解决数据丢失
默认异步复制:主库提交后立即返回,不等待从库确认 → 主库宕机可能丢数据。
半同步复制:主库提交后等待至少一个从库收到 binlog 并写入 relay log后才返回客户端。
# 安装半同步插件
# 主库
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = ON;
SET GLOBAL rpl_semi_sync_master_timeout = 10000; # 超时 10 秒退化为异步
# 从库
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = ON;
# 查看半同步状态
SHOW STATUS LIKE 'Rpl_semi_sync%';
主从延迟原因与解决
| 原因 | 解决方案 |
| 从库性能差(配置低) | 从库配置不低于主库 |
| 大事务(一次更新百万行) | 拆分大事务为小事务 |
| 从库 SQL 线程单线程(5.6 前) | MySQL 5.7+ 并行复制(MTS) |
| 网络延迟 | 主从同机房部署 |
| 锁等待 | 减少从库上的查询负载 |
# 查看主从延迟
SHOW SLAVE STATUS\G
# Seconds_Behind_Master: 延迟秒数(NULL 表示复制异常)
# 开启并行复制(MySQL 5.7+)
SET GLOBAL slave_parallel_type = 'LOGICAL_CLOCK';
SET GLOBAL slave_parallel_workers = 4; # 4 个并行线程
# 监控延迟
SELECT * FROM performance_schema.replication_applier_status_by_worker;
中级要点:GTID 简化主从切换;半同步减少数据丢失;并行复制(MTS)缓解延迟。
高级拓展
读写分离方案
| 方案 | 实现 | 优点 | 缺点 |
| 客户端路由 | ShardingSphere-JDBC | 无额外组件,性能好 | 语言绑定,配置复杂 |
| 中间件代理 | ProxySQL / MySQL Router | 对应用透明 | 多一层网络开销 |
| DNS 轮询 | 读域名指向多个从库 | 简单 | 无感知延迟和故障 |
# ShardingSphere-JDBC 读写分离配置(Spring Boot)
# application.yml
spring:
shardingsphere:
datasource:
names: master, slave0, slave1
master:
type: com.zaxxer.hikari.HikariDataSource
url: jdbc:mysql://master:3306/db
slave0:
url: jdbc:mysql://slave0:3306/db
slave1:
url: jdbc:mysql://slave1:3306/db
rules:
readwrite-splitting:
data-sources:
myds:
type: Static
props:
write-data-source-name: master
read-data-source-names: slave0, slave1
load-balancer-name: round_robin
主从切换(Failover)
当主库宕机时,需要将一个从库提升为主库。传统方式手动切换,推荐使用 Orchestrator 或 MHA 自动切换。
# 手动主从切换步骤
# 1. 确认主库已宕机,所有从库已同步到最新
# 2. 选择一个数据最新的从库作为新主库
# 3. 在新主库上:
STOP SLAVE;
RESET SLAVE ALL;
# 4. 其他从库指向新主库:
CHANGE MASTER TO MASTER_HOST='新主库IP', MASTER_AUTO_POSITION=1;
START SLAVE;
# 5. 更新应用连接地址
实战场景
场景:搭建一主一从复制
# 主库配置(my.cnf)
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog_format = ROW
binlog_row_image = FULL
expire_logs_days = 7
# 主库创建复制用户
CREATE USER 'repl'@'%' IDENTIFIED BY 'repl_password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
# 主库备份并记录位置
FLUSH TABLES WITH READ LOCK;
SHOW MASTER STATUS; # 记录 File 和 Position
mysqldump -u root -p --all-databases --master-data > backup.sql
UNLOCK TABLES;
# 从库配置(my.cnf)
[mysqld]
server-id = 2
relay-log = relay-log
read_only = ON
# 从库导入备份
mysql -u root -p < backup.sql
# 从库配置复制
CHANGE MASTER TO
MASTER_HOST = '192.168.1.100',
MASTER_PORT = 3306,
MASTER_USER = 'repl',
MASTER_PASSWORD = 'repl_password',
MASTER_LOG_FILE = 'mysql-bin.000001',
MASTER_LOG_POS = 1234;
START SLAVE;
SHOW SLAVE STATUS\G # 确认 Slave_IO_Running 和 Slave_SQL_Running 都是 Yes
面试模拟
面试官:主从延迟怎么解决?
你:1)MySQL 5.7+ 开启并行复制(MTS),设置 slave_parallel_workers;2)拆分大事务,避免一次更新百万行;3)从库硬件配置不低于主库;4)主从同机房部署减少网络延迟;5)业务上容忍延迟——关键读走主库,非关键读走从库。
面试官:binlog 的 ROW 和 STATEMENT 格式有什么区别?
你:STATEMENT 记录 SQL 语句,日志量小但可能主从不一致(如 NOW()、UUID() 等函数);ROW 记录每行数据变更,日志量大但精确安全。生产环境推荐 ROW 格式,MySQL 8.0 默认也是 ROW。
面试官:GTID 复制有什么优势?
你:1)简化主从切换——不需要手动指定 binlog 文件和位置,MASTER_AUTO_POSITION=1 自动找同步点;2)每个事务有全局唯一 ID,方便追踪;3)支持多源复制和级联复制时更易管理。