数据库三大日志深度解析:Redo Log、Binlog、Undo Log 如何守护你的数据

本文涉及的产品
RDS MySQL DuckDB 分析主实例,集群系列 4核8GB
RDS AI 助手,专业版
PolarDB Agent Express,2核4GB
简介: 本文由“数据库小学妹”带你厘清MySQL三大核心日志:Redo Log(引擎层物理日志,保障crash-safe)、Undo Log(支撑回滚与MVCC)和Binlog(Server层逻辑日志,用于复制与恢复),详解WAL机制与两阶段提交原理,助你真正理解事务安全底层逻辑。

📌 今日关键词:Redo Log、Binlog、Undo Log、WAL、两阶段提交、crash-safe

大家好,我是 数据库小学妹 👋

之前我们学过 MVCC,知道 Undo Log 可以实现数据的"时光回溯"。但很多同学问:"MySQL到底有几种日志?它们各自管什么事?为什么要有这么多日志而不是一个搞定?"

说实话,刚开始我也一头雾水——明明都是记录变更,为什么要搞 Redo Log、Binlog、Undo Log 三个概念?直到我真正理解了它们的分工,才发现这是数据库设计中最精妙的部分之一。

今天用一条 UPDATE 语句走一遍流程,把这三个东西的关系理清楚。


一、三种日志分工

日志类型 归属 作用 删除策略
Redo Log InnoDB 引擎 崩溃恢复(crash-safe) 循环覆盖
Undo Log InnoDB 引擎 事务回滚 + MVCC 事务结束后可被 purge
Binlog Server 层 主从复制 + 数据恢复 手动清理或按策略归档

记住一句话:Redo Log 负责"死了能活",Undo Log 负责"错了能悔",Binlog 负责"丢了能找"


二、Redo Log —— 宕机后靠它恢复数据

什么是 Redo Log?

想象一下这个场景:你刚给某个用户充值了 100 元,UPDATE 语句执行到一半,服务器突然断电了。数据会怎样?

如果不做任何处理,这笔账就丢了——因为内存里的修改还没来得及刷到磁盘上。

Redo Log 的作用就是:即使宕机,已提交的事务也不会丢失。

Redo Log 的核心特点

1. 环形文件结构

redo log000001 → redo log000002 → ... → redo log000010 → (回到开头) redo log000001

Redo Log 是固定大小的环形文件组(默认总共 1GB),写到末尾就从头开始覆盖。这种设计保证了日志不会因为长期运行而撑爆磁盘。

2. 物理日志

Redo Log 记录的是"在某个数据页上做了什么修改",比如:

[LSN=100] 在 page_id=100 的 offset=4096 处写入 value=100 元

这种物理级别的记录让恢复速度非常快——直接按日志重放就行,不用重新解析 SQL。

3. WAL 技术(Write-Ahead Logging)

核心原则:任何修改必须先写 Redo Log,才能认为事务成功。

正常流程(有风险):
  修改内存 buffer pool → 异步刷盘 → 告诉用户"成功了"
  ↑ 如果这里宕机,数据就丢了

WAL 流程(安全):
  写 Redo Log 并刷盘 → 修改内存 buffer pool → 告诉用户"成功了"
  ↑ 即使宕机,重启后通过 Redo Log 能恢复

查看 Redo Log 配置

-- 查看 Redo Log 大小和数量
SHOW VARIABLES LIKE 'innodb_log_file_size';    -- 单个文件 256M
SHOW VARIABLES LIKE 'innodb_log_files_in_group'; -- 4 个文件,共 1GB

-- 查看 checkpoint 位置(决定了能回收多少 log)
SHOW ENGINE INNODB STATUS\G

三、Undo Log —— 回滚和版本链

Undo Log 我们之前学 MVCC 时提过,今天从更底层角度再拆解一遍。

Undo Log 的两个职责

职责 1:事务回滚

你执行了一个错误操作,比如:

BEGIN;
UPDATE accounts SET balance = 0 WHERE user_id = 123;
-- 哎呀手滑了!
ROLLBACK;

数据库怎么知道你原来的余额是多少?靠的就是 Undo Log 里保存的"旧值"。

Undo Log 记录的格式类似这样:

