数据库

备份这件事,只有真正恢复过一次才算数。这篇对比逻辑备份与物理备份的取舍,并给出一份带校验的自动化脚本。

两种备份的本质区别

逻辑备份(mysqldump)物理备份(xtrabackup)
备份内容SQL 文本数据文件
速度慢,随数据量线性增长
恢复粒度可单表、单库只能整体
跨版本基本可以受限,需版本接近
适合场景中小站点、迁移大库、快速回滚

对个人站点来说,mysqldump 足够了;数据超过几十 GB 再考虑物理备份。

一份可用的备份脚本

#!/bin/bash
set -euo pipefail

DB_NAME="it365"
DB_USER="it365"
BACKUP_DIR="/var/backups/mysql"
KEEP_DAYS=14
STAMP=$(date +%Y%m%d-%H%M%S)

mkdir -p "$BACKUP_DIR"
FILE="$BACKUP_DIR/${DB_NAME}-${STAMP}.sql.gz"

# --single-transaction 保证 InnoDB 表的一致性快照,且不锁表
mysqldump \
  --single-transaction \
  --routines --triggers --events \
  --default-character-set=utf8mb4 \
  -u"$DB_USER" -p"$DB_PASS" "$DB_NAME" | gzip > "$FILE"

# 关键一步:校验产物能否解压,避免留下坏备份
gzip -t "$FILE"
echo "备份完成: $FILE ($(du -h "$FILE" | cut -f1))"

# 清理过期备份
find "$BACKUP_DIR" -name '*.sql.gz' -mtime +$KEEP_DAYS -delete

几个参数值得解释:

  • --single-transaction:靠事务隔离拿到一致快照,不会锁表,线上可直接跑。
  • --routines --triggers --events:默认不导出存储过程、触发器和事件,漏了会踩坑。
  • gzip -t:解压测试。备份文件损坏却没人发现,是最常见的翻车方式。

恢复流程

# 1. 建一个空库(不要覆盖原库,先恢复到临时库确认)
mysql -uroot -p -e "CREATE DATABASE it365_restore CHARACTER SET utf8mb4;"

# 2. 导入
gunzip -c /var/backups/mysql/it365-20260828-030000.sql.gz | mysql -uroot -p it365_restore

# 3. 抽样比对行数
mysql -uroot -p -e "SELECT COUNT(*) FROM it365_restore.typecho_contents;"

确认无误后再改配置切流量,这样万一恢复失败,线上仍然是好的。

关于恢复演练

建议每季度做一次真实演练:把最近一份备份恢复到一个临时库,跑通「起一个 Typecho 指向它、首页能打开」为止。演练过的备份才叫备份,没演练过的只是文件。

小结

  • 中小站点用 mysqldump + --single-transaction 足够可靠。
  • 一定要 gzip -t 校验,并保留至少两周的滚动窗口。
  • 定期演练恢复,而不是只盯着备份日志里的「成功」。

参与讨论