redo log 和 bin log
Redo log 和 binlog 的区别
- redo log 是 innodb 独有的,binlog 是 mysql server 层的日志所有存储引擎都可以使用。
- redo log 是循环写的,binlog 是追加写的。
- redo log 为 2 阶段提交,binlog 一次写入。
- redo log 保证事务的持久性,binlog 主要用于主从复制,数据恢复。
为什么 redo log 需要二阶段提交?
是为了避免 redo log 与 binlog 出现数据不一致的情况。
在写入其中一个之后,mysql 崩溃会导致另外一个丢失,但是他们的作用又不同,redo log 主要用于保证事务的持久性,binlog 主要用于主从复制和数据恢复。
为什单靠 binlog 没法满足事务?
有这样一个情况,一个事务会执行多条修改语句。
time1: set balance = 100 where id = 1 time2: set balance = 200 where id = 2 time3: 将 id = 1 的修改输入磁盘了 time4: mysql 崩溃(事务未提交,binlog 未写入,但是磁盘中的数据已部分修改)
mysql update 执行语句过程。
mysql 执行 update 语句的时候,会先找到这条数据,然后执行更新操作,把更新之后的数据写入内存,同时,写入 redo log,并将其标记为 prepare 状态,在事务提交时,先写入 bin log, 在将 redo log 改为 commit 状态。
事务执行
- 从磁盘读取数据页到 Buffer Pool
- 在 Buffer Pool 中修改数据
- I这个页变成脏页
- 写 undo log
- 写 redo log buffer
事务提交 6. 写 redo log, 并标记为 prepare 状态 7. bin log 写入 9. redo log 改为 commit 状态
某个时刻,后台线程把脏页写入磁盘的 .ibd 文件
WAL 机制
Write-Ahead Logging: 先写日志,在写入磁盘。
先把日志写入 redo log,再把修改刷入磁盘数据页。
- 写入 redo log buffer
- 写入 OS Cache
- 写入磁盘
- 在后台异步将脏数据刷到磁盘
崩溃后的恢复机制
mysql 崩溃后会根据 redo log 来恢复数据。
如果看到 redo log 是 prepare 状态时,会去检查 bin log 是否完整,如果 bin log 已经写入,则提交这个事务,否则回滚这个事务。 如果看到 redo log 是 commit 状态,就会直接提交事务。
相关的 mysql 配置参数
sync_binlog
binlog 什么时候写入磁盘
# sync_binlog配置
sync_binlog=1 # (fsync) 每次提交都刷盘
sync_binlog=0 # (写入 OS Cache)由操作系统决定何时刷盘
sync_binlog=N # 每 N 个事务刷一次盘
innodb_flush_log_at_trx_commit
innodb_flush_log_at_trx_commit 用于控制 redo log 什么时候写入磁盘。
mysql 内存 ---> 操作系统缓存(OS Cache = Page Cache) ---> 磁盘
- mysql 内存: 指的是 INNODB buffer bool,redo log buffer 等
- 操作系统缓存: 用于临时存放要写到磁盘的数据。
通过 fsync()/fdatasync() 系统调用,会将 OS Cache 的数据写入磁盘。
innodb_flush_log_at_trx_commit=1 # 每次都写入磁盘
innodb_flush_log_at_trx_commit=0 # 写入MySQL 内存,每隔 1s 将数据写入操作系统缓存,并调用 fsync 将数据刷入磁盘。====> mysql 崩溃时可能会丢失 1s 内的事务
innodb_flush_log_at_trx_commit=2 # 写入操作系统缓存,mysql 后台线程每秒执行一次 fsync 将数据刷入磁盘。====> mysql 崩溃不会丢失数据,系统断电可能会丢失 1s 内的事务
redo log 的 prepare 和 commit 阶段都是受到 innodb_flush_log_at_trx_commit 参数的控制。