服务器崩溃后,我是怎么用一条备份脚本救回全部数据的
MySQL 数据库自动备份 | mysqldump 全量备份 | crontab 定时任务 | 磁盘熔断 | 恢复验证
一次服务器硬盘故障差点让我丢掉所有客户数据。从那以后,我写了这条脚本,跑了大半年稳如老狗。今天把完整方案分享出来,包括我踩过的坑。
背景
我的服务器跑了十几套业务系统,MySQL 里存着合同数据、审批记录、监控日志。有一次磁盘满了导致 MySQL 直接崩掉,好在有冷备份才没丢数据。
痛定思痛,搞了一套全自动备份方案,加了磁盘熔断、过期清理、binlog 刷新。就算半夜崩了,第二天起床数据还在。
一、备份脚本
1.1 配置 MySQL 免密登录
直接写在命令行里会有安全风险(history 能查到密码),推荐用配置文件:
bash
cat > ~/.my.cnf <<EOF
[client]
user=你的用户名
password=你的密码
EOF
chmod 600 ~/.my.cnf
⚠️ 注意:该用户必须有数据库的读取权限,建议直接用 root。权限不够会导致备份静默失败,这是我自己踩过的第一个坑。
1.2 核心备份脚本
脚本路径:/usr/local/bin/mysql_backup.sh
bash
#!/bin/bash
BACKUP_DIR="/home/storehouse/DBbackup"
RETAIN_DAYS=7
MAX_DISK_USAGE=80
# 磁盘熔断:使用率超过 80% 直接跳过,防止备份把磁盘写满
CURRENT_USAGE=$(df -h /home | awk 'NR==2 {print $5}' | sed 's/%//')
if [ $CURRENT_USAGE -gt $MAX_DISK_USAGE ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') 警告: 磁盘使用率 ${CURRENT_USAGE}%,超过阈值,跳过本次备份!"
exit 1
fi
mkdir -p $BACKUP_DIR
DATE=$(date +%Y%m%d_%H%M%S)
BACKUP_FILE="$BACKUP_DIR/full_backup_${DATE}.sql.gz"
echo "$(date '+%Y-%m-%d %H:%M:%S') 开始备份..."
mysqldump --defaults-extra-file=~/.my.cnf \
--all-databases \
--single-transaction \
--routines \
--events \
| gzip -9 > $BACKUP_FILE
if [ $? -eq 0 ]; then
echo "$(date '+%Y-%m-%d %H:%M:%S') 备份成功: $BACKUP_FILE (大小: $(du -h $BACKUP_FILE | cut -f1))"
else
echo "$(date '+%Y-%m-%d %H:%M:%S') 备份失败!"
exit 1
fi
# 清理 7 天前的旧备份
find $BACKUP_DIR -name "full_backup_*.sql.gz" -mtime +$RETAIN_DAYS -delete
# 刷新 binlog,配合备份做时间点恢复
mysql --defaults-extra-file=~/.my.cnf -e "FLUSH LOGS;"
echo "$(date '+%Y-%m-%d %H:%M:%S') 备份流程结束,当前磁盘使用率: $(df -h /home | awk 'NR==2 {print $5}')"
bash
chmod +x /usr/local/bin/mysql_backup.sh
1.3 配置定时任务
bash
crontab -e
添加:
bash
0 2 * * * /usr/local/bin/mysql_backup.sh >> /var/log/mysql_backup.log 2>&1
每天凌晨 2 点自动跑,日志丢到 /var/log/mysql_backup.log。
二、日常巡检
2.1 每天看一眼备份是否成功
bash
tail -20 /var/log/mysql_backup.log
ls -lh /home/storehouse/DBbackup/
2.2 每周检查磁盘空间
bash
df -h
确保 /home 分区使用率不超过 80%。
2.3 每月做一次恢复测试(这条最重要)
备份不做恢复测试 = 没备份。每个月在测试环境验证一次:
bash
gunzip < /home/storehouse/DBbackup/full_backup_xxxxxx.sql.gz | mysql -u root -p
三、为什么不直接用云厂商的快照/Percona?
- 云快照:恢复粒度太粗,不能做单表或单库恢复,而且不是你自己的东西,云厂商崩了你跟着崩。
- Percona XtraBackup:更适合大库物理备份,部署重。中小库直接用 mysqldump + gzip,够用且迁移方便。
- 没有用第三方监控/告警:保持零依赖。有问题直接看日志,不需要额外配 Grafana 或钉钉机器人。当然,如果后面需要,你可以在脚本里加一行 webhook 就行。
四、我踩过的坑
- 权限不够导致备份静默失败 :
.my.cnf里的用户必须能读所有库。我第一次用了只有部分库权限的账号,备份没报错但缺了数据,恢复的时候才发现。 - 磁盘满了 MySQL 直接崩:这就是我加磁盘熔断的原因。备份脚本如果不管磁盘,会雪上加霜。
- crontab 环境变量与手动执行不一致 :cron 跑脚本时
PATH很简陋,mysqldump 和 gzip 必须用绝对路径或者在脚本里明确export PATH。我直接装了完整 MySQL 客户端,所以没遇到,但如果用最小化系统记得检查。
结语
这套方案我已经在生产环境稳定运行了大半年。它不完美,但够用。关键是简单、无依赖、出了问题你自己能修。
懒得手动配? 我把完整的一键部署脚本打包好了,复制到服务器上直接跑就行。私信回复「备份」直接发你。
有问题欢迎评论区或私信交流。如果你也在做服务器运维,也可以顺手关注一下,后面我会陆续分享监控、日志切割、Docker 实战这类东西。