
MySQL在崩溃后如何恢复数据?为什么更新操作不立即写入磁盘?主从复制为何依赖binlog而非redo log?本文将通过流程图详解InnoDB的三大日志系统。
三大日志的核心职责
- Redo Log(重做日志):保证事务的持久性,确保已提交的事务不会丢失
- Undo Log(回滚日志):负责事务回滚,MVCC一致性读依赖undo生成的行版本
- Bin Log(二进制日志):实现主从复制和数据恢复功能
详细操作流程
1. 读取磁盘页到Buffer Pool
执行SQL语句时:
UPDATE user SET age = 30 WHERE id = 1;
MySQL的InnoDB存储引擎首先会:
- 判断所需数据页是否在buffer pool中
- 如果不在,则从磁盘加载数据页到buffer pool
2. 生成undo log(记录旧值)
在更新数据前,InnoDB会将旧记录写入undo log:
3. 修改Buffer Pool中的数据(内存更新)
InnoDB不会立即修改磁盘文件,而是:
- 直接修改内存中的数据页
- 修改后的内存页变为脏页(dirty page)
4. 记录redo log(写入redo log buffer)
同时,InnoDB会将“对哪页做了什么修改”的信息写入redo log buffer。
至此,数据已经:
- 在内存(Buffer Pool)中完成修改
- 写入redo log buffer
- 但磁盘文件尚未更新
5. redo log刷盘(prepare阶段)
在事务即将提交时,InnoDB执行:
- 将redo log buffer写入磁盘的redo log文件
- 写入状态标记为:prepare
这一步标志着redo log已支持该事务恢复,但事务尚未完全提交。
6. 写binlog(记录事务逻辑)
MySQL Server层开始记录binlog:
- 写入binlog buffer
- 刷盘到binlog文件
7. 事务提交(commit)并写入binlog位点
binlog落盘成功后:
这一步完成“两阶段提交”,确保数据恢复时redo log与binlog的一致性。
后续处理流程
上面的流程仅保证:
- undo log已写入
- redo log已写入
- binlog已写入
- 内存数据已修改
但磁盘数据文件此时仍未被真正修改。
后台线程会执行以下操作:
8. IO线程异步刷脏页
后台LRU和flush线程将:
- 把Buffer Pool中的脏数据页写回磁盘
- 此过程为异步操作,不阻塞事务提交
9. 刷盘数据文件(持久化真实数据)
最终磁盘文件才真正完成数据变更的持久化。
|