MySQL 主从延迟问题全面梳理

前言 主从延迟是 MySQL 高可用架构中最高频的问题之一。很多人对延迟的理解停留在"大事务导致延迟"这个层面,遇到问题时无从下手。本文从复制链路的两个阶段出发——IO 线程和 SQL 线程——分别梳理常见延迟原因,并结合真实案例深入分析原理。 一、主从复制链路简述 理解延迟,先要清楚复制的完整链路: 主库写入事务 ↓ 主库 Dump 线程:读取 binlog 发送给从库 ↓ (网络传输) 从库 IO 线程:接收 binlog,写入 relay log ↓ 从库 SQL 线程(或并行 Worker):读取 relay log,回放事务 ↓ 从库数据与主库一致 延迟分两类: IO 延迟:从库 IO 线程落后于主库,relay log 还没接收完整 SQL 延迟:relay log 已收到,但 SQL 线程回放跟不上 用 SHOW SLAVE STATUS\G 区分: 1 2 3 4 5 6 7 8 SHOW SLAVE STATUS\G -- 判断是 IO 延迟还是 SQL 延迟: -- Master_Log_File / Read_Master_Log_Pos → IO 线程已读到的位置 -- Relay_Master_Log_File / Exec_Master_Log_Pos → SQL 线程已执行的位置 -- 如果 Read_Master_Log_Pos 远落后于主库最新位置 → IO 延迟 -- 如果 Read_Master_Log_Pos 接近主库,但 Exec_Master_Log_Pos 落后 → SQL 延迟 二、IO 线程延迟的常见原因 原因 1:网络带宽不足 原理: ...

2026年4月1日 · 6 分钟 · DBA Student

MySQL 内部两阶段提交机制深度解析

一、为什么需要两阶段提交 1.1 核心问题 MySQL 需要保证两个日志的一致性: redo log (InnoDB 引擎层) binlog (MySQL Server 层) 如果不使用两阶段提交,会导致主从数据不一致。 1.2 两个日志的作用 日志 层级 作用 格式 redo log InnoDB 引擎 崩溃恢复,保证持久性 物理日志(页修改) binlog MySQL Server 主从复制,数据备份 逻辑日志(SQL语句) 为什么不能只用一个日志? redo log 是 InnoDB 特有,其他引擎(MyISAM)没有 binlog 是 Server 层,所有引擎共享 历史原因: binlog 先存在,redo log 后加入 1.3 不用两阶段提交的后果 场景1: 先写 redo log,后写 binlog 1 UPDATE users SET balance = 900 WHERE id = 1; 执行流程: 1. 写 redo log ✅ 2. 【此时崩溃】 3. binlog 未写入 ❌ 后果: ...

2026年3月31日 · 5 分钟 · DBA Student

mysqldump 备份参数深度解析:--single-transaction 与 --master-data

