MySQL日志undo log、redo log和binlog详解

发布于:2025-02-22 ⋅ 阅读:(18) ⋅ 点赞:(0)

MySQL 日志:undo log、redo log、binlog 有什么用?

在这里插入图片描述

一、前言

在MySQL数据库中,undo log、redo log和binlog这三种日志扮演着至关重要的角色,它们各自承担着不同的功能,共同保障了数据库的正常运行和数据的完整性。了解它们的工作原理和作用,对于深入理解MySQL数据库的运行机制以及进行性能优化和故障排查都具有重要意义。

二、基础篇

MySQL的数据存储于磁盘,读写操作若频繁直接访问磁盘,效率较低。为提升性能,InnoDB存储引擎设计了缓冲池(Buffer Pool),以页(默认16KB)为单位缓存数据,包括索引页、数据页、Undo页等。

三、undo log

(一)undo log的作用

  1. 事务回滚:undo log由InnoDB存储引擎生成,用于实现事务的原子性。在事务执行“增删改”操作时,MySQL会隐式开启事务,undo log会记录更新前的数据。若事务执行中途MySQL崩溃,可利用undo log回滚到事务之前的数据状态。
  2. MVCC(多版本并发控制):对于“读提交”和“可重复读”隔离级别的事务,其快照读通过Read View + undo log实现。不同隔离级别创建Read View的时机不同,从而控制并发事务访问同一记录时的行为。

(二)undo log的记录方式

当InnoDB引擎对记录进行操作(修改、删除、新增)时,会把回滚所需信息记录到undo log中。如插入记录时记录主键值,删除记录时记录内容,更新记录时记录被更新列的旧值。不同操作产生的undo log格式不同,且每条记录的更新操作产生的undo log都有roll_pointer指针和trx_id事务id,可串成版本链。

(三)undo log的刷盘机制

undo log和数据页的刷盘策略一致,都需通过redo log保证持久化。buffer pool中有undo页,对undo页的修改会记录到redo log,redo log每秒刷盘,提交事务时也刷盘,以此保证undo log的持久化。

四、redo log

(一)redo log的作用

  1. 实现事务持久性:Buffer Pool基于内存,为防止断电导致数据丢失,InnoDB引擎在更新数据时,先更新内存(标记为脏页),再将修改以redo log形式记录,事务提交时只需将redo log持久化到磁盘,无需等待脏页写入磁盘。系统崩溃重启后,可依据redo log恢复数据,保证已提交记录不丢失,即crash - safe能力。
  2. 提升写入性能:写入redo log采用追加操作,是顺序写,而写入数据是随机写,磁盘顺序写比随机写高效得多,WAL技术将MySQL的写操作从随机写变为顺序写,提升了写入性能。

(二)redo log的缓存与刷盘时机

  1. 缓存:执行事务过程中,产生的redo log先写入redo log buffer,其默认大小16MB,可通过innodb_log_Buffer_size参数调整。
  2. 刷盘时机
    • MySQL正常关闭时;
    • 当redo log buffer中记录的写入量大于其内存空间一半时;
    • InnoDB的后台线程每隔1秒;
    • 每次事务提交时(由innodb_flush_log_at_trx_commit参数控制,默认值为1,取值0表示事务提交时redo log留在buffer中,取值2表示事务提交时redo log写入文件但不保证写入磁盘)。

(三)redo log文件组与循环写机制

默认InnoDB存储引擎有1个重做日志文件组,由2个redo log文件(ib_logfile0和ib_logfile1)组成,大小固定且一致。以循环写方式工作,write pos表示当前记录位置,checkpoint表示可擦除位置。当write pos追上checkpoint,即redo log文件满时,会暂停执行新更新操作,将脏页刷新到磁盘,擦除旧记录,移动checkpoint,然后恢复正常运行。

五、binlog

