mysql执行SQL如何保证崩溃恢复_mysql日志机制说明

来源:这里教程网 时间:2026-02-28 20:39:31 作者:

MySQL崩溃后靠什么恢复数据

MySQL崩溃后能恢复到最近一次一致状态,核心依赖的是

redo log
(重做日志)和
binlog
(归档日志)的协同机制。其中
redo log
是 InnoDB 存储引擎层的物理日志,保障事务的持久性(DURABLE);
binlog
是 Server 层的逻辑日志,用于主从复制和基于时间点的恢复。两者不互相替代,但配合使用才能实现崩溃安全与可回溯。

为什么只靠 binlog 不能保证崩溃恢复

binlog
是追加写、逻辑日志(如
INSERT INTO t VALUES (1)
),它不记录页级变更,也不保证写入时机与事务提交强绑定。如果 MySQL 在事务已写
binlog
但尚未刷盘 InnoDB 数据页时崩溃,重启后会发现:数据页仍是旧值,而
binlog
里却有这条“已提交”的记录——造成主从不一致或恢复出错。

binlog
默认异步写入磁盘(
sync_binlog=0
),崩溃可能丢失未刷盘的 binlog 内容
InnoDB 数据页刷新(
flush
)是后台异步进行的,事务提交时并不保证数据页已落盘
只有
redo log
在事务
commit
前强制写入并
fsync
到磁盘(由
innodb_flush_log_at_trx_commit
控制),确保崩溃后可用其重放未落盘的页变更

崩溃恢复时 redo log 怎么工作

MySQL 启动时,InnoDB 会自动进入恢复流程:扫描

redo log
文件(通常是
ib_logfile0
ib_logfile1
),从检查点(
checkpoint
)位置开始,重放所有已写入但未应用到数据页的
redo log
记录,把数据页“追平”到崩溃前的状态。

检查点位置由
innodb_checkpoint_lsn
记录,代表已刷盘数据页对应的日志序列号(LSN)
恢复过程不依赖
binlog
,纯靠
redo log
的物理操作(如“将 page 123 offset 48 处的 4 字节改为 0x00000001”)
innodb_flush_log_at_trx_commit = 1
(默认),每次
COMMIT
都触发
fsync
,崩溃最多丢失 1 个事务;设为 0 或 2 时,可能丢失秒级事务
mysql> SHOW VARIABLES LIKE 'innodb_flush_log_at_trx_commit';
+--------------------------------+-------+
| Variable_name                  | Value |
+--------------------------------+-------+
| innodb_flush_log_at_trx_commit | 1     |
+--------------------------------+-------+

如何验证 redo log 是否正常参与恢复

最直接的方式是模拟崩溃并观察错误日志。手动 kill -9 mysqld 进程后重启,查看

error.log
中是否出现类似以下内容:

InnoDB: Starting crash recovery.
InnoDB: Reading tablespace information from the .ibd files...
InnoDB: Doing recovery: scanned up to log sequence number XXXXXXXXX
InnoDB: Database was not shut down normally!

注意几个关键点:

必须用
kill -9
(非
mysqladmin shutdown
),否则不会触发 crash recovery 流程
确保
innodb_log_file_size
足够大(如 256M),避免频繁覆盖导致早期日志丢失
不要手动删除或清空
ib_logfile*
,否则 InnoDB 启动会报错
Invalid log file size
并拒绝启动

真正容易被忽略的是:

redo log
binlog
的两阶段提交(2PC)协议是否启用。只要
innodb_support_xa = ON
(5.7.7+ 默认开启)且
sync_binlog = 1
,MySQL 就会在事务提交时先写
redo log
prepare,再写
binlog
,最后写
redo log
commit —— 这个顺序才是崩溃后能对齐两者的关键。漏掉任一环节,恢复就不可靠。

相关推荐