MySQL主从复制
MySQL 主从复制解决"单点故障 + 读写压力"两个问题:数据从主库同步到从库,实现读写分离(主写从读)与故障切换。复制的本质是"主库记录 Binlog、从库重放 Binlog"——理解 Binlog 三种格式(见 日志)是理解复制的前提。MGR(组复制)是比传统主从更高阶的高可用方案(见 MGR高可用),本文聚焦传统异步/半同步复制。
复制原理
主库与从库各有一个核心线程:
| 角色 | 线程 | 职责 |
|---|---|---|
| 主库 | Binlog Dump 线程 | 把 Binlog 变更推送给从库 |
| 从库 | IO 线程 | 接收主库 Binlog 写入本机 Relay Log |
| 从库 | SQL 线程 | 读取 Relay Log 重放到从库数据 |
复制的延迟点在于"IO 线程写 Relay Log → SQL 线程重放"是异步的,主库写入后不等从库确认直接返回。
搭建步骤
-- 主库:开启 Binlog 并设 server-id(必须唯一)
-- my.cnf
[mysqld]
log-bin=mysql-bin
server-id=1
-- 主库:创建复制账号
CREATE USER 'repl'@'%' IDENTIFIED BY 'password';
GRANT REPLICATION SLAVE ON *.* TO 'repl'@'%';
FLUSH PRIVILEGES;
-- 主库:记录当前 Binlog 坐标
SHOW BINARY LOG STATUS; -- 记下 File 和 Position 两列值-- 从库:指定主库连接(8.0.23+ 用 SOURCE 关键字,旧版 MASTER 已弃用)
CHANGE REPLICATION SOURCE TO
SOURCE_HOST='主库IP',
SOURCE_USER='repl',
SOURCE_PASSWORD='password',
SOURCE_LOG_FILE='mysql-bin.000001',
SOURCE_LOG_POS=154;
START REPLICA; -- 启动复制(旧版 START SLAVE)
SHOW REPLICA STATUS\G -- 查看复制状态全量初始化
从库若已有数据或需从主库全量复制,先 mysqldump 主库并导入从库,再开启复制——复制只同步"开启之后"的增量:
# 主库导出(带 --master-data=2 自动记录 binlog 坐标)
mysqldump --all-databases --master-data=2 --single-transaction > dump.sql
# 从库导入后 CHANGE REPLICATION SOURCE 指向 dump 中记录的坐标
mysql < dump.sql异步与半同步
| 模式 | 主库提交时机 | 数据安全 | 性能 |
|---|---|---|---|
| 异步复制(默认) | 写完 Binlog 立即提交返回 | 主库宕机瞬间未同步的写可能丢失 | 最高 |
| 半同步复制 | 等至少一个从库确认收到 Binlog 才提交 | 至少一个从库有最新数据 | 略降(等从库确认) |
| 组复制 MGR | 多数派确认 | 强一致(见 MGR高可用) | 较低 |
半同步启用(插件方式):
INSTALL PLUGIN rpl_semi_sync_source SONAME 'semisync_source.so'; -- 主库
INSTALL PLUGIN rpl_semi_sync_replica SONAME 'semisync_replica.so'; -- 从库
SET GLOBAL rpl_semi_sync_source_enabled = 1;
SET GLOBAL rpl_semi_sync_replica_enabled = 1;半同步的降级
半同步在"从库确认超时(默认 10s)"或"无从库"时会降级回异步(rpl_semi_sync_source_timeout 控制)——降级期间主库写入不再等从库,故障窗口重新出现。监控该参数状态是半同步运维要点。
主从延迟
主从延迟 = 主库写入时间 − 从库重放时间,典型来源是"从库只有单 SQL 线程顺序重放":
| 延迟来源 | 说明 | 对策 |
|---|---|---|
| 从库单线程重放 | 大事务/DDL 在从库执行慢 | 并行复制(8.0.27+ 默认 4 线程 replica_parallel_workers,旧版需手动开启;按库/事务粒度并行) |
| 大事务 | 单条 SQL 影响大量行,Binlog 大 | 拆分大事务、max_binlog_cache_size 调优 |
| 从库有查询压力 | 重放与查询抢资源 | 从库只读(super_read_only=1)、加从库 |
| 网络延迟 | 主从跨机房 | 同机房部署、半同步 |
-- 查看延迟(Seconds_Behind_Source 接近 0 为正常;8.0.23 前为 Seconds_Behind_Master)
SHOW REPLICA STATUS\G
-- 秒杀类对延迟敏感业务:同一事务内写主库+读主库,或强制从库读走主库故障切换
| 场景 | 处理 |
|---|---|
| 从库故障 | 直接剔除,主库不受影响;修复后重新 CHANGE REPLICATION |
| 主库故障(人工切换) | 选延迟最小的从库 STOP REPLICA → RESET REPLICA ALL → 提升为主(应用改连) |
| 自动切换 | 用 MHA(Master High Availability,Percona 的 MySQL 自动故障转移工具)/ Orchestrator(Raft 协调的 MySQL 拓扑管理工具)/ MGR 自动故障转移(见 MGR高可用) |
切换数据一致性
主库突然宕机时,异步复制下"尚未同步到从库的写"会在切换后丢失。严格场景需配合半同步减少窗口,或用 MGR 保证多数派一致后再切换。切换前必须确认延迟字段(Seconds_Behind_Source)归零。
常见问题
| 问题 | 排查 |
|---|---|
SHOW REPLICA STATUS 为空 | 检查 server-id 是否冲突、Binlog 是否开启 |
复制中断 IO error | 看 Last_IO_Error,多为网络/权限/坐标错误 |
复制中断 SQL error | 看 Last_SQL_Error,多为重放冲突(如主键冲突),定位后 START REPLICA 前先修正 |
| 主从数据不一致 | pt-table-checksum 校验 + pt-table-sync 修复(Percona Toolkit) |