重做日志 redo log
重做日志是用来保障事务的持久性的,它体现了 MySQL 中的 WAL 技术,即在长久化数据之前,先保障 redo log 曾经写到了磁盘上。重做日志是基于磁盘的数据结构,记录了在某个数据页上做了什么批改,是 InnoDB 引擎特有的日志,在事务提交前重做日志被写入磁盘,当零碎解体时,就能够依据 redo log 来复原数据。
WAL:Write-Ahead Logging,先写日志,再写磁盘。
当执行一条更新语句时,InnoDB 首先会将更新信息写入重做日志中,而后将重做日志放到重做日志缓冲区(redo log buffer),之后依照肯定的频率将 redo log buffer 写入重做日志文件中。
重做日志对应的物理文件
默认状况下,在数据库的 data 目录下有两个文件 ib_logfile1
和 ib_logfile2
。重做日志文件以循环写入的形式进行:
重做日志缓冲区刷新到磁盘
依照上面三种状况刷新:
- Master Thread 每一秒将重做日志缓冲刷新到重做日志文件;
- 每个事务提交时会将重做日志缓冲刷新到重做日志文件;
- 当重做日志缓冲残余空间小于 1 / 2 时刷新到重做日志文件;
对于第二种状况,触发写磁盘的条件由 innodb_flush_log_at_trx_commit 参数管制,示意当提交事务时,解决 redo log 的形式。
innodb_flush_log_at_trx_commit
的有效值为 0, 1, 2;默认为 1:
- 0:提交事务时并不刷新缓冲区,而是期待主线程每秒的刷新;
- 1:提交事务时将重做日志缓冲区刷新到磁盘;合乎事务的 ACID 个性;
- 2:提交事务时将重做日志缓冲区先刷新到文件系统的缓存中,之后每秒将缓存刷新到磁盘中,也就是说 重做日志异步写到磁盘;
当值为 0 和 2 时,数据库产生解体,会存在局部日志未刷新到磁盘,因而会失落局部数据;
二进制日志 binlog
后面提到的 redo log 是 InnoDB 引擎特有的日志,而 Server 层也有本人的日志,即二进制日志 binlog,binlog 记录了数据库 增删改 操作的信息,以二进制的格局保留在磁盘中。当提交事务时,一次性将事务中的所有 SQL 语句写入 binlog 中。
binlog 记录的是 逻辑操作,能够简略认为就是 SQL 语句,binlog 是通过追加的形式进行写入的,也就是说当 binlog 文件写到肯定大小后切换到下一个,不会笼罩之前的文件。
MySQL 通过 sync_binlog 参数来管制服务层什么时候将 binlog 同步到磁盘上,sync_binlog
的有效值为 0, 1, N,默认为 1:
- 0:敞开服务层同步 binlog 到磁盘的性能,binlog 的同步依赖于操作系统的不定时同步,该设置提供了最好的性能,但如果操作系统解体,就会导致已提交的事务没有同步到磁盘上;
- 1:每次事务提交都会同步 binlog,该设置是最平安的,然而因为磁盘 IO 频率变高,会影响性能;
- N:每提交 N 个事务才进行一次 binlog 同步,能进步肯定的性能;
作用
- 主从复制:从库利用主库的 binlog 进行重播,实现主从同步;
- 复原:将数据库还原到某一个工夫点;
两阶段提交
两阶段提交(two-phase commit,2PC)指的是事务提交分成 prepare 和 commit 两个阶段:
- 引擎将更新记录写入 redo log,并将 redo log 同步到磁盘 上,此时事务处于
prepared
状态; - 接着 执行器生成事务的 binlog,并将 binlog 写入磁盘,而后调用引擎的提交事务接口,通知引擎提交更改,引擎就会将之前曾经筹备好的事务(
prepared
)改成已提交(committed
)状态;
通过两个阶段,最终事务胜利提交,并且保留在重做日志和二进制日志中。两阶段提交的目标是保障重做日志和二进制日志的一致性,避免数据库复原时数据不统一。
如果事务处于 prepared 状态时,MySQL 解体了,会产生什么?
因为事务此时还未提交,所以依据事务的原子性,这个事务会进行回滚,之前的操作都有效。所以两阶段提交保障了日志的一致性,如果两个日志离开写入,那么就有可能产生不统一的问题。
redo log 和 binlog 的区别
- 作用不同:redo log 是 InnoDB 引擎特有的日志,用来保障事务的持久性,是事务层面的;binlog 是 MySQL 服务层实现的,所有引擎都能够应用,起到还原的作用,是数据库层面的;
- 内容不同:redo log 是物理日志,记录的是「在某个数据页上做了什么更改」;binlog 是逻辑日志,记录的是语句的原始逻辑,能够简略了解为记录的是 SQL 语句;
- 写入形式不同:redo log 是循环写入的;binlog 是追加写入,不会笼罩以前的日志;
- 复原数据的效率不同:基于物理日志的 redo log 复原数据的效率要比逻辑日志 binlog 高;
参考资料:
- MySQL 中的重做日志(redo log),回滚日志(undo log),以及二进制日志(binlog)的简略总结
- MySQL 系列之 redo log、undo log 和 binlog 详解
- MySQL 45 讲
- Fun MySQL fact of the day: everything is two-phase