前言 在 MySQL 备份实践中,mysqldump --single-transaction --master-data=2 是最常见的组合。但很多 DBA 只知道"这样用不锁表",却不清楚底层原理。今天我们深入剖析这两个参数的工作机制,以及为什么它们必须配合使用。 一、MVCC 可见性规则(理论基础) 在理解 --single-transaction 之前,必须先掌握 InnoDB 的 MVCC 机制。 1.1 Read View 结构 当事务执行 START TRANSACTION WITH CONSISTENT SNAPSHOT 时,InnoDB 会创建一个 Read View: 1 2 3 4 5 6 7 struct read_view_t { trx_id_t m_low_limit_id; // 系统中尚未分配的最小事务ID(当前最大事务ID + 1) trx_id_t m_up_limit_id; // 活跃事务列表中的最小事务ID trx_id_t m_creator_trx_id; // 创建此 Read View 的事务ID trx_id_t *m_ids; // 创建 Read View 时的活跃事务ID数组(降序) ulint m_n_trx_ids; // 活跃事务数量 }; 注意:InnoDB 的命名反直觉 m_low_limit_id 虽然叫 “low limit”,但实际是最大值(下一个要分配的事务ID) m_up_limit_id 虽然叫 “up limit”,但实际是最小值(最小活跃事务ID) 1.2 可见性判断规则 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 def is_visible(row_trx_id, read_view): # 规则1:如果是当前事务自己修改的,可见 if row_trx_id == read_view.m_creator_trx_id: return True # 规则2:如果行的事务ID < m_up_limit_id(最小活跃事务ID),说明在 Read View 创建前已提交,可见 if row_trx_id < read_view.m_up_limit_id: return True # 规则3:如果行的事务ID >= m_low_limit_id(下一个要分配的ID),说明在 Read View 创建后才开始,不可见 if row_trx_id >= read_view.m_low_limit_id: return False # 规则4:如果在 [m_up_limit_id, m_low_limit_id) 区间内 # 需要检查是否在活跃事务列表 m_ids 中 if row_trx_id in read_view.m_ids: return False # 在活跃列表中,说明创建 Read View 时未提交,不可见 else: return True # 不在活跃列表中,说明已提交,可见 可见性判断示例: ...

2026年3月29日 · 6 分钟 · DBA Student

tpmC、tpm、tps — 数据库性能指标的定义与换算

三个指标的定义 在数据库性能评估中,经常会遇到 tpmC、tpm、tps 这三个指标,它们的含义如下: 指标 全称 含义 tpmC Transactions Per Minute (TPC-C) 每分钟处理的新订单事务数(TPC-C 基准) tpm Transactions Per Minute 每分钟处理的总事务数 tps Transactions Per Second 每秒处理的总事务数 注意区别:tpmC 只统计新订单,tpm 和 tps 统计所有类型的事务。 TPC-C 基准测试的事务模型 tpmC 来自 TPC-C 基准测试。TPC-C 模拟的是一个完整的订单处理系统,包含 5 种事务类型: 事务类型 占比 New Order(新订单) 45% Payment(支付) 43% Order Status(订单查询) 4% Delivery(发货) 4% Stock Level(库存查询) 4% tpmC 只统计其中的 New Order 事务,但系统实际上同时在处理其他 4 种事务。这就是换算公式中 0.45 这个系数的来源。 换算公式 1 tpmC = (1 / 0.45) / 60 ≈ 0.037 tps 逐步推导 假设系统性能为 1 tpmC,即每分钟处理 1 笔新订单: ...

2026年3月26日 · 1 分钟 · DBA Student

MySQL 内部两阶段提交(2PC)深度解析

MySQL 内部两阶段提交(2PC)深度解析 一、背景与问题起源 MySQL 的存储架构分为两层: Server 层:负责 SQL 解析、优化、执行,以及 binlog 的写入 引擎层(InnoDB):负责数据的实际存储,以及 redo log 的写入 这两层各自维护一套日志体系,当一个事务提交时,需要同时保证两套日志的一致性。若没有协调机制,极易造成数据不一致。 为什么两个日志会不一致? 假设没有 2PC,先写 redo log,再写 binlog: [事务 T1 执行 UPDATE] → 写入 redo log(状态:commit) → MySQL 崩溃 💥 → binlog 未写入 恢复后: InnoDB 重放 redo log,T1 数据存在 从库通过 binlog 同步,T1 不存在 主从数据不一致! 假设没有 2PC,先写 binlog,再写 redo log: [事务 T1 执行 UPDATE] → 写入 binlog → MySQL 崩溃 💥 → redo log 未写入 恢复后: InnoDB 没有 redo log,T1 回滚(数据不存在) 从库通过 binlog 同步,T1 被执行 主从数据不一致! 正是因为这两种情况都会造成主从不一致,MySQL 引入了内部两阶段提交(Internal 2PC)。 ...

2026年3月18日 · 3 分钟 · DBA Student