服务器崩溃后,我是怎么用一条备份脚本救回全部数据的

服务器崩溃后,我是怎么用一条备份脚本救回全部数据的

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 就行。

四、我踩过的坑

  1. 权限不够导致备份静默失败.my.cnf 里的用户必须能读所有库。我第一次用了只有部分库权限的账号,备份没报错但缺了数据,恢复的时候才发现。
  2. 磁盘满了 MySQL 直接崩:这就是我加磁盘熔断的原因。备份脚本如果不管磁盘,会雪上加霜。
  3. crontab 环境变量与手动执行不一致 :cron 跑脚本时 PATH 很简陋,mysqldump 和 gzip 必须用绝对路径或者在脚本里明确 export PATH。我直接装了完整 MySQL 客户端,所以没遇到,但如果用最小化系统记得检查。

结语

这套方案我已经在生产环境稳定运行了大半年。它不完美,但够用。关键是简单、无依赖、出了问题你自己能修


懒得手动配? 我把完整的一键部署脚本打包好了,复制到服务器上直接跑就行。私信回复「备份」直接发你。

有问题欢迎评论区或私信交流。如果你也在做服务器运维,也可以顺手关注一下,后面我会陆续分享监控、日志切割、Docker 实战这类东西。

相关推荐
宠友信息1 小时前
MySQL 租户数据隔离在即时通讯源码后端中的落地方式
java·数据库·spring boot·redis·websocket·mysql
wear工程师2 小时前
MySQL 索引失效别再背八股:看懂 EXPLAIN,面试官追问也不慌
mysql·面试
逆向编程4 小时前
MySQL 负载均衡完整入门实战教程
mysql·adb·负载均衡
tant1an4 小时前
MySQL面试题(一)
数据库·mysql
红糖奶茶5 小时前
MySQL 8.0的自增主键持久化特性
数据库·mysql·adb
xieliyu.6 小时前
MySQL 六大基础约束详解:NOT NULL/DEFAULT/UNIQUE/ 主键 / 外键 / CHECK
android·数据库·sql·mysql
Anokata7 小时前
MYSQL SQL 执行系列1
android·sql·mysql
Java成神之路-7 小时前
彻底分清:垂直分库、水平分库、垂直分表、水平分表(附 Mycat 完整配置)
mysql
techdashen9 小时前
Uber 如何让 MySQL Group Replication 在大规模生产环境中可用:自动化、故障转移与一致性保障
数据库·mysql·自动化