当前位置: 首页 > news >正文

MySQL 中 redo log、undo log 以及 bin log 的区别

在 MySQL 数据库的底层架构中,有三个至关重要的日志子系统:redo log(重做日志)、undo log(回滚日志)和 bin log(二进制日志)。它们如同数据库的 "免疫系统",分别承担着事务持久化、数据回滚、增量备份与主从复制的核心功能。本文将从存储引擎底层实现出发,结合具体原理图,深入解析三者的技术原理与核心差异。

一、redo log:InnoDB 的事务持久化基石

1. 物理日志的本质

redo log 是 InnoDB 存储引擎独有的物理日志,记录的是数据页的物理修改操作,例如 "将数据页 0x123 的第 100 字节修改为 0x45"。其核心作用是实现 WAL(Write-Ahead Logging)机制,通过先写日志再写数据的方式,保证事务的持久性(ACID 中的 D)。

2. MySQL 中两个重点概念

  • 缓冲池(buffer pool):主内存中的一个区域,里面可以缓存磁盘上经常操作的真实数据,在执行增删改查操作时,先操作缓冲池中的数据(若缓冲池没有数据,则从磁盘加载并缓存),以一定频率刷新到磁盘,从而减少磁盘 IO,加快处理速度
  • 数据页(page):是 InnoDB 存储引擎磁盘管理的最小单元,每个页的大小默认为 16KB。页中存储的是行数据

示意图如下:图中 xxx.ibd 是InooDB 文件

为什么要区分内存结构和磁盘结构呢?当然是因为操作缓存比操作磁盘快啊!!!

当SQL 服务器正常时,就按上述二者的作用正常操作,当读取数据、修改数据、预读机制等情况,说明缓冲池在多种情况下都会和数据页交互;如果此时SQL 服务器突然宕机了,那么缓冲池中的数据就无法同步到 MySQL 中,此时就发生了数据丢失。

为了应对这种情况,提出了 redo log 日志。

redo log(重做日志),记录的是事务提交时数据页的物理修改,是用来实现事务的持久性。
该日志文件由两部分组成:重做日志缓冲(redo log buffer)以及重做日志文件(redo log file),前者是在内存中,后者在磁盘中。当事务提交之后会把所有修改信息都存到该日志文件中,用于在刷新脏页到磁盘,发生错误时,进行数据恢复使用。

当然这里还可以有其他做法,比如同步,每存在一个 增删改 操作,我就去同步一次,每次同步都加一个返回,那也可以保证数据不丢失,即使丢失也能知道;但是这样会导致效率非常底,我缓冲池就是为了加快效率而存在的。

如下图所示:

当出现服务器宕机时,就会触发redo log。

3. 日志结构与写入流程

  • 内存结构:redo log buffer 是 InnoDB 的内存缓冲区,采用环形数组结构,默认大小 16MB
  • 刷盘策略:通过 innodb_flush_log_at_trx_commit 控制
    • 0:每秒刷盘一次(性能最佳,可能丢失 1 秒数据)
    • 1(默认):每次提交必刷盘(强一致性)
    • 2:提交时写入 OS 缓存,由系统决定何时刷盘

从redo log 缓冲池中写入数据到磁盘结构是顺序的,相比于逆序顺序的效率要更高。

主要原因有:

磁盘读写特性

磁盘由多个盘片组成,盘片上的数据存储在磁道和扇区中 。进行随机读写时,磁盘的机械臂需要频繁移动来定位不同磁道和扇区,会产生寻道时间和旋转延迟;而顺序读写时,机械臂可以按顺序依次读取或写入相邻磁道扇区,无需频繁移动,能大幅减少寻道时间和旋转延迟,显著提升读写效率。redo log 顺序写入,符合磁盘高效读写特性。

性能优化层面

  • 减少 I/O 次数:数据库运行中会产生大量 redo log 记录,若逆序写入,意味着频繁随机定位磁盘位置,每次定位都需额外 I/O 操作。顺序写入可将多个小的写操作合并成一个大的连续写操作,降低 I/O 操作次数,提升整体性能。比如事务执行过程中多条 redo log 记录,可批量顺序写入磁盘,而非分散多次随机写入。
  • 降低系统开销:顺序写入方式简单直接,相比逆序写入复杂的定位和组织方式,对系统资源(如 CPU 计算资源、内存管理资源等)消耗更少,能让系统将更多资源用于处理核心业务逻辑。

