本页内容受版权保护 · 已添加水印 · 禁止任何形式转载
主从复制与高可用 · 复制原理

MySQL 主从复制的整体流程?(binlog dump、IO thread、relay log、SQL thread)

The overall process of MySQL master-slave replication? (binlog dump, IO thread, relay

答案语言

考察要点

这道题面试官想看你是否深入理解 MySQL 异步复制的完整数据流和核心组件。考察点包括:

  1. 核心流程的掌握:你是否能清晰描述从 Master 产生变更到 Slave 应用变更的每一步,并准确说出 binlog、log dump 线程、I/O 线程、relay log、SQL 线程 各自的角色和交互关系。
  2. 关键机制的理解:你是否明白复制过程中的关键设计,如 relay log 的缓冲作用、GTID 的优势、半同步复制的权衡。
  3. 问题定位与优化能力:你是否知道主从延迟(Replication Lag)产生的原因,并能提出有效的监控和优化方案,如并行复制(MTS)。

核心概念

MySQL 主从复制是一个异步过程,核心目标是让从库(Slave/Replica)的数据与主库(Master/Source)保持最终一致。其标准流程涉及三大线程和两种日志。

整体流程图示

mermaid
1graph TD
2 subgraph Master (主库)
3 A[1. Client执行DML/DDL] --> B{Storage Engine};
4 B -- 提交事务 --> C[2. 写入Binlog];
5 D[3. Log Dump 线程] -- 读取Binlog --> E((Network));
6 end
7
8 subgraph Slave (从库)
9 F[4. I/O 线程] -- 请求并接收Binlog --> E;
10 F --> G[5. 写入Relay Log];
11 H[6. SQL 线程] -- 读取Relay Log --> I[7. 重放(Replay)SQL];
12 I --> J{Storage Engine};
13 end
14
15 style Master fill:#f9f,stroke:#333,stroke-width:2px
16 style Slave fill:#ccf,stroke:#333,stroke-width:2px

核心组件详解

  1. 二进制日志 (Binary Log / Binlog)

    • 作用:主库上以二进制格式记录所有修改数据库数据的事件(DML、DDL)。它是复制的基础。
    • 格式 (binlog_format):
      • STATEMENT:记录原始的 SQL 语句。优点是日志量小,缺点是某些非确定性函数(如 NOW(), UUID())或 LIMIT 无 ORDER BY 的语句可能导致主从数据不一致。
      • ROW:记录每一行数据的变更前(before-image)和变更后(after-image)的值。优点是能保证数据绝对一致,缺点是日志量较大,尤其在 UPDATE 或 DELETE 影响大量行时。MySQL 5.7.7+ 版本后,ROW 格式为默认格式,因为它在数据一致性上更可靠。
      • MIXED:混合模式。MySQL 会根据 SQL 语句的类型自动选择 STATEMENT 或 ROW 格式。
  2. Log Dump 线程

    • 位置:主库。
    • 作用:当从库连接主库时,主库会为该从库创建一个 Log Dump 线程。该线程负责读取主库的 Binlog 事件,并根据从库 I/O 线程请求的坐标(Binlog 文件名 + Position)发送给从库。
  3. I/O 线程 (Receiver Thread)

    • 位置:从库。
    • 作用:负责与主库建立连接,向主库的 Log Dump 线程请求指定位置之后的 Binlog。接收到 Binlog 事件后,将其顺序写入到从库本地的 Relay Log(中继日志)中。
  4. 中继日志 (Relay Log)

    • 位置:从库。
    • 作用:本质上是 I/O 线程从主库拉取回来的 Binlog 的一个本地副本。它的存在实现了读写分离:I/O 线程负责网络数据接收和磁盘写入,SQL 线程负责从本地磁盘读取和执行。这避免了 SQL 线程的执行速度受网络波动的影响,也减轻了主库的压力(Binlog 只需被拉取一次)。
  5. SQL 线程 (Applier Thread)

    • 位置:从库。
    • 作用:读取 Relay Log 中的事件,并将其在从库上重放(Apply),从而实现数据的同步。在单线程复制模式下,SQL 线程是串行执行的,这也是造成主从延迟的主要瓶颈。
  6. 状态记录文件/表

    • master.info (MySQL 8.0.22 前) / mysql.slave_master_info 表:记录从库连接主库所需的信息(主库地址、端口、用户名、密码)以及 I/O 线程当前读取到的主库 Binlog 的坐标(文件名和位置)。
    • relay-log.info (MySQL 8.0.22 前) / mysql.slave_relay_log_info 表:记录 SQL 线程当前已经执行完的 Relay Log 的坐标。
    • 版本差异:在老版本中,这些信息存储在文件中,存在 crash-unsafe 的风险。MySQL 5.6+ 引入了 master_info_repository=TABLE 和 relay_log_info_repository=TABLE 参数,允许将这些状态信息存储在 InnoDB 表中,利用事务特性保证了 crash-safe。MySQL 8.0+ 默认使用表存储。

常见低分回答

  1. 流程混淆:将 I/O 线程和 SQL 线程的功能搞混,例如说“I/O 线程负责执行 SQL”,或者完全忽略 Relay Log,描述成“I/O 线程直接从主库读取 SQL 并执行”。
  2. 忽略 Binlog 格式:当被问到复制可能出现的问题时,想不到 STATEMENT 格式下的非确定性函数会导致数据不一致,这表明对 Binlog 的理解不够深入。
  3. 对延迟原因的理解过于肤浅:只回答“网络慢”或“机器性能差”,而没有点出核心瓶颈——单线程的 SQL 线程在处理主库并发写入时,由于需要串行回放,必然会产生延迟。
  4. 描述过于简单:“主库把数据同步给从库”,这种回答没有任何技术含量,无法体现专业性。需要明确说出线程、日志、数据流转的细节。
  5. 不知道 GTID:在讨论故障转移或多级复制时,如果不知道 GTID (Global Transaction ID),说明知识体系还停留在比较旧的 MySQL 版本,无法应对现代高可用架构的讨论。

工程实践与优化

  1. 主从延迟(Replication Lag)监控与定位

    • 监控:通过 SHOW SLAVE STATUS\G 命令查看 Seconds_Behind_Master 的值。注意:这个值在某些情况下可能不准(例如网络抖动)。更精确的监控可以使用 Percona 的 pt-heartbeat 工具,它通过在主库插入一个时间戳表,然后在从库查询该表来计算真实延迟。
    • 定位:延迟通常发生在 SQL 线程。如果 Exec_Master_Log_Pos 与 Read_Master_Log_Pos(通过 SHOW SLAVE STATUS 查看)差距很大,说明 I/O 线程正常,但 SQL 线程执行慢。可以通过 SHOW PROCESSLIST 查看从库上是否有慢查询或大事务正在执行。
  2. 并行复制(Multi-Threaded Slave, MTS)

    • 目的:解决单 SQL 线程瓶颈,提升从库应用 Relay Log 的速度。
    • MySQL 5.6:引入了基于 DATABASE 的并行复制,即不同库的事务可以并行应用。但如果压力集中在单一数据库,效果不佳。
    • MySQL 5.7:引入了更强大的基于 LOGICAL_CLOCK 的并行复制。主库在生成 Binlog 时,会为可以并行执行的事务打上相同的 last_committed 值。从库的 coordinator 线程根据这个值将事务分发给多个 worker 线程并行执行,大大提升了复制性能。通过设置 slave_parallel_workers > 0 和 slave_parallel_type = LOGICAL_CLOCK 开启。
    • MySQL 8.0:进一步增强,引入了 WRITESET 模式。它基于事务修改的行(主键)来判断事务是否可以并行,即使是同一 schema 下的事务,只要不修改相同的行,就可以并行执行,并行度更高。
  3. 半同步复制(Semi-Synchronous Replication)

    • 目的:在异步复制和全同步复制之间取得平衡,提升数据一致性。
    • 流程:主库提交事务后,不会立即返回给客户端,而是等待至少一个从库确认已接收到该事务的 Binlog 事件并写入 Relay Log 后,才返回成功。
    • 权衡:
      • 优点:在主库发生宕机时,能保证至少有一个从库拥有最新的数据,为无损故障转移提供了可能。
      • 缺点:增加了主库事务的响应时间(RTT)。如果从库响应慢或网络故障,主库会被阻塞,直到超时(rpl_semi_sync_master_timeout)后自动降级为异步复制。
    • 版本差异:MySQL 5.7 引入了 AFTER_SYNC 模式,相比之前的 AFTER_COMMIT,它在主库 InnoDB 引擎提交前就等待从库 ACK,进一步增强了数据一致性。
  4. GTID(全局事务标识符)

    • 格式:source_id:transaction_id,在整个复制集群中唯一。
    • 优势:
      • 简化故障转移:当需要将从库指向新主库时,不再需要手动查找和设置 Binlog 文件和位置。只需 CHANGE MASTER TO ... MASTER_AUTO_POSITION=1,从库会自动从断点处开始复制。
      • 避免重复执行:从库会记录已执行的 GTID 集合,即使接收到重复的事务,也会自动跳过。
      • 高可用架构基石:MHA、Orchestrator、InnoDB Cluster 等高可用方案都强依赖 GTID。

常见追问与延伸题目

  1. 追问:如果 Seconds_Behind_Master 持续增长,你如何排查和解决?

    • 回答要点 1 (排查):
      • 首先,执行 SHOW SLAVE STATUS\G,确认是 Slave_IO_Running 还是 Slave_SQL_Running 为 No。如果是,先解决线程启动问题。
      • 如果都为 Yes,比较 Relay_Log_Space 是否持续增长,以及 Exec_Master_Log_Pos 和 I/O 线程读取的 Relay_Master_Log_File + Exec_Master_Log_Pos 之间的差距。差距大说明 SQL 线程是瓶颈。
      • 在从库上执行 SHOW PROCESSLIST,查看 SQL 线程是否正在执行一个耗时很长的 DDL 或大事务。
      • 检查从库的系统资源,如 CPU、I/O 是否有瓶颈。
    • 回答要点 2 (解决):
      • 短期:如果是一个大 DDL 阻塞,考虑在业务低峰期执行。如果是大事务,考虑在主库侧拆分。
      • 长期:
        • 开启并行复制:这是最有效的手段。在 MySQL 5.7+ 中,设置 slave_parallel_workers 为一个合理的值(如 4-16),并使用 LOGICAL_CLOCK。
        • 优化查询:在主库上导致慢的查询,在从库上回放同样会慢。确保所有写操作都有合适的索引。
        • 硬件升级:为从库配置更快的磁盘(SSD)和更强的 CPU。
        • 架构调整:如果写压力实在太大,考虑分库分表,从根本上降低单机写 QPS。
  2. 追问:半同步复制能保证数据完全不丢失吗?为什么?

    • 回答要点:不能 100% 保证。半同步复制只保证了在主库返回 COMMIT 成功给客户端之前,至少有一个从库接收到了 Binlog 并写入了 Relay Log。但存在一个极端情况:
      1. 主库事务 T1 提交。
      2. Log Dump 线程将 T1 的 Binlog 发送给从库。
      3. 从库接收成功,写入 Relay Log,并发送 ACK 给主库。
      4. 主库接收到 ACK,准备在存储引擎层提交事务 T1 并返回给客户端。
      5. 就在这一瞬间,主库宕机了。
      • 此时,客户端没有收到成功的响应,可能会重试事务。但从库上已经有了这个事务的记录。如果此时进行主从切换,新的主库(原从库)就比旧的主库多了一个事务,造成了数据不一致。MySQL 5.7 的 loss-less semi-sync 改进了这一点,但理论上的微小窗口依然存在。
  3. 追问:如果我想搭建一个一主多从的结构,其中一个从库专门用于报表分析,不希望它因为主库的 DDL 操作(如 ALTER TABLE)而长时间阻塞,该怎么办?

    • 回答要点 1 (延迟复制):可以配置这个报表从库为延迟复制。通过 CHANGE MASTER TO ... MASTER_DELAY = N(N 为秒数),让它故意延迟 N 秒应用日志。这样,如果主库执行了一个错误的 DDL 或 DML,你有 N 秒的时间在主库上修复,并在它影响到报表库之前停止复制。
    • 回答要点 2 (过滤复制):可以使用复制过滤规则(如 replicate-do-db, replicate-ignore-table 等)让报表从库只复制它关心的库或表,忽略其他不必要的变更。对于 DDL,可以考虑使用 pt-online-schema-change 或 gh-ost 这类工具在主库上进行在线 DDL,它们将 DDL 转化为对影子表的 DML 操作,对从库的影响更平滑。
    • 回答要点 3 (逻辑备库):更彻底的方案是,不使用物理复制,而是通过 Canal、Maxwell 等工具订阅主库的 Binlog,解析成结构化数据后写入专门用于分析的数据仓库(如 ClickHouse, Hive, Doris),实现真正的读写分离和异构数据同步。