(一)binlog的作用

  1. 数据备份与恢复:记录了所有数据库表结构变更和表数据修改的日志,不记录查询操作。当数据库数据丢失或损坏时,可利用binlog进行数据恢复。
  2. 主从复制:MySQL的主从复制依赖于binlog,主库将binlog传输到从库,从库通过回放binlog实现数据同步。

(二)binlog与redo log的区别

  1. 适用对象:binlog是MySQL的Server层实现的日志,所有存储引擎都可使用;redo log是InnoDB存储引擎实现的日志。
  2. 文件格式:binlog有STATEMENT(逻辑日志,记录SQL语句)、ROW(记录行数据最终修改结果)、MIXED(包含前两种模式)三种格式;redo log是物理日志,记录数据页的修改。
  3. 写入方式:binlog是追加写,写满创建新文件,保存全量日志;redo log是循环写,空间固定,保存未刷盘的脏页日志。
  4. 用途:binlog用于备份恢复、主从复制;redo log用于掉电等故障恢复。

(三)主从复制的实现与模型

  1. 实现过程:主库写binlog日志并提交事务,更新本地数据;从库I/O线程连接主库log dump线程接收binlog,写入relay log中继日志;从库回放线程读relay log,回放binlog更新数据,实现主从数据一致性。
  2. 复制模型
    • 同步复制:主库提交事务线程等待所有从库复制成功响应,性能差、可用性低。
    • 异步复制(默认):主库提交事务线程不等待从库复制,主库宕机可能丢数据。
    • 半同步复制:MySQL 5.7版本新增,事务线程等待部分从库复制成功响应,兼顾性能和数据安全。

(四)binlog的刷盘时机

事务执行中,先将日志写入binlog cache,事务提交时,把binlog cache写入binlog文件。MySQL通过sync_binlog参数控制刷盘频率,取值0表示只write不fsync,交由操作系统决定持久化时机;取值1表示每次提交事务都write并fsync;取值N(N>1)表示累积N个事务后fsync。

六、两阶段提交

(一)两阶段提交的原因

事务提交时,redo log和binlog都要持久化到磁盘,若出现半成功状态,会导致两份日志逻辑不一致,在主从架构中造成数据不一致问题。为避免此问题,MySQL采用两阶段提交。

(二)两阶段提交的过程

  1. prepare阶段:将XID(内部XA事务的ID)写入redo log,将事务状态设置为prepare,然后将redo log持久化到磁盘。
  2. commit阶段:把XID写入binlog,将binlog持久化到磁盘,接着调用引擎提交事务接口,将redo log状态设置为commit。

(三)异常重启的处理

在两阶段提交不同时刻MySQL异常重启,若redo log处于prepare状态,重启后会根据binlog中是否存在相同XID决定事务提交或回滚。若存在则提交,不存在则回滚,以此保证两份日志一致性。

(四)两阶段提交的问题与优化

  1. 问题
    • 磁盘I/O次数高:“双1”配置下,每个事务提交进行两次fsync,一次redo log刷盘,一次binlog刷盘。
    • 锁竞争激烈:早期通过prepare_commit_mutex锁保证事务提交顺序,并发量大时锁争用严重,性能不佳。
  2. 优化 - 组提交
    • binlog组提交:将多个binlog刷盘操作合并,减少磁盘I/O次数。commit阶段拆分为flush(将binlog从cache写入文件)、sync(对binlog文件fsync,合并刷盘)、commit(各个事务按顺序做InnoDB commit操作)三个过程,每个阶段有队列和锁保护,第一个进入队列事务为leader,负责整队操作。
    • redo log组提交(MySQL 5.7):将prepare阶段融合在flush阶段,延迟redo log刷盘到flush阶段,sync阶段之前,实现redo log组写入。
前言
基础概念
undo log
作用事务回滚MVCC
记录方式
刷盘机制
redo log
作用事务持久提升写入
缓存与刷盘
文件组与循环写
binlog
作用备份恢复主从复制
与redo log区别
主从复制实现与模型
刷盘时机
两阶段提交
原因避免日志不一致
过程preparecommit
异常处理
问题与优化组提交
总结