MySQL之日志写入顺序
MySQL之日志写入顺序
当MySQL执行一条UPDATE语句时,InnoDB存储引擎和Server层会协同工作,按照严格的顺序写入undo log、redo log和binlog,并通过两阶段提交保证数据一致性和崩溃恢复能力。以下是详细的执行流程和日志写入顺序:
1. 更新语句执行前的准备
- 客户端发送
UPDATE语句,MySQL Server通过连接器、分析器、优化器后,调用InnoDB的接口执行更新。 - 如果更新的数据页不在内存的缓冲池中,InnoDB会先将该页从磁盘读入缓冲池。
2. 记录 undo log(回滚日志)
- 顺序:第1步写入
在修改数据之前,InnoDB会先将修改前的旧值写入**undo log**,记录到undo log buffer中。- 例如:将“修改前”的整行数据或主键信息保存下来,用于事务回滚或MVCC。
undo log本身也是物理修改(因为undo页也需要持久化),因此对undo页的修改也会在稍后被redo log保护。
3. 修改缓冲池中的数据页
- 顺序:第2步(内存操作)
在内存中更新缓冲池里的数据页,将新值写入,此时该页变为“脏页”(内存与磁盘不一致)。- 注意:这一步不会立即写回磁盘,而是等待后续刷盘。
4. 记录 redo log(重做日志)到缓冲区
- 顺序:第3步写入
在数据页修改的同时,InnoDB会生成对应的物理日志(记录“在哪个页的哪个偏移量改为什么值”),并写入redo log buffer。- 这一步遵循WAL(Write-Ahead Logging)原则:日志先于数据持久化。
undo页的修改也会同时被记录到redo log中。
此时,UPDATE语句的执行阶段完成,但事务尚未提交。
5. 事务提交:两阶段提交(关键步骤)
当客户端发起COMMIT时,MySQL会进入两阶段提交流程,确保redo log和binlog的一致性。
第一阶段:redo log 进入 prepare 状态并刷盘
- 顺序:第4步
InnoDB将当前事务的redo log buffer刷入磁盘的redo log file,并记录事务状态为PREPARE。- 如果
innodb_flush_log_at_trx_commit=1,此时会强制fsync落盘,保证redo log已持久化。
- 如果
第二阶段:写入 binlog(二进制日志)并刷盘
- 顺序:第5步
MySQL Server将事务的binlog(逻辑日志,记录SQL语句或行变更)写入binlog file,并执行fsync刷盘。- 至此,
binlog已持久化。
- 至此,
第三阶段:redo log 进入 commit 状态
- 顺序:第6步
InnoDB在redo log中写入一个COMMIT标记,表示事务正式提交。此时事务才算真正完成。- 这一步通常不需要再次刷盘,只需在内存中标记即可(但
redo log中已有完整的修改记录)。
- 这一步通常不需要再次刷盘,只需在内存中标记即可(但
6. 返回成功
- 顺序:最后一步
提交完成后,MySQL向客户端返回“更新成功”。
日志写入顺序总结(时间线)
| 步骤 | 操作内容 | 日志类型 | 说明 |
|---|---|---|---|
| 1 | 记录旧值到undo log buffer |
undo log |
内存中记录,为回滚做准备 |
| 2 | 修改缓冲池中的数据页 | 无 | 内存中的脏页生成 |
| 3 | 生成redo log并写入redo log buffer |
redo log |
记录物理修改 |
| 4 | 两阶段提交第1阶段:redo log刷盘并标记PREPARE |
redo log |
持久化到redo log file |
| 5 | 两阶段提交第2阶段:binlog刷盘 |
binlog |
持久化到binlog file |
| 6 | 两阶段提交完成:redo log标记COMMIT |
redo log |
在redo log中写入提交标记 |
| 7 | 返回客户端成功 | - | - |
为什么要这么设计?两阶段提交的作用
- 保证数据一致性:如果崩溃发生在步骤4之后、步骤5之前,恢复时会发现
redo log处于PREPARE状态且无对应binlog,则事务回滚;如果崩溃在步骤5之后,则redo log和binlog都已持久化,事务可以提交。这样就避免了主从数据不一致或数据丢失。 undo log先于修改:确保任何修改都可以被撤销,即使系统在修改后立即崩溃,重启后也可以通过undo log回滚未提交的事务。
补充说明
undo log的持久化:虽然undo log是逻辑日志,但其所在的数据页修改也会被redo log记录,因此undo log的持久化依赖于redo log的WAL机制。- 刷盘策略的影响:如果
innodb_flush_log_at_trx_commit或sync_binlog设置为非1的值,刷盘时机可能延迟,但日志写入的顺序逻辑不变。 - 自动提交:如果
autocommit=1,则每条UPDATE语句执行完后会自动提交,即上述提交阶段会立即执行。
通过这种严格的顺序和两阶段提交,MySQL在保证高性能的同时,实现了事务的ACID特性和主从复制的数据一致性。
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 wshawk's blog!