备份这件事,只有真正恢复过一次才算数。这篇对比逻辑备份与物理备份的取舍,并给出一份带校验的自动化脚本。
两种备份的本质区别
| 逻辑备份(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校验,并保留至少两周的滚动窗口。 - 定期演练恢复,而不是只盯着备份日志里的「成功」。