数据恢复角度

  • 方便日志解析:redo log 用于事务持久性和故障恢复,按顺序记录事务操作。顺序写入使日志记录按事务发生顺序排列,恢复时可按顺序逐一执行 redo 操作,还原数据到正确状态。若逆序,恢复时需重新梳理操作顺序,增加恢复难度和复杂性,可能导致恢复错误。
  • 保证数据一致性:在崩溃恢复等场景下,顺序写入的 redo log 能确保先发生事务的修改先应用,后发生事务的修改后应用,避免数据混乱,保障数据一致性。若逆序,可能出现后发生事务先恢复、先发生事务后恢复的情况,破坏数据一致性。

简单点说,就是日志文件中存储了大量的 insert delete 语句,而日志文件都是追加的形式,顺序存储效率要更高。

这种顺序的写入方式也叫做 WAL(Write-Ahead Logging)机制

当脏页数据可以正常的同步到磁盘文件的时候,这个redo log 就没啥用了。每隔一段时间就会把 redo log 日志进行清理,这个redo log 日志 是有两份的,彼此之间循环写,如下图所示:

3. Checkpoint 机制

为避免日志无限增长,InnoDB 通过 checkpoint 机制将已持久化的数据从 redo log 中移除:

  • 模糊检查点:定期将 Buffer Pool 中脏页刷盘,并更新 redo log 的 LSN(日志序列号)
  • 尖锐检查点:数据库异常重启时,通过 LSN 定位需要恢复的日志范围

二、undo log:事务回滚与 MVCC 的核心载体

1. 逻辑日志的特性

undo log 是 InnoDB 实现事务原子性(ACID 中的 A)和 MVCC(多版本并发控制)的关键,记录的是数据修改前的反向操作,例如 "将数据页 0x123 的第 100 字节从 0x45 恢复为 0x36"。

2. MVCC

MVCC 即 Multi - Version Concurrency Control,多版本并发控制 ,是一种在数据库管理系统中广泛应用的并发控制方法,用于实现对数据库的并发访问 ,也可在编程语言中实现事务内存。主要依赖于数据库记录中的 隐式字段、undo log 日志、readView

MVCC 最主要的功能是确定在并发的环境下,可以确定用户到底要使用的是哪个版本。

隐藏字段
隐藏字段含义
DB_TRX_ID Database Transaction ID 事务 ID,最近修改事务 ID,记录插入这条记录或最后一次修改该记录的事务 ID。
DB_ROLL_PTRDatabase  Roll Point 回滚指针,指向这条记录的上一个版本,用于配合 undo log,指向上一个版本。
DB_ROW_IDDatabase Row ID 隐藏主键,如果表结构没有指定主键,将会生成该隐藏字段。
undo log
  1. 回滚日志,在 insert、update、delete 的时候产生的便于数据回滚的日志。
  2. 当 insert 的时候,产生的 undo log 日志只在回滚时需要,在事务提交后,可被立即删除。
  3. 而 update、delete 的时候,产生的 undo log 日志不仅在回滚时需要,mvcc 版本访问也需要,不会立即被删除。
版本链 和 readView

undo log 通过构建数据版本链实现历史数据访问:

  • 版本链:每个数据行通过 trx_id 和 roll_ptr 字段链接多个历史版本

类似于上图,将多个版本形成一个链表。

  • Read View:事务启动时生成的快照,包含当前活跃事务 ID 列表,通过比较 trx_id 判断版本可见性

ReadView(读视图)是快照读 SQL 执行时 MVCC 提取数据的依据,记录并维护系统当前活跃的事务(未提交的)id。

readView  又分为当前读和快照读

  • 当前读:        
    • 读取的是记录的最新版本,读取时还要保证其他并发事务不能修改当前记录,会对读取的记录进行加锁。对于我们日常的操作,如:select ... lock in share mode (共享锁),select ... for update、update、insert、delete (排他锁) 都是一种当前读。
    • 当有事务在读取的时候,又有一个事务来进行写操作,并且提交了,但是该事务还是能够读取到最新数据,即使是发生阻塞也要读取到最新数据。
  • 快照读:简单的 select(不加锁)就是快照读,快照读,读取的是记录数据的可见版本,有可能是历史数据,不加锁,是非阻塞读;收到不同的隔离级别影响,不同的隔离级别,会有不同的结果
    • Read Committed:每次 select,都生成一个快照读。
    • Repeatable Read:开启事务后第一个 select 语句才是快照读的地方。(在同一个事务下无论读取多少次,读到的结果都一样)

