MySQL Replication 面试题
12 道题- 分类
- 数据库
- 子分类
- mysql
- 题目数
- 12 道
1 MySQL 复制架构总览与异步复制原理
答案:
MySQL 复制是 MySQL 内置的数据分布与高可用基础机制,主库(Source/Primary)将数据变更以事件(event)形式记录到二进制日志(binlog),从库(Replica/Secondary)通过 I/O 线程拉取 binlog 并由 SQL 线程重放,实现数据同步。
异步复制(Asynchronous Replication)拓扑:
graph LR
App["Application
Write"]
M["Source
binlog dump thread"]
R1["Replica-1
IO_Thread / SQL_Thread"]
R2["Replica-2
IO_Thread / SQL_Thread"]
R3["Replica-3
IO_Thread / SQL_Thread"]
App --> M
M -->|"binlog events"| R1
M -->|"binlog events"| R2
M -->|"binlog events"| R3
复制线程模型:
| 线程 | 运行位置 | 职责 |
|---|---|---|
| Binlog Dump Thread | 主库 | 监听从库连接,读取 binlog 并推送至从库 I/O 线程 |
| IO_Thread | 从库 | 连接主库,请求 binlog 位置,写入本地 relay log(中继日志) |
| SQL_Thread | 从库 | 读取 relay log,重放事件到从库存储引擎 |
异步复制关键特性:
- 默认模式:主库写入 binlog 后立即返回客户端成功,不等待从库 ACK
- 主库性能无损:复制延迟不影响主库事务提交
- 数据丢失风险:主库宕机时已提交但未推送给从库的事务会丢失
- 版本要求:MySQL 8.0.22+ 官方文档将 “Master-Slave” 重命名为 “Source-Replica”
典型配置:
# 主库 my.cnf
[mysqld]
server_id = 1
log_bin = /var/log/mysql/mysql-bin.log
binlog_format = ROW
gtid_mode = ON
enforce_gtid_consistency = ON
sync_binlog = 1
innodb_flush_log_at_trx_commit = 1
# 从库 my.cnf
[mysqld]
server_id = 2
relay_log = /var/log/mysql/relay-bin.log
read_only = ON
log_slave_updates = ON
gtid_mode = ON
enforce_gtid_consistency = ON
适用场景:
- 数据分布、读写分离、报表分析从库
- 对一致性要求不高的业务(社交、日志分析)
- 故障切换时存在数据丢失风险,需配合半同步或 MHA
2 binlog 格式:STATEMENT、ROW 与 MIXED 的差异与生产选型
答案:
binlog 格式决定了主库记录变更的方式,直接影响复制数据一致性、磁盘占用、恢复能力与主从一致性。MySQL 支持三种格式:STATEMENT、ROW、MIXED。
三种格式对比:
| 维度 | STATEMENT | ROW | MIXED |
|---|---|---|---|
| 记录内容 | 原始 SQL 语句 | 行的实际变更前/后镜像 | 默认 STATEMENT,特定场景切换为 ROW |
| binlog 大小 | 最小(仅记录 SQL) | 最大(每行变更都记录) | 中等 |
| 数据一致性 | 差(非确定函数、触发器问题) | 最强(行级一致) | 较好 |
| 主从延迟 | 较低 | 较高(大事务产生大量 row event) | 折中 |
| 恢复能力 | 需上下文(时间点/位置) | 可逆(原始行镜像) | 介于两者之间 |
| 审计能力 | 可读 SQL 文本 | 需 binlog2sql 等工具解析 | 部分可读 |
| 典型问题 | UUID()、NOW()、LIMIT 无 ORDER BY 导致主从不一致 | 大表 UPDATE/DELETE 产生海量 binlog | 切换规则不透明 |
ROW 格式的双镜像机制:
graph TD
A["原 SQL: UPDATE t SET v=v+1 WHERE id<1000"] --> B["STATEMENT 格式
记录 SQL 文本
binlog: 'UPDATE t SET v=v+1...'"]
A --> C["ROW 格式
记录每行变更
Table_map event + Update_rows event
含 BEFORE_AFTER_IMAGE"]
B --> D["从库重放时存在
执行时机/上下文差异风险"]
C --> E["从库重放时直接写入
行镜像,强一致"]
生产环境选型建议:
- 金融、订单、库存等强一致场景:必须使用
ROW - 大规模 DML 的数据集成场景:可考虑
MIXED平衡体积与一致性 - STATEMENT 格式:仅遗留系统或对 binlog 可读性有特殊要求的场景
- 行级闪回(Flashback):依赖
ROW格式的BEFORE_IMAGE
在线修改 binlog 格式:
-- 全局修改(需所有会话断开才能生效)
SET GLOBAL binlog_format = 'ROW';
-- 会话级修改(推荐测试场景)
SET SESSION binlog_format = 'ROW';
-- 验证当前格式
SHOW VARIABLES LIKE 'binlog_format';
SHOW MASTER STATUS;
最佳实践:
- 主从复制链路所有节点必须使用相同
binlog_format - MySQL 8.0 默认
ROW格式,且binlog_format已废弃(保留仅作兼容) - 高一致性业务建议
ROW + binlog_row_image=FULL(记录完整前后镜像)
3 基于位点(File-Position)复制与基于 GTID 复制的对比
答案:
传统复制依赖 binlog 文件名 + 偏移量(File-Position)定位复制位点,MySQL 5.6 引入 GTID(Global Transaction Identifier)提供全局唯一事务标识,从 MySQL 5.7.9 开始 GTID 模式趋于成熟,8.0 默认启用。
File-Position 复制核心机制:
-- 主库查看位点
SHOW MASTER STATUS;
-- File: mysql-bin.000003 Position: 154 Binlog_Do_DB: mydb
-- 从库配置复制
CHANGE MASTER TO
MASTER_HOST = '192.168.1.10',
MASTER_USER = 'repl_user',
MASTER_PASSWORD = 'repl_pass',
MASTER_LOG_FILE = 'mysql-bin.000003',
MASTER_LOG_POS = 154;
START SLAVE;
GTID 复制核心机制:
graph LR
A["GTID 格式
source_id:transaction_id
3E11FA47-71CA-11E1-9E33-C80AA9429562:1-5"] --> B["全局唯一
每实例 UUID 标识"]
A --> C["单调递增
事务序号"]
B --> D["故障切换时
自动定位位点"]
C --> E["跳过事务
基于 GTID 集合"]
GTID 复制配置:
# 主从均需配置
[mysqld]
gtid_mode = ON
enforce_gtid_consistency = ON
log_bin = /var/log/mysql/mysql-bin.log
log_slave_updates = ON
-- 从库使用 GTID 自动定位
CHANGE MASTER TO
MASTER_HOST = '192.168.1.10',
MASTER_USER = 'repl_user',
MASTER_PASSWORD = 'repl_pass',
MASTER_AUTO_POSITION = 1;
START SLAVE;
核心差异对比:
| 维度 | File-Position | GTID |
|---|---|---|
| 定位方式 | 文件名 + 偏移量 | GTID 集合 |
| 故障切换 | 需人工查找一致位点 | 自动协商,简化切换 |
| 跳过事务 | SET GLOBAL sql_slave_skip_counter=1 | 注入空事务 SET GTID_NEXT='xxx:1'; BEGIN; COMMIT; |
| 多源复制 | 配置复杂 | 天然支持,事务不冲突 |
| 主从切换 | MHA/Orchestrator 需额外逻辑 | 内置自动位点协商 |
| MySQL 版本 | 全版本支持 | 5.6+ 实验,5.7+ 稳定,8.0 默认 |
GTID 集合与 gtid_executed / gtid_purged:
-- 查看实例已执行 GTID 集合
SHOW MASTER STATUS;
-- Executed_Gtid_Set: 3E11FA47-71CA-11E1-9E33-C80AA9429562:1-100
-- 从库恢复时需设置 gtid_purged
SET GLOBAL gtid_purged = '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-100';
-- 实时查看从库状态
SHOW SLAVE STATUS\G
-- Retrieved_Gtid_Set / Executed_Gtid_Set
生产实践:
- 新建复制环境一律启用 GTID,简化运维与故障切换
- 老旧 File-Position 环境升级时先观察
gtid_mode兼容性 - 启用
enforce_gtid_consistency避免非事务引擎、CREATE TABLE…SELECT 等导致 GTID 空洞
4 MySQL 半同步复制与增强半同步(After Sync / Loss-less)
答案:
半同步复制(Semi-Synchronous Replication)解决异步复制数据丢失风险,主库提交事务前需等待至少一个从库确认收到 binlog 才返回客户端成功。MySQL 5.7 引入增强半同步(AFTER_SYNC 模式),5.7.2 设为默认。
异步 vs 半同步 vs 增强半同步:
sequenceDiagram
participant App as Application
participant M as Master
participant R as Replica
Note over App,R: 异步复制
App->>M: COMMIT
M->>M: binlog write/fsync
M-->>App: OK (立即返回)
M->>R: async push binlog
Note over App,R: 增强半同步 (AFTER_SYNC)
App->>M: COMMIT
M->>M: binlog write/fsync
M->>R: push binlog
R-->>M: ACK (写入 relay log)
M->>M: engine commit
M-->>App: OK (收到 ACK 后)
半同步复制配置:
-- 1. 主库安装半同步插件
INSTALL PLUGIN rpl_semi_sync_master SONAME 'semisync_master.so';
SET GLOBAL rpl_semi_sync_master_enabled = 1;
SET GLOBAL rpl_semi_sync_master_timeout = 10000; -- 10秒超时
SET GLOBAL rpl_semi_sync_master_wait_for_slave_count = 1; -- 至少1个ACK
-- 2. 从库安装半同步插件
INSTALL PLUGIN rpl_semi_sync_slave SONAME 'semisync_slave.so';
SET GLOBAL rpl_semi_sync_slave_enabled = 1;
-- 3. 重启从库 IO 线程使插件生效
STOP SLAVE IO_THREAD;
START SLAVE IO_THREAD;
两种等待模式对比:
| 模式 | 等待 ACK 时机 | 引擎提交时机 | 性能 | 一致性 |
|---|---|---|---|---|
| AFTER_COMMIT(旧,5.7 之前) | 引擎 commit 之后 | 先 commit 后等待 | 高 | 弱(宕机时可能多从库未收到) |
| AFTER_SYNC(增强,5.7+) | binlog 同步之后 | 等待 ACK 后才 commit | 略低 | 强(Loss-less 零丢失) |
生产环境增强半同步关键参数:
[mysqld]
# 主库
plugin-load = "rpl_semi_sync_master=semisync_master.so"
rpl_semi_sync_master_enabled = 1
rpl_semi_sync_master_timeout = 30000 # 30秒超时降级为异步
rpl_semi_sync_master_wait_for_slave_count = 2 # 至少2个从库ACK(5.7+)
rpl_semi_sync_master_wait_point = AFTER_SYNC # 增强半同步
# 从库
plugin-load = "rpl_semi_sync_slave=semisync_slave.so"
rpl_semi_sync_slave_enabled = 1
监控指标:
SHOW STATUS LIKE 'Rpl_semi_sync_master_status'; -- ON/OFF
SHOW STATUS LIKE 'Rpl_semi_sync_master_yes_tx'; -- 成功等待ACK次数
SHOW STATUS LIKE 'Rpl_semi_sync_master_no_tx'; -- 超时降级次数
SHOW STATUS LIKE 'Rpl_semi_sync_master_clients'; -- 半同步从库数
降级与风险:
- 超时降级:
rpl_semi_sync_master_timeout内未收到 ACK 自动降级为异步,存在数据丢失 - 网络抖动是常见降级诱因,需配置
wait_for_slave_count至少 2 副本 - 主库宕机时已收到 ACK 但未提交的事务在从库可继续应用
适用场景:
- 金融、订单、支付等强一致业务
- 配合 MHA/Orchestrator 实现高可用切换
- 与 GTID 配合使用简化故障恢复
5 并行复制:多线程 applier 演进(5.6 -> 5.7 -> 8.0 Writeset)
答案:
MySQL 单线程 SQL_Thread 长期是复制延迟主因,从 5.6 起逐步引入多线程复制机制,5.7 实现 LOGICAL_CLOCK 真正并行,8.0 引入 WRITESET 等更细粒度策略。
并行复制演进:
| 版本 | 策略 | 并行粒度 | 适用场景 |
|---|---|---|---|
| 5.6 | 基于库(schema)并行 | 按 database 分配 worker | 多 schema 独立业务 |
| 5.7 | LOGICAL_CLOCK(基于组提交) | 同一主库组提交事务可并行 | 单 schema 高并发写入 |
| 8.0 | WRITESET / WRITESET_SESSION | 基于行主键 hash 分配 | 同一事务/写集冲突最小化 |
并行复制架构:
graph TD
A["Master
binlog events"] --> B["Relay Log"]
B --> C["Coordinator
分发线程"]
C --> D1["Worker-1
Apply"]
C --> D2["Worker-2
Apply"]
C --> D3["Worker-3
Apply"]
C --> D4["Worker-N
Apply"]
D1 --> E["Replica Storage"]
D2 --> E
D3 --> E
D4 --> E
5.7 LOGICAL_CLOCK 配置:
[mysqld]
slave_parallel_type = LOGICAL_CLOCK
slave_parallel_workers = 16 # 建议 CPU 核数 50%~100%
slave_preserve_commit_order = ON # 8.0 强制 ON,保证 binlog 顺序
8.0 WRITESET 配置:
[mysqld]
slave_parallel_type = WRITESET
slave_parallel_workers = 16
binlog_transaction_dependency_tracking = WRITESET
slave_preserve_commit_order = ON
transaction_write_set_extraction = XXHASH64
三种依赖跟踪策略:
| 策略 | 依赖判定 | 性能 | 限制 |
|---|---|---|---|
| COMMIT_ORDER | 同主库组提交顺序 | 中 | 单实例组提交窗口 |
| WRITESET | 事务写集(行主键 hash)有交集则顺序 | 高 | 需主键,更新非主键列无 hash 变化 |
| WRITESET_SESSION | 同一会话事务强制顺序 + WRITESET | 中 | 牺牲部分并行度保会话内一致 |
生产调优建议:
slave_parallel_workers建议设为min(CPU核数, 32),过多线程切换开销反而增加- 必须开启
slave_preserve_commit_order=ON,否则回放顺序错乱导致主从不一致 - 大事务(bulk load / DDL)会阻塞后续小事务并行,需拆分大事务
- 主库调整
binlog_group_commit_sync_delay/binlog_group_commit_sync_no_delay_count增加组提交窗口可提升从库并行度
监控延迟:
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: 0
-- Slave_SQL_Running_State: Reading event from the relay log
-- (Seconds_Behind_Master 不准确时检查)
SELECT RECEIVED_TRANSACTION_SET, APPLIED_TRANSACTION_SET
FROM performance_schema.replication_applier_status_by_worker;
6 MySQL Group Replication(MGR)架构与单主/多主模式
答案:
Group Replication(GR)是 MySQL 5.7.17 引入、8.0 成熟的官方多主集群方案,基于 Paxos 变体协议实现分布式共识与自动故障切换,InnoDB Cluster 的内核组件。
MGR 架构与数据流:
graph TD
subgraph "Group (3+ nodes)"
N1["Node-1
PRIMARY"]
N2["Node-2
SECONDARY"]
N3["Node-3
SECONDARY"]
end
N1 <-.->|XCom Paxos| N2
N2 <-.->|XCom Paxos| N3
N1 <-.->|XCom Paxos| N3
N1 -->|replicate| N2
N1 -->|replicate| N3
核心机制:
| 概念 | 说明 |
|---|---|
| Group Communication System (XCom) | 基于 Paxos 变体的消息层,提供 Total Order 广播与成员视图管理 |
| Certification(认证) | 事务提交前对 Write Set 冲突检测,多数派通过后才提交 |
| Flow Control | 慢节点反压机制,避免落后节点被淘汰 |
| Consensus | 多数派(N/2+1)节点确认才视为提交,保证强一致 |
单主模式(Single-Primary Mode):
- 仅一个节点接受写入(PRIMARY),其余为 SECONDARY 自动选主
- 写扩展能力弱,但避免多主冲突
- 适合读多写少、对一致性要求高的场景
[mysqld]
plugin_load_add = 'group_replication.so'
group_replication_group_name = "aaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
group_replication_start_on_boot = OFF
group_replication_local_address = "192.168.1.10:33061"
group_replication_group_seeds = "192.168.1.10:33061,192.168.1.11:33061,192.168.1.12:33061"
group_replication_bootstrap_group = OFF
# 单主模式
group_replication_single_primary_mode = ON
group_replication_enforce_update_everywhere_checks = OFF
多主模式(Multi-Primary Mode):
- 所有节点均可写入,Paxos 协商全局顺序
- 同一行并发更新会被踢出集群(
ER_GROUP_REPLICATION_ROW_NOT_FOUND或冲突中止) group_replication_enforce_update_everywhere_checks = ON强制开启严格检查- 适合地理分布式多机房写入
关键限制:
- 必须使用 InnoDB 存储引擎
- 表必须有主键(无主键表会导致 GR 报错)
- 不支持
CREATE TABLE ... SELECT、GTID 不一致、SERIALIZABLE隔离 - 网络分区可能触发多数派自动踢出节点
故障切换:
- PRIMARY 失联超
group_replication_member_expel_timeout(默认 5s) - 多数派基于 UUID 字典序选新 PRIMARY(单主模式)
- 客户端需配置重试或使用 MySQL Router 透明路由
适用场景:
- 强一致 + 自动故障切换的分布式数据库集群
- 替代传统主从 + MHA 架构
- 与 MySQL Shell + MySQL Router 组合成完整 InnoDB Cluster 解决方案
7 主从延迟(Replication Lag)成因、监控与优化
答案:
主从延迟指主库已提交事务到从库重放完成的时间差。Seconds_Behind_Master 是常见监控指标,但该值基于 Slave_IO_Thread 时间戳与 SQL 线程差,存在误报可能。
延迟产生的核心环节:
graph LR
A["主库写入
事务执行+binlog"] --> B["binlog dump
推送到从库"]
B --> C["从库 IO_Thread
写入 relay log"]
C --> D["从库 SQL_Thread
重放到存储引擎"]
D --> E["从库可见"]
style A fill:#ffe
style D fill:#fdd
延迟主因分类:
| 类型 | 成因 | 影响 |
|---|---|---|
| 大事务 | 单个事务修改百万行(如 UPDATE 无索引列) | 长时间持有 binlog 位点,阻塞后续 event |
| DDL 操作 | ALTER TABLE 大表加列、Online DDL 卡顿 | SQL 线程暂停 |
| 主库写入并发 | 5.6 库级并行 / 5.7 提交顺序决定并行度 | 高并发写入时单 worker 仍排队 |
| 从库硬件 | IO 慢(机械盘)、CPU 弱、内存不足 | 重放速度跟不上主库 |
| 锁冲突 | 从库只读下仍有 MDL 锁、隐式锁等待 | 重放阻塞 |
| 长事务 | 从库 innodb_lock_wait_timeout 默认 50s | 大事务回滚耗时 |
真实监控指标(替代 Seconds_Behind_Master):
-- 1. GTID 集合差异
SELECT
(SELECT RECEIVED_TRANSACTION_SET FROM performance_schema.replication_connection_status) AS received,
(SELECT APPLIED_TRANSACTION_SET FROM performance_schema.replication_applier_status) AS applied;
-- 2. 复制性能表(8.0+)
SELECT * FROM performance_schema.replication_applier_status_by_worker;
-- 3. 监控 worker 延迟
SELECT WORKER_ID, LAST_APPLIED_TRANSACTION,
LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP,
(APPLYING_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP -
LAST_APPLIED_TRANSACTION_ORIGINAL_COMMIT_TIMESTAMP) AS lag_sec
FROM performance_schema.replication_applier_status_by_worker;
优化策略:
[mysqld]
# 主库
binlog_group_commit_sync_delay = 1000 # 1ms 组提交窗口,提升从库并行机会
binlog_group_commit_sync_no_delay_count = 10
sync_binlog = 1
# 从库
slave_parallel_workers = 16
slave_parallel_type = LOGICAL_CLOCK
slave_preserve_commit_order = ON
read_only = ON
super_read_only = ON # 8.0 防止误写
log_slave_updates = ON
innodb_flush_log_at_trx_commit = 2 # 从库可放宽
sync_binlog = 0
slave_skip_errors = 1062,1032 # 谨慎使用
# 硬件:SSD/NVMe、万兆网络
业务层缓解:
- 强制读写分离路由走主库(评论、点赞、库存扣减等强写后立即读)
- 使用缓存(Redis)吸收读流量
- 拆分大事务(按主键范围分批
UPDATE) - 重要业务接受最终一致性(CDN、ES 索引延迟同步)
生产案例:
Seconds_Behind_Master=0不等于无延迟:IO 线程断连重连时该值会跳变- 推荐使用
pt-heartbeat工具通过注入时间戳字段精确测量延迟 - 监控告警阈值建议:金融业务 < 1s,通用业务 < 10s
8 延迟复制(Delayed Replication)与防误删场景
答案:
延迟复制通过 CHANGE MASTER TO MASTER_DELAY = N 让从库故意滞后主库 N 秒应用,是对抗"误操作 / 误删除"的关键灾备手段。
延迟复制架构:
graph LR
A["Master
实时写入"] -->|"实时"| B["Replica-1
即时同步
读写分离"]
A -->|"延迟 3600s"| C["Replica-2
Delayed Replica
灾备"]
A -->|"延迟 86400s"| D["Replica-3
24h 延迟
极端灾备"]
配置延迟复制:
STOP SLAVE;
CHANGE MASTER TO MASTER_DELAY = 3600; -- 滞后 1 小时
START SLAVE;
-- 查看延迟
SHOW SLAVE STATUS\G
-- SQL_Delay: 3600
-- SQL_Remaining_Delay: 2453
核心价值:
| 场景 | 价值 |
|---|---|
| 误删表/误删库 | 主库已删除,从库延迟 N 秒尚未应用,可 STOP SLAVE 后导出回滚 |
| 误 UPDATE/DROP | 延迟从库保留 N 秒前快照,可基于此做 Point-in-Time 恢复 |
| 逻辑错误回退 | 业务上线新版本导致逻辑错误,可从延迟从库回退到上一版本数据 |
| 安全合规 | 防止内部误操作快速蔓延 |
生产实践:
[mysqld]
# 延迟从库独立配置
read_only = ON
super_read_only = ON
log_slave_updates = ON
relay_log_info_repository = TABLE # 8.0 默认 FILE,更可靠
master_info_repository = TABLE
# 误操作后回滚流程
# 1. 主库执行 DROP TABLE
# 2. 立即 STOP SLAVE 延迟从库,暂停中继日志应用
# 3. 确认延迟从库的 SQL_Remaining_Delay 跑完已删除 event 之前
# 4. mysqldump 导出被误删对象
# 5. 恢复到主库
注意事项:
- 延迟从库会持续消耗 relay log 存储,需监控磁盘
- 长时间延迟下,从库
relay_log_purge默认开启会自动清理已重放日志 - 延迟从库不应承担实时读流量(数据严重滞后)
CHANGE MASTER TO MASTER_DELAY = 0关闭延迟,但应保持read_only
增强半同步 + 延迟复制组合:
- 主库增强半同步保证至少 1 个从库收到 ACK
- 延迟从库作为兜底灾备,组合实现"RPO ≈ 0 + 误操作秒级回滚"
适用场景:
- 金融、电商核心库必备
- 配合 binlog2sql / MyFlash 等闪回工具构成完整数据保护方案
9 主从复制拓扑设计:级联、多源与主主复制
答案:
MySQL 复制拓扑决定数据分布、故障域隔离、写入扩展性。常见拓扑包括一主多从、级联复制、多源复制、主主复制,各有适用场景与陷阱。
一主多从(Master-Replicas):
graph TD
M["Master
写"] --> R1["Replica-1
读"]
M --> R2["Replica-2
读"]
M --> R3["Replica-3
报表/BI"]
M --> R4["Replica-4
备份"]
- 优点:拓扑简单,读扩展能力强
- 缺点:主库连接数、binlog dump 线程成为瓶颈
- 适用:中小规模业务,读多写少
级联复制(Chained Replication):
graph TD
M["Master"] --> R1["Relay Replica
中继从库"]
R1 --> R2["Replica-2"]
R1 --> R3["Replica-3"]
R1 --> R4["Replica-4"]
- 优点:减少主库连接压力,扩展从库数量
- 配置:中间从库
log_slave_updates=ON+log_bin=ON - 缺点:延迟叠加,中间节点故障影响下游
- 适用:大规模读扩展(>10 个从库)
多源复制(Multi-Source Replication):
graph TD
M1["Master-1
华北"] --> A["Multi-Source Replica
聚合分析"]
M2["Master-2
华东"] --> A
M3["Master-3
华南"] --> A
- MySQL 5.7+ 支持,每个 channel 对应一个主库
- 典型场景:分库分表后聚合分析、跨地域数据汇聚
-- 添加复制通道
CHANGE MASTER TO
MASTER_HOST='192.168.1.10', MASTER_USER='repl',
MASTER_PORT=3306, MASTER_AUTO_POSITION=1
FOR CHANNEL 'channel_north';
CHANGE MASTER TO
MASTER_HOST='192.168.1.11', MASTER_USER='repl',
MASTER_PORT=3306, MASTER_AUTO_POSITION=1
FOR CHANNEL 'channel_east';
START SLAVE FOR CHANNEL 'channel_north';
START SLAVE FOR CHANNEL 'channel_east';
SHOW SLAVE STATUS FOR CHANNEL 'channel_east'\G
- 限制:多源复制从库必须
log_slave_updates=ON,且仅支持单层(从库不能再作为主库同步给其他库)
主主复制(Master-Master / Dual Master):
graph LR
M1["Master-1
业务写入"] <-->|"双向同步"| M2["Master-2
业务写入"]
M2 --> R1["Replica-1"]
M2 --> R2["Replica-2"]
- 机制:两个节点互为主从,
auto_increment_increment+auto_increment_offset避免主键冲突 - 风险:双向写入导致循环复制、数据冲突、分裂脑
- 现代替代:MGR 多主模式 / Orchestrator 协调的主主
# Master-1
auto_increment_increment = 2
auto_increment_offset = 1
# Master-2
auto_increment_increment = 2
auto_increment_offset = 2
- 生产建议:主主复制风险高,仅在跨机房双活写入且能容忍最终一致性的场景使用,推荐改用 Orchestrator + GTID + 单主写入的灰度切换方案
选型决策树:
| 业务特征 | 推荐拓扑 |
|---|---|
| 单机房、读多写少 | 一主多从 + 读写分离 |
| 大量从库 (>10) | 级联复制(Relay Replica) |
| 多地域数据聚合 | 多源复制(5.7+) |
| 同城主备自动切换 | MGR 单主 / Orchestrator + GTID |
| 跨机房双活 | MGR 多主 / Orchestrator 协调主主 |
| 报表/聚合 | 级联中继 + 专属报表从库 |
10 故障切换工具:MHA、Orchestrator 与 MGR 自动选主对比
答案:
主库故障时需快速选新主库并重定向应用,业界方案包括 MHA、Orchestrator 与 MGR 内置选主。
三种方案核心机制:
| 维度 | MHA | Orchestrator | MGR 内置 |
|---|---|---|---|
| 原理 | 监控 + 提升最新从库 + 补齐差异 relay log | 拓扑感知 + Raft 协调 + 提升候选从库 | Paxos 多数派自动选主 |
| 数据一致性 | 强(半同步 + relay log 补齐) | 强(GTID 自动协商) | 强(共识协议) |
| RTO | 10~30s | 5~15s | < 5s |
| RPO | 0(半同步 Loss-less) | 0(GTID 强一致) | 0(共识提交) |
| 切换模式 | 手动触发 / 自动监控 | 手动 / 计划内切换 / 故障自动切换 | 自动 |
| 代理/路由 | 需 VIP 漂移脚本 / ProxySQL | 需配合 ProxySQL / HAProxy | MySQL Router |
| 维护状态 | 已停止维护(最后一版 0.58) | 活跃(GitHub maintained) | Oracle 官方 |
| MySQL 兼容性 | 5.6 / 5.7 主流 | 全版本 | 5.7.17+ / 8.0 |
MHA 架构:
graph TD
M["Master"] --> R1["Replica-1
Candidate"]
M --> R2["Replica-2"]
MHA["MHA Manager
(监控+选主+VIP漂移)"] -.->|监控| M
MHA -.->|监控| R1
MHA -.->|监控| R2
R1 -->|"新主"| App["Application
VIP 漂移后"]
Orchestrator 架构:
graph TD
O["Orchestrator
Raft 集群
检测+协调"] --> M["Master"]
O --> R1["Replica-1"]
O --> R2["Replica-2"]
O --> R3["Replica-3"]
O -->|通知| ProxySQL["ProxySQL / HAProxy
重定向流量"]
ProxySQL --> App["Application"]
Orchestrator 关键命令:
# 优雅主从切换(计划内)
orchestrator -c graceful-master-takeover -alias mycluster \
-designated-master replica-2.example.com \
-reason "patching primary"
# 发现拓扑
orchestrator -c discover -i mycluster
# 强制故障切换
orchestrator -c force-master-failover -alias mycluster \
-reason "master unreachable"
Orchestrator 高可用部署:
# 3 节点 Raft 集群
node1: orchestrator -c raft -raft-leader
node2: orchestrator -c raft
node3: orchestrator -c raft
# 后端 MySQL 存储元数据
OrchestratorDB: orchestrator_meta (clusters, topology, recovery)
MGR 自动选主:
- 内置基于 Paxos 的多数派选主,无需外部工具
group_replication_member_expel_timeout(默认 5s)触发疑似故障超时- 多数派节点基于
member_weight+ UUID 字典序自动选主 - 应用需配合 MySQL Router(
mysqlrouter --bootstrap)实现透明路由
生产选型建议:
- 传统主从 + 半同步 + GTID:Orchestrator 是首选(活跃维护、拓扑感知强)
- 新建项目 + 强一致:直接 MGR(8.0 稳定)
- 遗留 5.6 升级中:MHA 仍可用,但建议规划迁移到 Orchestrator
- 应用层透明:Orchestrator + ProxySQL / MGR + MySQL Router 是两个完整方案
RTO/RPO 优化:
- Orchestrator 配合 ProxySQL 减少 DNS 缓存与连接中断
- 启用
seconds_behind_master < threshold健康检查避免误切 - 配置
pre-failover-script/post-failover-script实现 VIP 漂移、告警通知
11 数据一致性校验:pt-table-checksum 与 pt-table-sync
答案:
主从复制异常可能导致数据不一致(DDL 漏同步、跳过错误、版本差异),需定期校验并修复。Percona Toolkit 的 pt-table-checksum 与 pt-table-sync 是业界标准。
pt-table-checksum 工作原理:
sequenceDiagram
participant L as pt-table-checksum (主库)
participant M as Master
participant R as Replica
L->>M: REPLACE INTO percona.checksums (...)
L->>M: SELECT COUNT(*) FROM tbl WHERE ... (计算 checksum)
M->>M: binlog event
M->>R: 推送到从库
R->>R: 应用 REPLACE INTO percona.checksums
R->>R: 计算本地 checksum
L->>R: SELECT checksum FROM percona.checksums
L->>L: 比对主从 checksum 差异
pt-table-checksum 核心特性:
- 通过复制通道在主库执行,将 checksum 写入
percona.checksums表并随 binlog 同步 - 避免在主从分别执行产生的"checksum 计算期间数据变化"误判
- 分块(chunk)计算避免长事务,支持大表分片
- 报告差异表(
--replicate模式)
典型用法:
# 全量校验所有从库
pt-table-checksum \
--host=master.example.com \
--user=checksum_user \
--password='xxx' \
--replicate=percona.checksums \
--replicate-check-only # 仅检查,不写入
# 仅校验指定表
pt-table-checksum \
--host=master.example.com \
--user=checksum_user \
--password='xxx' \
--databases=mydb \
--tables=orders,users \
--chunk-size=1000 \
--threads=4
# 报告差异
pt-table-checksum --replicate-check-only \
--replicate=percona.checksums \
--host=master.example.com
发现不一致后修复:
# 1. 打印修复 SQL(不执行)
pt-table-sync \
--execute \
--print \
--sync-to-master \
h=replica.example.com,P=3306,u=checksum_user,p='xxx' \
--databases=mydb \
--tables=orders
# 2. 同步方向:主库 -> 从库
pt-table-sync \
--execute \
--sync-to-master \
h=replica.example.com,u=sync_user,p='xxx' \
--databases=mydb \
--tables=orders
# 3. 仅打印 SQL 供审核
pt-table-sync \
--print \
--sync-to-master \
h=replica.example.com,u=sync_user,p='xxx' \
--databases=mydb \
--tables=orders > fix.sql
生产最佳实践:
- 业务低峰期运行,避免 checksum 阻塞主库
- 校验账号仅授予
SELECT, REPLICATION CLIENT, LOCK TABLES, SUPER, PROCESS权限 - 大表分块大小(
--chunk-size)建议 1000-10000,配合--chunk-time控制执行时间 - 定期(每周/每月)全量校验,关键表每日增量校验
- 输出报告入库(
--replicate-check-only+ 监控脚本)
一致性保障组合方案:
- 半同步 + GTID:RPO ≈ 0,复制不丢数据
- pt-table-checksum 定期校验:发现并修复历史不一致
- MGR 共识协议:根本上避免主从不一致
- 延迟从库 + binlog 闪回:误操作秒级回滚
注意事项:
pt-table-sync慎用,修复方向错误会反向破坏数据- 大表同步会长时间持有主键范围锁,需评估业务影响
- 8.0 引入
check_constraint_checks配合 checksum 工具更精细
12 MySQL 复制生产案例与故障排查实战
答案:
复制链路复杂、生产环境常出现各类异常,本节汇总经典生产案例与排查方法。
案例一:主从延迟突增至小时级
-- 排查步骤
SHOW SLAVE STATUS\G
-- Seconds_Behind_Master: 7200
-- Slave_SQL_Running_State: Waiting for dependent transaction to be committed
-- (常见提示)
-- 1. 查大事务
SELECT * FROM mysql.slow_log
WHERE sql_text LIKE '%UPDATE%' AND rows_examined > 1000000
ORDER BY start_time DESC LIMIT 5;
-- 2. 查 worker 状态(8.0)
SELECT * FROM performance_schema.replication_applier_status_by_worker;
-- LAST_ERROR_MESSAGE / LAST_ERROR_TIMESTAMP
-- 3. 查 relay log 积压
SELECT * FROM performance_schema.replication_applier_status
WHERE REMAINING_DELAY IS NOT NULL;
根因:主库执行 1 千万行 UPDATE(无主键或大表无索引),从库 SQL 线程单线程重放。
修复:
- 主库拆分大事务(按主键范围分批)
- 启用并行复制
slave_parallel_workers=16 - 添加主键或合适索引
- 8.0 启用
WRITESET模式提升并行度
案例二:从库 SQL 线程报错 1062 Duplicate entry
-- Slave_IO_Running: Yes
-- Slave_SQL_Running: No
-- Last_SQL_Error: Could not execute Write_rows event;
-- Duplicate entry '12345' for key 'PRIMARY'
根因:主从数据不一致(应用绕过主库直接写从库、跳过错误等)。
修复:
-- 1. 跳过单条错误(GTID 模式)
STOP SLAVE;
SET GTID_NEXT = '3E11FA47-71CA-11E1-9E33-C80AA9429562:12345';
BEGIN; COMMIT;
SET GTID_NEXT = 'AUTOMATIC';
START SLAVE;
-- 2. File-Position 模式
STOP SLAVE;
SET GLOBAL sql_slave_skip_counter = 1;
START SLAVE;
-- 3. 彻底修复(推荐)
pt-table-sync --execute --sync-to-master h=replica,u=sync_user,p='xxx' \
--databases=mydb --tables=orders
案例三:主库 binlog dump 线程异常断开
-- 主库 error log
[ERROR] Binlog dump thread is killed because it is not able to send binlog
events to the slave. Error: Read timeout
根因:slave_net_timeout(默认 60s)超时、心跳未续约、网络抖动。
修复:
[mysqld]
# 主从都需配置
slave_net_timeout = 30 # 缩短超时
# 主库
binlog_cache_size = 4M
max_binlog_size = 1G
# 从库
master_heartbeat_period = 10 # 心跳周期
master_retry_count = 86400 # 重试次数
案例四:GTID 复制中断 ER_SLAVE_HAS_MORE_GTIDS_THAN_MASTER
-- 从库 Executed_Gtid_Set 包含主库不存在的 GTID
-- 常见于:主从切换后从库"跨代"恢复
修复:
-- 1. 备份主库现有数据
mysqldump --single-transaction --master-data=2 --triggers --routines \
--events --all-databases > full_backup.sql
-- 2. 从库重置 GTID 集合
RESET MASTER;
SET GLOBAL gtid_purged = '3E11FA47-71CA-11E1-9E33-C80AA9429562:1-1000';
-- 3. 重新建立复制
CHANGE MASTER TO MASTER_AUTO_POSITION=1, ...;
START SLAVE;
案例五:MGR 单主模式 PRIMARY 失联,新主选举
-- 从集群状态查
SELECT * FROM performance_schema.replication_group_members\G
-- MEMBER_STATE: ERROR / UNREACHABLE
排查:
# 查看网络端口 33061 是否可达
nc -zv node2 33061
# 查看 group_replication_local_address 配置
SHOW VARIABLES LIKE 'group_replication_local_address';
# 查看本节点 GR 日志
tail -f error.log | grep -i "group_replication"
修复:
-- 失联节点重加入
STOP GROUP_REPLICATION;
SET GLOBAL group_replication_recovery_get_public_key = 1;
START GROUP_REPLICATION;
-- 或重置后重新加入集群
RESET MASTER;
SET GLOBAL group_replication_allow_local_disjoint_gtids_join = 1;
START GROUP_REPLICATION;
通用排查方法论:
| 步骤 | 操作 |
|---|---|
| 1. 明确现象 | 延迟?中断?数据不一致? |
2. 查看 SHOW SLAVE STATUS\G | 定位 IO/SQL 线程状态、错误码、延迟时间 |
| 3. 检查错误日志 | /var/log/mysql/error.log GR 段 |
| 4. 检查网络连通性 | telnet master 3306、端口可达性、丢包率 |
| 5. 验证数据一致性 | pt-table-checksum 定期跑 |
| 6. 评估修复影响 | 跳过错误 vs 重新搭建复制 vs pt-table-sync 修复 |
预防性措施清单:
- 启用
super_read_only防止从库误写 - 监控
Seconds_Behind_Master+pt-heartbeat双指标 - 定期演练主从切换(季度故障演练)
- 启用增强半同步 + GTID 组合
- 关键业务启用延迟从库 + binlog 闪回工具