[事务 A] 将 accounts 表中 user_id=123 的 balance 从 500 改为 0
         ↓ 反向操作就是
[回滚]   将 accounts 表中 user_id=123 的 balance 从 0 改回 500

职责 2:MVCC 版本链

同一个表的同一行数据,不同事务看到的版本可能不一样:

时间线:
T1: 事务 A 把 balance 从 100 改成 200(undo log 指向旧版本)
T2: 事务 B 把 balance 从 200 改成 300(undo log 指向 T1 的版本)
T3: 事务 C 查询,如果是 RC 级别看到 300,如果是 RR 级别且早于 T1 则看到 100

每一行数据的 undo log 连成一条"版本链",越新的数据在链表头部,越旧的在后面。

Undo Log vs Redo Log

特性 Undo Log Redo Log
存储位置 表空间内(系统表空间或独立 undo 表空间) 独立的 redo log 文件
是否循环使用 否,事务结束后被 purge 线程清理 是,checkpoint 后可覆盖
记录内容 逻辑日志(反向日志) 物理日志(数据页修改)
主要用途 回滚 + MVCC 崩溃恢复

四、Binlog —— Server 层的日志文件

Binlog 是什么?

Binlog(Binary Log)是 MySQL Server 层的日志,所有引擎(InnoDB、MyISAM 等)都会产生。

它记录的是 SQL 语句的逻辑变更,比如:

# At 123456789
#260521 10:30:00 server id 1  end_log_pos 123456789 Query
SET timestamp=1684658400;
UPDATE accounts SET balance = 100 WHERE id = 1

Binlog 的三种格式

-- 查看当前 binlog 格式
SHOW VARIABLES LIKE 'binlog_format';
格式 记录内容 优点 缺点
STATEMENT 原始 SQL 语句 体积小 某些函数(如 NOW())主从不一致
ROW 每行变更的前后镜像 精确可靠 DDL 或批量更新时体积大
MIXED 混合模式,自动切换 平衡两者 逻辑复杂

生产环境推荐用 ROW 模式,虽然体积大点,但最安全。

Binlog 的独特价值

1. 数据恢复(Point-in-Time Recovery)

误删了一张表?可以通过 Binlog 恢复到任意时间点:

# 停止 MySQL
# 恢复全量备份
# 回放 Binlog 到删除前的时间点
mysqlbinlog --stop-datetime="2026-05-21 10:29:59" binlog.000001 | mysql -u root -p

2. 主从复制

从库通过读取主库的 Binlog,保持数据同步——这是我们之前学主从复制时的基础。

Binlog 管理命令

-- 查看 Binlog 列表
SHOW BINARY LOGS;

-- 清空过期 Binlog(谨慎操作!)
PURGE BINARY LOGS BEFORE '2026-05-01 00:00:00';

-- 强制刷新 Binlog 到新文件
FLUSH LOGS;

-- 关闭/开启 Binlog(一般不用)
SET GLOBAL log_bin = 0;

五、一条 UPDATE 语句的执行流程

现在看执行一条 UPDATE 时,三个日志怎么协作:

UPDATE accounts SET balance = balance + 100 WHERE user_id = 1;

执行流程

┌─────────────────────────────────────────────────────────────┐
│  1. 检查 Buffer Pool,找到对应的数据页                        │
│     ↓                                                        │
│  2. 生成 Undo Log(记录旧值 balance=500)                    │
│     ↓                                                        │
│  3. 修改内存中的数据页(balance 变成 600)                     │
│     ↓                                                        │
│  4. 写 Redo Log(记录"page X 的 offset Y 修改为 600")          │
│     ↓                                                        │
│  5. 写 Binlog(记录"UPDATE accounts...")                    │
│     ↓                                                        │
│  6. 两阶段提交:先准备(prepare),再提交(commit)           │
│     ↓                                                        │
│  7. 返回给客户端:"Query OK, 1 row affected"                 │
└─────────────────────────────────────────────────────────────┘

关键点:两阶段提交

为什么不写完 Redo Log 和 Binlog 就直接提交,而要分两个阶段?

场景假设

  • 写完 Redo Log 并提交,然后宕机
  • 结果:Redo Log 里有这条记录,但 Binlog 没有
  • 后果:主库恢复了,但从库没有这条变更记录→数据不一致!