不同的隔离级别,生成 ReadView 的时机不同:

  • READ COMMITTED:在事务中每一次执行快照读时生成 ReadView。
  • REPEATABLE READ:仅在事务中第一次执行快照读时生成 ReadView,后续复用该 ReadView。
ReadView 中包含的四个核心字段
字段含义
m_ids当前活跃的事务 ID 集合(Active Transaction IDs),记录了在创建 ReadView 时,数据库中所有尚未提交的事务 ID。
min_trx_id最小活跃事务 ID(Minimum Transaction ID),是 m_ids 集合中最小的事务 ID,用于判断事务的可见性。
max_trx_id预分配事务 ID(Maximum Transaction ID),值为当前最大事务 ID + 1(因为事务 ID 是自增的),用于界定事务 ID 的范围。
creator_trx_id

ReadView 创建者的事务 ID(Creator Transaction ID),标识创建该 ReadView 的事务。

MVCC 小结

MySQL 中的多版本并发控制。指维护一个数据的多个版本,使得读写操作没有冲突

  • 隐藏字段:
    ① trx_id (事务 id),记录每一次操作的事务 id,是自增的
    ② roll_pointer (回滚指针),指向上一个版本的事务版本记录地址
  • undo log:
    ① 回滚日志,存储老版本数据
    ② 版本链:多个事务并行操作某一行记录,记录不同事务修改数据的版本,通过 roll_pointer 指针形成一个链表
  • readView 解决的是一个事务查询选择版本的问题
    • 根据 readView 的匹配规则和当前的一些事务 id 判断该访问那个版本的数据
    • 不同的隔离级别快照读是不一样的,最终的访问的结果不一样
      • RC:每一次执行快照读时生成 ReadView
      • RR:仅在事务中第一次执行快照读时生成 ReadView,后续复用

小结:

回滚日志,用于记录数据被修改前的信息,作用包含两个:提供回滚 和 MVCC (多版本并发控制)。undo log 和 redo log 记录物理日志不一样,它是逻辑日志。

  • 可以认为当 delete 一条记录时,undo log 中会记录一条对应的 insert 记录,反之亦然,
  • 当 update 一条记录时,它记录一条对应相反的 update 记录。当执行 rollback 时,就可以从 undo log 中的逻辑记录读取到相应的内容并进行回滚。

undo log 可以实现事务的一致性和原子性

三、bin log:MySQL 服务器层的增量记录

1. 逻辑日志的定位

bin log 是 MySQL 服务器层(而非存储引擎)的日志,记录所有修改数据的 SQL 语句或数据行变更,用于实现:

  • 基于时间点的恢复(Point-in-Time Recovery)
  • 主从复制(Master-Slave Replication)
  • 审计追踪(需配合其他工具)

这里就只简单说说主从复制的原理。

  1. bin log 存在于主节点,功能是 记录所有修改数据的 SQL 语句或数据行变更。
  2. 而在从节点存在一个 IO 线程,这个线程只干一件事,就是去读 bin log 中的日志,并记录到 relay log (中继日志)中。
  3. 另外从节点还有一个 SQL 线程,这个线程用于将中继日志记录到的语句,写入从节点中,进而实现数据同步。

2. 三种日志格式

格式

记录内容

优点

缺点

Statement

SQL 语句文本

日志体积小

可能导致主从数据不一致(如 UUID ())

Row

数据行的前后镜像

绝对一致性

日志体积大(可能是 SQL 的 10 倍)

Mixed

自动切换上述两种格式

平衡一致性与体积

存在格式切换的不确定性

3. 写入与复制流程

  • 两阶段提交:bin log 与 redo log 通过 XID(事务 ID)关联,保证提交的原子性
  • sync_binlog:控制 bin log 刷盘策略(0 = 由 OS 控制,1 = 每次提交刷盘,n = 每 n 次提交刷盘)

四、核心区别对比表

特征

redo log

undo log

bin log

所属模块

InnoDB 存储引擎

InnoDB 存储引擎

MySQL 服务器层

日志类型

物理日志(数据页修改)

逻辑日志(反向操作)

逻辑日志(SQL / 行变更)

