docker stop 正常停 → 不会 crash recovery;kill -9 / 异常宕机 → 重启必做 crash recovery。
一、两种 stop 的区别
- docker stop(默认 10s 优雅关闭)
- MySQL 收到 SIGTERM,走正常 shutdown:
- 停止新连接,回滚活跃事务
- 脏页全部刷盘,写 checkpoint
- 正常关闭 redo/undo log
- 重启时 error log:
Database was shut down normally,无 crash recovery。
- docker stop -t 0 /kill -9 / 容器被强杀
- 直接断电,不走正常 shutdown:
- 内存脏页未刷盘、checkpoint 未写
- redo log 有未完成事务
- 重启时 error log:
Database was not shut down normally,强制进入 crash recovery。
二、MySQL 5.7 InnoDB 恢复机制
- 正常关闭:跳过 redo 重放,直接启动。
- 异常关闭:必须执行 crash recovery
- 重放 redo log(前滚已提交未刷盘数据)
- 回滚未提交事务
- 清理 undo/purge 等MySQL。
三、容器场景常见现象
- 用
docker-compose down/docker stop:无 crash recovery,启动快。 - 用
kill -9 $(pidof mysqld)/ 宿主机断电:必 crash recovery,启动慢(取决于 redo 大小与负载)。 - 日志特征(crash recovery):
InnoDB: Database was not shut down normally.
InnoDB: Starting recovery from log files...
InnoDB: Doing recovery: scanned up to log sequence number ...
四、如何避免不必要的 crash recovery
- Always use
docker stop(给足时间,如 -t 300)。 - 不要在事务高峰期强杀容器。
- 关键环境配置
innodb_fast_shutdown=0(正常关闭时全量刷盘,更安全)。
innodb_fast_shutdown=0 详解(MySQL5.7 容器适配)
一、参数取值含义
1. innodb_fast_shutdown 三个值
- 1(默认):快速关闭不刷全量脏页、只做最小化关闭,速度快,重启大概率触发 crash recovery。
- 2:最快速直接丢弃缓冲池脏页,相当于异常宕机,重启必走崩溃恢复。
- 0:完整优雅关闭停机时做三件事:
- 停止新事务、回滚活跃事务
- 把缓冲池所有脏页全部刷到磁盘
- 清空 undo 日志、完成 purge 清理、落地所有事务状态
二、设为 0 的核心效果
- docker stop 正常停机后,重启绝对不会进 crash recovery
- 停机耗时变长(脏页越多、数据量越大,关得越慢)
- 数据一致性最高,适合生产容器、主从、定时重启场景
三、容器环境关键配置要点
1. my.cnf 配置写入
[mysqld]
innodb_fast_shutdown = 0
# 建议配套加这两个,适配优雅停机
innodb_buffer_pool_dump_at_shutdown = 1
innodb_buffer_pool_load_at_startup = 1
2. docker stop 必须加长超时
因为 0 关闭慢,默认 10 秒会超时,超时后 Docker 直接发 kill -9,等于白设!
# 给300秒优雅关闭时间
docker stop -t 300 mysql57
docker-compose 也要改:
services:
mysql:
image: mysql:5.7
stop_grace_period: 300s
四、优缺点总结
✅ 优点
- 正常 stop 重启无 crash recovery,启动快、无日志恢复开销
- 数据落地完整,减少索引碎片、redo 日志残留
- 主从架构不易出现 relay log 崩溃、事务不一致
❌ 缺点
- 关机等待时间明显增加
- 大内存、大表、高脏页场景,停机可能要几分钟
五、最佳实践建议
生产 MySQL5.7 容器必设 innodb_fast_shutdown=0 + stop_grace_period: 300s,
彻底解决「正常 stop 重启还自动 crash recovery」的问题。
Categories:
数据库运维