两阶段提交的解决方案

阶段 1(Prepare):
  写 Redo Log,标记为"prepare"状态
  ↓
阶段 2(Commit):
  写 Binlog 并刷盘
  写 Redo Log 的 commit 标记
  ↓
事务完成

如果中途宕机,重启后通过检查 Redo Log 的状态来决定是否恢复:

  • 只有 prepare 标记 → 不恢复(说明 Binlog 没写完)
  • 有 commit 标记 → 恢复

六、实战:监控与调优

1. 检查 Redo Log 使用情况

-- 查看 checkpoint 进度
SHOW ENGINE INNODB STATUS\G
# 搜索 "LOG" 部分,关注:
# - Log sequence number(当前 LSN)
# - Checkpoint age(距离 checkpoint 还有多远)

Checkpoint age 过大说明刷盘跟不上写入速度,可以考虑:

  • 增大 innodb_log_file_size
  • 优化写入负载

2. Undo Log 膨胀排查

长事务会导致 Undo Log 无法被清理:

-- 查找长事务
SELECT 
    trx.trx_id,
    trx.trx_state,
    trx.trx_started,
    TIMESTAMPDIFF(SECOND, trx.trx_started, NOW()) as running_seconds
FROM information_schema.innodb_trx trx
WHERE TIMESTAMPDIFF(SECOND, trx.trx_started, NOW()) > 60;

发现有长事务要尽快定位原因,通常是因为业务代码里事务包裹的范围太大。

3. Binlog 大小监控

-- 查看所有 binlog 总大小
SELECT 
    FILE_NAME as log_name,
    FILE_LENGTH as size_bytes,
    ROUND(FILE_LENGTH / 1024 / 1024, 2) as size_mb
FROM information_schema.FILES 
WHERE FILE_TYPE = 'REDO LOG' OR FILE_NAME LIKE '%binlog%';

-- 或者直接从系统表查
SHOW BINARY LOGS;

Binlog 占用太大时可以调整保留策略:

# my.cnf
[mysqld]
expire_logs_days = 7           # 7 天后自动删除
max_binlog_size = 100M         # 单个 binlog 最大 100M

七、常见问题速答

Q1: Redo Log 和 Binlog 的区别?

A: Redo Log 是 InnoDB 引擎层的物理日志,用于崩溃恢复,循环使用;Binlog 是 Server 层的逻辑日志,用于主从复制和数据恢复,不会自动覆盖。

Q2: 为什么要两阶段提交?

A: 保证 Redo Log 和 Binlog 的一致性。如果一个事务在 Redo Log 中提交了但 Binlog 没写完,单阶段提交会导致主从数据不一致。

Q3: Undo Log 什么时候被清除?

A: 当事务不需要再读旧版本时,Purge 线程会在后台清理 Undo Log。具体来说,RR 级别下事务结束后可清理,RC 级别下每条 SELECT 后可清理不再需要的旧版本。

Q4: Redo Log 满了怎么办?

A: Redo Log 是环形文件,满了就从头开始覆盖。但有个前提:checkpoint必须已经追赶上来,即对应的脏页已经刷回磁盘。如果写入速度太快导致 checkpoint 追不上,MySQL 会挂起写入直到有空间。


八、今日学习心得

  1. Redo Log 是 InnoDB 的"保险箱",确保宕机后数据不丢失
  2. Undo Log 是事务的"后悔药",同时支撑 MVCC 的版本链
  3. Binlog 是 Server 层的"审计日志",用于主从复制和时间点恢复
  4. 两阶段提交是保证 Redo Log 和 Binlog 一致性的关键
  5. 理解这三种日志,才能真正掌握 MySQL 的事务机制

👋 我是 数据库小学妹 一个用设计师思维学数据库的转行人。我们一起,把复杂的技术变得简单有趣!💕


本文示例基于 MySQL 8.0 + InnoDB。

