跳转到内容

MySQL Replication 面试题

12 道题
分类
数据库
子分类
mysql
题目数
12 道
已阅读 0 / 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 支持三种格式:STATEMENTROWMIXED

三种格式对比:

维度STATEMENTROWMIXED
记录内容原始 SQL 语句行的实际变更前/后镜像默认 STATEMENT,特定场景切换为 ROW
binlog 大小最小(仅记录 SQL)最大(每行变更都记录)中等
数据一致性差(非确定函数、触发器问题)最强(行级一致)较好
主从延迟较低较高(大事务产生大量 row event)折中
恢复能力需上下文(时间点/位置)可逆(原始行镜像)介于两者之间
审计能力可读 SQL 文本需 binlog2sql 等工具解析部分可读
典型问题UUID()NOW()LIMITORDER 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-PositionGTID
定位方式文件名 + 偏移量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.7LOGICAL_CLOCK(基于组提交)同一主库组提交事务可并行单 schema 高并发写入
8.0WRITESET / 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 内置选主。

三种方案核心机制:

维度MHAOrchestratorMGR 内置
原理监控 + 提升最新从库 + 补齐差异 relay log拓扑感知 + Raft 协调 + 提升候选从库Paxos 多数派自动选主
数据一致性强(半同步 + relay log 补齐)强(GTID 自动协商)强(共识协议)
RTO10~30s5~15s< 5s
RPO0(半同步 Loss-less)0(GTID 强一致)0(共识提交)
切换模式手动触发 / 自动监控手动 / 计划内切换 / 故障自动切换自动
代理/路由需 VIP 漂移脚本 / ProxySQL需配合 ProxySQL / HAProxyMySQL 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-checksumpt-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 闪回工具