mysql中三大日志文件的写入/刷盘时机

在 MySQL(InnoDB)事务执行过程中,Binlog、Redo Log、Undo Log 的写入与刷盘时机紧密配合,共同保障 ACID 特性主从一致性 。它们的协作核心是 两阶段提交(2PC)

下面从 写入时机、刷盘时机、执行顺序 三个维度详细说明。

一、总体流程:两阶段提交(2PC)

为保证 崩溃恢复一致性主从复制一致性,MySQL 采用如下顺序:

💡 关键点:Redo Log 先 Prepare,Binlog 后写,最后 Redo Log Commit

二、各日志的写入与刷盘时机详解

|--------------|--------------------------------------------------------|----------------------------------------------------------------------------------------------------|----------------------------|
| 日志类型 | 写入时机 | 刷盘时机 | 是否强制落盘? |
| Undo Log | DML 执行时 (修改数据前) → 写入 Undo Page(在 Buffer Pool 中) | 异步刷盘 → 随 Undo Page 脏页由后台线程刷入磁盘 | ❌ (持久性由 Redo Log 保证) |
| Redo Log | DML 执行时 → 写入 Redo Log Buffer(内存) | 在事务 Prepare/Commit 阶段 → 由 innodb_flush_log_at_trx_commit 控制: • =1:每次 COMMIT 强制刷盘 • =0/2:异步刷盘 | ✅ 是(默认) (WAL 机制要求) |
| Binlog | 事务 COMMIT 时 → 先写入 Binlog Cache,再写入 Binlog File(内存) | 在事务 COMMIT 阶段 → 由 sync_binlog 控制: • =1:每次事务刷盘 • =0:由 OS 决定 • =N:每 N 个事务刷一次 | ⚠️ 可配置 (生产建议 =1) |


三、详细步骤分解(以 UPDATE + COMMIT 为例)

步骤 1:执行 DML(如 UPDATE t SET x=1 WHERE id=1

  • InnoDB:
    • 生成 Undo Log(记录旧值),存入 Undo Page(Buffer Pool)
    • 修改聚簇索引页(标记为脏页)
    • 生成 Redo Log (物理修改),写入 Redo Log Buffer

此时:Undo 和 Redo 都在内存,未刷盘


步骤 2:执行 COMMIT → 触发两阶段提交

▶ 阶段 1:Prepare 阶段(InnoDB)
  • InnoDB 将 Redo Log Buffer 中的日志 刷盘(含事务状态 = PREPARE)
  • 返回成功给 Server 层

此时 Redo Log 已持久化(若 innodb_flush_log_at_trx_commit=1**)**

▶ 阶段 2:Commit 阶段(Server 层)
  • Server 层将事务的 Binlog 写入 Binlog File(内存)
  • 根据 sync_binlog 决定是否 刷 Binlog 到磁盘
    • sync_binlog=1 → 立即 fsync() 刷盘
  • 然后通知 InnoDB 提交
▶ 阶段 3:InnoDB 最终提交
  • InnoDB 写一条 Redo Log(状态 = COMMIT)
  • 根据配置决定是否立即刷盘(通常可延迟)

至此,事务完成


四、崩溃恢复如何保证一致性?

MySQL 通过 Redo Log + Binlog 对账 实现:

|------------------------------------|--------------------|
| 场景 | 恢复动作 |
| 只有 Redo Log(PREPARE),无 Binlog | → 事务未完整提交 → 回滚 |
| Redo Log(PREPARE) + Binlog 都存在 | → 事务已完整提交 → 提交 |
| Redo Log(COMMIT)存在 | → 直接提交 |

💡 这确保了:Binlog 记录的事务 = InnoDB 实际提交的事务,主从不会数据不一致。


五、三者的角色总结

|--------------|--------|-------------|--------------|------------------|
| 日志 | 层级 | 作用 | 刷盘要求 | 生命周期 |
| Undo Log | InnoDB | 回滚 + MVCC | ❌ 异步 | 被 Purge 线程清理 |
| Redo Log | InnoDB | 崩溃恢复 + WAL | ✅ 默认强制 | Checkpoint 后循环覆盖 |
| Binlog | Server | 主从复制 + PITR | ⚠️ 可配置(建议强制) | 手动或自动过期删除 |


六、关键参数配置建议(生产环境)

复制代码
# Redo Log(安全第一)
innodb_flush_log_at_trx_commit = 1

# Binlog(保证主从一致)
sync_binlog = 1
binlog_format = ROW

# 自动清理
binlog_expire_logs_seconds = 604800  # 7天

⚠️ 如果 innodb_flush_log_at_trx_commit=1sync_binlog=0
可能主从不一致(主库崩溃时 Binlog 丢失,但从库可能已收到部分日志)。


七、常见误区澄清

|-----------------------------|----------------------------------------------|
| 误区 | 正确理解 |
| "Binlog 在 DML 时就写" | ❌ 只在 COMMIT 时 写(保证原子性) |
| "Undo Log 需要刷盘才能 COMMIT" | ❌ 不需要,靠 Redo Log 保证其可恢复 |
| "Redo Log 和 Binlog 谁先谁后无所谓" | ❌ 必须 Redo Prepare → Binlog → Redo Commit |
| "关闭 Binlog 能提升性能" | ✅ 能,但失去主从和 PITR 能力 |


总结:三者的写入与刷盘顺序

|---------------------|------------------------|------------------------------------------------|
| 阶段 | 操作 | 日志行为 |
| 1. DML 执行 | UPDATE/INSERT/DELETE | • Undo Log 写入内存 • Redo Log 写入内存(Redo Buffer) |
| 2. COMMIT 开始 | 两阶段提交启动 | --- |
| 3. Prepare | InnoDB 准备提交 | • Redo Log 刷盘(PREPARE) |
| 4. Write Binlog | Server 层记录 | • Binlog 写入文件(内存) • 按 sync_binlog 决定是否刷盘 |
| 5. Commit | InnoDB 最终提交 | • Redo Log 写 COMMIT(可延迟刷盘) |

💡 记住口诀
"改数据 → 记 undo → 生 redo → prepare redo → 写 binlog → commit redo"

这种精密协作,使得 MySQL 既能 高性能写入 ,又能 强一致、高可用、可恢复

相关推荐
weixin_462446232 小时前
【原创实践】使用 Docker 在 MySQL 容器中批量导出所有数据库
数据库·mysql·docker
苹果醋32 小时前
24.记录Vue项目iview组件日期获取时间少一天
java·运维·spring boot·mysql·nginx
HunterMichaelG2 小时前
【MySQL】KylinV10 ARM 服务器上编译MySQL 5.7 XtraBackup
mysql·arm·xtrabackup
源代码•宸12 小时前
goframe框架签到系统项目(BITFIELD 命令详解、Redis Key 设计、goframe 框架教程、安装MySQL)
开发语言·数据库·经验分享·redis·后端·mysql·golang
思成不止于此14 小时前
【MySQL 零基础入门】事务精讲(二):ACID 特性与并发问题
数据库·笔记·学习·mysql
Boilermaker199214 小时前
[MySQL] 初识 MySQL 与 SQL 基础
数据库·mysql
Boilermaker199215 小时前
[MySQL] 服务器架构
数据库·mysql·架构
qualifying16 小时前
MySQL——表的操作
数据库·mysql
学Linux的语莫17 小时前
mysql主从同步(复制)搭建
数据库·mysql