相关文章
|
1天前
|
编解码 自然语言处理 文字识别
HiDream-O1开源:8B参数像素级统一Transformer
HiDream-O1-Image是HiDream.ai开源的8B参数像素级统一生成模型,摒弃VAE与分离文本编码器,首创UiT架构实现文本、图像、任务条件在共享token空间端到端联合建模。支持2048×2048高清生成、多镜头/多语言渲染、指令编辑与主体个性化,在GenEval等基准刷新SOTA。含50步未蒸馏版与28步Dev加速版,并集成推理驱动提示代理。
350 0
|
24天前
|
SQL 关系型数据库 MySQL
MySQL慢查询诊断实战:从10秒到0.1秒,我的5步排障法
数据库小学妹分享慢查询优化实战:从10秒降至0.08秒!详解「发现→收集→分析→优化→验证」5步排障法,覆盖慢日志配置、EXPLAIN进阶、索引失效场景、JOIN与分页优化等核心技巧,附真实案例与速查表。
|
2月前
|
SQL 关系型数据库 MySQL
EXPLAIN 执行计划:一眼看穿你的SQL慢在哪
数据库小学妹带你轻松掌握SQL性能诊断!通过EXPLAIN查看执行计划,精准识别索引失效、全表扫描(ALL)、key为NULL等瓶颈。聚焦type、key、rows等6个关键字段,结合实战案例与避坑指南(如函数滥用、最左前缀破坏),让优化有的放矢。学完即用,告别盲目调优!
|
1天前
|
人工智能 安全 关系型数据库
RDS Agent可观测能力正式邀测!全面支持Qoder、Codex、Claude Code、OpenClaw等主流研发Agent
阿里云RDS Agent可观测平台正式发布!面向Qoder、Codex等多类AI Agent,提供统一接入、Token/成本归因、ROI分析、风险回溯与全链路Trace下钻能力,基于RDS MySQL+DuckDB列式分析底座,助力团队从“使用Agent”迈向“治理Agent”。
181 6
|
1天前
|
SQL 安全 Java
SQL注入防御指南:从漏洞原理到实战防护,我的安全避坑血泪史
数据库小学妹带你秒懂SQL注入防护!📌核心关键词:SQL注入、参数化查询、预编译、WAF。用餐厅点餐类比攻击原理,详解布尔盲注、时间延迟、联合查询三种手法;手把手演示Python/Java/PHP/C#安全写法;构建“参数化(必选)+输入校验(辅助)+最小权限(兜底)”三层防御体系,并推荐WAF、ORM与扫描工具。安全无小事,从杜绝字符串拼接开始!
|
24天前
|
关系型数据库 MySQL 测试技术
JOIN、IN、EXISTS谁最快?实测三种写法性能差异与执行计划深度剖析
本文用MySQL 8.0实测拆解`IN`/`EXISTS`/`JOIN`子查询性能:从执行计划、半连接优化、临时表开销等底层原理出发,结合10万+100万数据实测(`EXISTS`最快95ms),给出三条选型铁律——告别盲从“最佳实践”,只选最适配业务与数据的写法!
|
1天前
|
数据采集 监控 网络协议
STM32 + MODBUS RTU + RS485 实现方案
STM32 + MODBUS RTU + RS485 实现方案
|
24天前
|
运维 容灾 关系型数据库
数据库容灾配置全攻略:同城容灾vs两地三中心,RPO、RTO一篇讲透
数据库小学妹带你轻松搞懂容灾核心概念!本文用通俗语言解析同城容灾、两地三中心、高可用集群,厘清RPO(数据丢失容忍)与RTO(恢复时效)关键指标,对比方案选型要点,并揭秘同步/异步复制、自动切换、读写分离等实战技术,附避坑指南与演练建议。
|
1天前
|
人工智能 Linux API
告别多账号切换!用 9Router 一键把所有 AI 模型变成一个 API,Cursor/Cline 直接起飞
还在为 AI 客户端配置混乱、多账号来回切换、Token 消耗过高而头疼?最近爆火的开源项目 9Router 彻底解决了这些痛点!它能把 OpenAI、Claude、Gemini、Copilot、Ollama 等所有主流 AI 服务,统一成一个标准的 OpenAI API 接口,不管是 Cursor、Cline 还是 Cherry Studio、OpenWebUI,直接用一个地址就能调用所有模型,还自带 Token 压缩,大幅降低成本!本文从 0 开始带你用 Docker 一键部署,全程干货无废话。
473 0
告别多账号切换!用 9Router 一键把所有 AI 模型变成一个 API,Cursor/Cline 直接起飞