作用

事务持久化

事务回滚 / MVCC

增量备份 / 主从复制

写入时机

事务修改时异步生成

事务修改前生成

事务提交时同步写入

存储位置

ib_logfile * 文件

回滚段(共享表空间或独立表空间)

主机文件系统(路径由 log_bin 指定)

日志格式

专有格式(ibd)

专有格式

Statement/Row/Mixed

生命周期

由 Checkpoint 控制

由 Purge 线程清理

由 expire_logs_days 控制(默认 0 不自动删除)

五、典型应用场景

1. 事务故障恢复

  • 崩溃恢复:InnoDB 通过 redo log 重做未提交的事务,通过 undo log 回滚已提交但未持久化的事务
  • 手动回滚:ROLLBACK 语句通过 undo log 执行反向操作,快速撤销事务影响

2. 高可用性架构

  • 主从复制:bin log 作为主库与从库的数据桥梁,实现异步复制(默认)、半同步复制(增强一致性)
  • 数据备份:通过 mysqldump 结合 bin log,实现基于时间点的精确恢复

3. 并发控制

  • MVCC 读:通过 undo log 的版本链,实现读不阻塞写,提升高并发场景下的性能
  • 锁优化:减少行锁使用,降低锁竞争导致的性能瓶颈

六、最佳实践建议

  1. redo log 配置:根据业务 IO 特性调整日志文件大小(innodb_log_file_size),建议设置为可用内存的 25%-50%
  1. undo log 管理:定期监控回滚段空间使用(SHOW ENGINE INNODB STATUS),避免长事务导致的空间膨胀
  1. bin log 安全:生产环境建议使用 Row 格式(binlog_format=ROW),并开启 bin log 加密(binlog_encryption=ON)
  1. 性能平衡:通过 sync_binlog=1+innodb_flush_log_at_trx_commit=1 实现强一致性,或根据容忍度调整参数提升写入性能

总结

三大日志系统犹如数据库的 "三驾马车":redo log 保障数据不丢失,undo log 维护事务原子性与数据多版本,bin log 构建增量复制与恢复体系。理解它们的底层原理,不仅能帮助我们优化数据库性能,更能在故障处理、架构设计时做出正确决策。当遇到事务异常、主从延迟或空间占用过高等问题时,从这三大日志入手分析,往往能快速定位到核心原因。

(注:本文原理图可根据实际需求绘制,建议包含 redo log 写入流程、undo log 版本链结构、bin log 主从复制架构等示意图,帮助读者更直观理解日志机制。)

相关文章:

  • 安全企业内部im,BeeWorks即时通讯
  • 智能 + 安全:婴幼儿托育管理实训基地标准化建设方案
  • 傅里叶与相位偏移
  • 【Java函数式编程-58.1】深入理解Java中的Consumer函数式接口
  • 基于Spring Boot + Vue 项目中引入deepseek方法
  • 基于RFID与云边端协同的智慧牧场解决方案架构设计
  • 信号完整性简介第二篇
  • 大语言模型(LLM)应用开发平台Dify详细使用
  • 实用Chrome插件备忘
  • Kubernetes 与 Service Mesh 的集成
  • 关键词排名工具查到的位置和真实搜索差距大是什么原因?
  • LeetCode 2905 找出满足差值条件的下标II 题解
  • SNR8016语音模块详解(STM32)
  • 外部访问 Kubernetes 集群中 MQ 服务的方案
  • “技术创新+全球视野”良性驱动,首航新能的2025新征程正式起航
  • 【Linux更新openSSH服务】
  • 经典算法 独立任务最优调度问题
  • 数据结构每日一题day14(链表)★★★★★
  • nDCG(归一化折损累计增益) 是衡量排序质量的指标,常用于搜索引擎或推荐系统
  • FUSE 3.0.0 | 聚合7大直播平台的免费电视直播软件,支持原画清晰度及弹幕、收藏功能
  • 五大光伏龙头一季度亏损超80亿元,行业冬天难言结束
  • 水利部将联合最高检开展黄河流域水生态保护专项行动
  • 启程回家!神十九轨道舱与返回舱成功分离
  • 美的集团一季度净利增长38%,库卡中国机器人接单增超35%
  • 违规行为屡禁不止、责任边界模糊不清,法治日报:洞穴探险,谁为安全事故买单?
  • 夜读丨怀念那个写信的年代