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

8次阅读

MySQL 崩溃后靠 redo log 恢复数据,其通过重放未落盘的页变更将数据页追平至崩溃前状态,binlog 仅用于主从复制和时间点恢复,不参与崩溃恢复。

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

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

text=ZqhQzanResources