不能直接用 mysqldump 做 ZFS 快照前的一致性准备,因其不阻塞写入,快照无法保证 InnoDB 事务一致性;需先执行 FLUSH ENGINE LOGS 和 FLUSH TABLES WITH READ LOCK,再对所有相关 dataset 分别打快照,并手动记录 binlog 位点。

为什么不能直接用 mysqldump 做 ZFS 快照前的“一致性准备”
因为 mysqldump 本身不阻塞写入(除非显式加 --lock-all-tables 或 --single-transaction),而 ZFS 快照是瞬间的文件系统级快照,它只保证磁盘上数据块的一致性,不感知 MySQL 的事务状态。如果 dump 过程中 InnoDB 正在刷脏页、redo 日志持续写入,ZFS 快照里可能包含部分提交/部分回滚的中间状态——恢复出来大概率报 Tablespace is missing for table 或启动失败。
- 必须让 MySQL 主动 flush 所有脏页并暂停写入,再打快照;
-
FLUSH TABLES WITH READ LOCK能停写,但会卡住 DDL 和长事务,且在主从架构下可能拖慢复制; - 更稳妥的做法是:用
mysqladmin flush-logs+FLUSH ENGINE LOGS确保 redo 和 binlog 边界清晰,再配合FLUSH TABLES WITH READ LOCK获取一个轻量锁,立刻打 ZFS 快照,然后马上UNLOCK TABLES; - 注意:该操作要求 MySQL 用户有
RELOAD和LOCK TABLES权限。
ZFS 快照命令必须带挂载点而非 dataset 名
ZFS 快照对象是 dataset,但 MySQL 数据目录通常只是某个 dataset 下的子路径(比如 /data/mysql 对应 dataset pool/data)。如果误对 pool 打快照,会包含无关数据;如果只对 pool/data 打快照,又可能漏掉 ib_logfile* 或 undo_001 等文件——它们可能在另一个 dataset 上(比如独立的 pool/mysql-log)。
- 先确认 MySQL 实际使用的全部挂载点:
df -h /var/lib/mysql /var/log/mysql /etc/mysql; - 对每个对应 dataset 分别打快照,例如:
zfs snapshot pool/mysql@snap-20240520-1430、zfs snapshot pool/mysql-log@snap-20240520-1430; - 快照名建议含时间戳和语义标签,避免后续混淆;
- 不要依赖
zfs list -t snapshot后手动匹配路径——ZFS 不记录快照和 MySQL 实例的逻辑关联。
恢复时必须先还原 ZFS 快照,再修复 InnoDB 内部状态
ZFS 快照还原后,MySQL 数据文件是“物理一致”的,但 InnoDB 的 ibdata1、redo log、doublewrite buffer 可能处于未完全刷盘状态。直接启动 mysqld 很容易触发崩溃恢复失败或静默数据损坏。
- 还原快照后,先停掉 mysqld:
systemctl stop mysql; - 清空 redo 日志文件(
ib_logfile0,ib_logfile1),否则 InnoDB 会尝试按旧日志恢复,导致校验失败; - 设置
innodb_force_recovery = 1启动一次,仅用于校验表空间可读,成功后立即关闭; - 再以正常配置重启,InnoDB 会自动执行 crash recovery(基于快照时刻的 checkpoint 位置);
- 务必检查
SHOW ENGINE INNODB STATUS\G中的 “Log sequence number” 和 “Last checkpoint at” 是否连续。
binlog 位点与 ZFS 快照无法自动对齐
ZFS 快照不含 binlog 文件内容,也不记录当时的 MASTER_LOG_FILE 和 MASTER_LOG_POS。如果要用快照做主库切换或 PITR(Point-in-Time Recovery),必须在打快照前后主动记录 binlog 坐标。
- 打快照前执行:
mysql -e "SHOW MASTER STATUS\G" > /tmp/snap-binlog.pos; - 该命令输出里的
File和Position就是快照对应的 binlog 起始点; - 注意:这个位置是“快照完成后、UNLOCK TABLES 之前”的坐标,比快照时间略晚几十毫秒,但足够用于后续追平;
- 如果开启了 GTID,还要额外记录
SELECT @@GLOBAL.GTID_EXECUTED;; - 千万别把
mysqldump --master-data输出当真——它是在 dump 开始时查的位点,和 ZFS 快照时间完全错开。
最麻烦的不是命令怎么写,而是每次快照都要人工核对 dataset 范围、redo 清理时机、binlog 坐标采集顺序——少一步,恢复时就多一小时排查。










