一、为什么数据备份至关重要
MySQL数据库是企业核心数据的存储载体。在Ubuntu服务器的LNMP(Linux + Nginx + MySQL + PHP)环境中,数据库故障可能导致:
- 业务数据永久丢失
- 服务中断影响用户体验
- 合规要求无法满足
- 恢复成本高昂
本文详细介绍在Ubuntu LNMP环境下实现MySQL数据备份的完整方案,涵盖手动备份、自动备份、远程备份和恢复验证等关键环节。
二、备份前的准备工作
2.1 检查MySQL版本和状态
# 查看MySQL版本
mysql --version
# 查看数据库列表
mysql -u root -p -e "SHOW DATABASES;"
# 查看当前运行状态
sudo systemctl status mysql
2.2 创建备份专用账户
-- 创建备份专用账户
CREATE USER 'backup_user'@'localhost' IDENTIFIED BY 'StrongPassword123!';
-- 授予必要权限
GRANT SELECT, LOCK TABLES, RELOAD, REPLICATION CLIENT ON *.* TO 'backup_user'@'localhost';
-- 刷新权限
FLUSH PRIVILEGES;
2.3 创建备份目录
# 创建备份目录
sudo mkdir -p /backup/mysql
sudo mkdir -p /backup/mysql/daily
sudo mkdir -p /backup/mysql/weekly
# 设置目录权限
sudo chown mysql:mysql /backup/mysql
sudo chmod 750 /backup/mysql
三、手动备份方法
3.1 完整备份(mysqldump)
备份单个数据库:
mysqldump -u root -p --single-transaction --routines --triggers --events mydb > /backup/mysql/mydb_$(date +%Y%m%d).sql
备份所有数据库:
mysqldump -u root -p --all-databases --single-transaction --routines --triggers --events > /backup/mysql/all_dbs_$(date +%Y%m%d).sql
关键参数说明:
| 参数 | 说明 |
|---|---|
| –single-transaction | 启动事务保证一致性 |
| –routines | 备份存储过程和函数 |
| –triggers | 备份触发器 |
| –events | 备份事件调度器 |
| –master-data | 记录复制位置 |
3.2 增量备份
启用二进制日志:
编辑MySQL配置文件:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
添加:
[mysqld]
log-bin = mysql-bin
expire_logs_days = 7
max_binlog_size = 100M
binlog_format = row
重启MySQL:
sudo systemctl restart mysql
执行增量备份:
# 查找当前二进制日志文件
mysql -u root -p -e "SHOW MASTER STATUS;"
# 刷新日志并记录位置
mysql -u root -p -e "FLUSH LOGS;"
# 备份二进制日志
sudo mysqlbinlog --read-binary-logs --start-datetime="$(date -d 'yesterday' +%Y-%m-%d)" /var/lib/mysql/mysql-bin.* > /backup/mysql/incremental_$(date +%Y%m%d).sql
3.3 物理备份(冷备份)
# 停止MySQL服务
sudo systemctl stop mysql
# 复制数据文件
sudo cp -a /var/lib/mysql /backup/mysql/mysql_data_$(date +%Y%m%d)
# 重启MySQL服务
sudo systemctl start mysql
# 压缩备份
sudo tar -czvf /backup/mysql/mysql_data_$(date +%Y%m%d).tar.gz /var/lib/mysql
四、自动备份配置
4.1 使用cron定时备份
# 编辑crontab
sudo crontab -e
添加每日备份任务:
# 每天凌晨2点执行完整备份
0 2 * * * mysqldump -u root -p'YourPassword' --all-databases --single-transaction --routines --triggers --events > /backup/mysql/daily/full_backup_$(date +\%Y\%m\%d).sql 2>> /var/log/mysql-backup.log
# 每天上午6点执行增量备份
0 6 * * * mysql -u root -p'YourPassword' -e "FLUSH LOGS;" && mysqlbinlog --read-binary-logs /var/lib/mysql/mysql-bin.* > /backup/mysql/daily/incremental_$(date +\%Y\%m\%d).sql 2>> /var/log/mysql-backup.log
4.2 备份脚本(推荐)
创建综合备份脚本:
#!/bin/bash
# /usr/local/bin/mysql-backup.sh
# 配置参数
MYSQL_USER="root"
MYSQL_PASSWORD="YourPassword"
BACKUP_DIR="/backup/mysql"
DATE=$(date +%Y%m%d_%H%M%S)
LOG_FILE="/var/log/mysql-backup.log"
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
# 创建备份目录
mkdir -p $BACKUP_DIR/daily
mkdir -p $BACKUP_DIR/weekly
mkdir -p $BACKUP_DIR/monthly
# 完整备份函数
full_backup() {
log "开始执行完整备份..."
mysqldump -u $MYSQL_USER -p"$MYSQL_PASSWORD" \
--single-transaction \
--routines \
--triggers \
--events \
--all-databases \
--master-data=2 \
--flush-logs \
> $BACKUP_DIR/daily/full_backup_$DATE.sql 2>> $LOG_FILE
if [ $? -eq 0 ]; then
log "完整备份成功: $BACKUP_DIR/daily/full_backup_$DATE.sql"
# 压缩备份文件
gzip $BACKUP_DIR/daily/full_backup_$DATE.sql
log "备份文件已压缩"
return 0
else
log "完整备份失败!"
return 1
fi
}
# 增量备份函数
incremental_backup() {
log "开始执行增量备份..."
mysql -u $MYSQL_USER -p"$MYSQL_PASSWORD" -e "FLUSH LOGS;"
mysqlbinlog --read-binary-logs --base64-output=decode-rows \
/var/lib/mysql/mysql-bin.* \
> $BACKUP_DIR/daily/incremental_$DATE.sql 2>> $LOG_FILE
if [ $? -eq 0 ]; then
log "增量备份成功: $BACKUP_DIR/daily/incremental_$DATE.sql"
gzip $BACKUP_DIR/daily/incremental_$DATE.sql
return 0
else
log "增量备份失败!"
return 1
fi
}
# 清理旧备份
clean_old_backups() {
log "清理30天前的备份..."
find $BACKUP_DIR/daily -name "*.sql.gz" -mtime +30 -delete
find $BACKUP_DIR/weekly -name "*.sql.gz" -mtime +90 -delete
log "旧备份清理完成"
}
# 主流程
case "$1" in
full)
full_backup
;;
incremental)
incremental_backup
;;
clean)
clean_old_backups
;;
*)
full_backup
incremental_backup
clean_old_backups
;;
esac
log "备份任务完成"
设置执行权限:
sudo chmod +x /usr/local/bin/mysql-backup.sh
4.3 自动化任务配置
sudo crontab -e
添加:
# 每天凌晨2点执行完整备份
0 2 * * * /usr/local/bin/mysql-backup.sh full >> /var/log/mysql-backup.log 2>&1
# 每天每6小时执行增量备份
0 */6 * * * /usr/local/bin/mysql-backup.sh incremental >> /var/log/mysql-backup.log 2>&1
# 每周日凌晨3点清理旧备份
0 3 * * 0 /usr/local/bin/mysql-backup.sh clean >> /var/log/mysql-backup.log 2>&1
五、远程备份配置
5.1 SCP远程传输
#!/bin/bash
# /usr/local/bin/mysql-remote-backup.sh
LOCAL_BACKUP="/backup/mysql"
REMOTE_HOST="backup.example.com"
REMOTE_USER="backupuser"
REMOTE_DIR="/backup/mysql"
# 执行本地备份
/usr/local/bin/mysql-backup.sh full
# 传输到远程服务器
rsync -avz --progress \
-e "ssh -i /root/.ssh/backup_key" \
$LOCAL_BACKUP/daily/full_backup_*.sql.gz \
$REMOTE_USER@$REMOTE_HOST:$REMOTE_DIR/
5.2 云存储备份
配置阿里云OSS:
# 安装ossutil
wget https://help.aliyun.com/document_detail/120077.html -O ossutil.zip
unzip ossutil.zip
chmod +x ossutil
# 配置凭证
./ossutil config
上传备份:
#!/bin/bash
# /usr/local/bin/mysql-oss-backup.sh
BACKUP_FILE="/backup/mysql/daily/full_backup_$(date +%Y%m%d).sql.gz"
OSS_BUCKET="my-backup-bucket"
OSS_ENDPOINT="oss-cn-hangzhou.aliyuncs.com"
./ossutil cp $BACKUP_FILE oss://$OSS_BUCKET/mysql/$(date +%Y%m%d)/ \
--endpoint $OSS_ENDPOINT
配置AWS S3:
# 安装AWS CLI
pip3 install awscli
# 配置凭证
aws configure
# 上传备份
aws s3 cp /backup/mysql/daily/full_backup_$(date +%Y%m%d).sql.gz s3://my-backup-bucket/mysql/
5.3 双机热备
配置主从复制:
主库配置:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
server-id = 1
log-bin = mysql-bin
binlog-do-db = mydb
从库配置:
sudo nano /etc/mysql/mysql.conf.d/mysqld.cnf
[mysqld]
server-id = 2
relay-log = mysql-relay-bin
read-only = 1
配置复制:
-- 主库
SHOW MASTER STATUS;
-- 从库执行
CHANGE MASTER TO
MASTER_HOST='192.168.1.10',
MASTER_USER='repl_user',
MASTER_PASSWORD='ReplPassword123',
MASTER_LOG_FILE='mysql-bin.000001',
MASTER_LOG_POS=123;
START SLAVE;
SHOW SLAVE STATUS\G
六、备份恢复验证
6.1 验证备份完整性
# 检查备份文件是否存在
ls -lh /backup/mysql/daily/
# 验证备份文件是否可读
zcat /backup/mysql/daily/full_backup_20260514.sql.gz | head -20
# 验证SQL语法
mysqlcheck -u root -p --all-databases
6.2 测试恢复流程
# 创建测试数据库
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS test_restore;"
# 恢复测试
mysql -u root -p test_restore < /backup/mysql/daily/full_backup_20260514.sql
# 验证数据
mysql -u root -p -e "USE test_restore; SHOW TABLES; SELECT COUNT(*) FROM users;"
6.3 定期恢复演练
#!/bin/bash
# /usr/local/bin/mysql-restore-test.sh
TEST_DB="restore_test_$(date +%Y%m%d)"
BACKUP_FILE=$(ls -t /backup/mysql/daily/full_backup_*.sql.gz | head -1)
# 创建测试数据库
mysql -u root -p -e "CREATE DATABASE IF NOT EXISTS $TEST_DB;"
# 解压并恢复
zcat $BACKUP_FILE | mysql -u root -p $TEST_DB
# 验证数据
TABLE_COUNT=$(mysql -u root -p -e "USE $TEST_DB; SHOW TABLES;" | wc -l)
if [ $TABLE_COUNT -gt 0 ]; then
echo "恢复测试成功:$TABLE_COUNT 个表"
mysql -u root -p -e "DROP DATABASE $TEST_DB;"
return 0
else
echo "恢复测试失败!"
return 1
fi
七、备份策略建议
7.1 备份频率
| 备份类型 | 频率 | 保留时间 |
|---|---|---|
| 完整备份 | 每天1次 | 30天 |
| 增量备份 | 每6小时1次 | 7天 |
| 月度备份 | 每月1次 | 12个月 |
| 归档备份 | 每季度1次 | 2年 |
7.2 3-2-1备份原则
- 3份数据副本:原始数据 + 本地备份 + 远程备份
- 2种不同介质:本地磁盘 + 云存储
- 1份异地备份:远程数据中心或云端
7.3 备份检查清单
- [ ] 备份账户权限正确配置
- [ ] 备份脚本可执行权限已设置
- [ ] Cron定时任务已添加
- [ ] 备份存储空间充足
- [ ] 远程备份已配置
- [ ] 恢复演练已执行
- [ ] 备份日志正常记录
- [ ] 监控告警已配置
八、常见问题处理
8.1 备份失败排查
# 检查MySQL服务状态
sudo systemctl status mysql
# 检查磁盘空间
df -h /backup/mysql
# 检查MySQL用户权限
mysql -u backup_user -p -e "SHOW GRANTS;"
# 查看备份日志
tail -f /var/log/mysql-backup.log
8.2 恢复失败排查
# 检查备份文件完整性
file /backup/mysql/daily/full_backup_20260514.sql.gz
# 检查MySQL错误日志
sudo tail -50 /var/log/mysql/error.log
# 手动执行备份命令排查
mysqldump -u root -p --all-databases --single-transaction
8.3 备份压缩失败
# 检查gzip是否安装
which gzip
# 手动压缩测试
gzip -k /backup/mysql/daily/test.sql
# 查看压缩率
gzip -l /backup/mysql/daily/test.sql.gz
九、监控与告警
9.1 备份状态监控
#!/bin/bash
# /usr/local/bin/mysql-backup-monitor.sh
BACKUP_DIR="/backup/mysql/daily"
MAX_AGE=25 # 小时
# 检查最新备份时间
LATEST_BACKUP=$(ls -t $BACKUP_DIR/full_backup_*.sql.gz 2>/dev/null | head -1)
if [ -z "$LATEST_BACKUP" ]; then
echo "警告:未找到备份文件!"
exit 1
fi
BACKUP_AGE=$(find $LATEST_BACKUP -mmin +$((MAX_AGE*60)) -print 2>/dev/null)
if [ -n "$BACKUP_AGE" ]; then
echo "警告:最新备份超过${MAX_AGE}小时未更新!"
# 发送告警
echo "MySQL备份告警:最新备份超过${MAX_AGE}小时" | mail -s "MySQL备份告警" admin@example.com
exit 1
fi
echo "备份状态正常"
exit 0
9.2 Prometheus监控
# mysql_backup_exporter监控配置
groups:
- name: mysql-backup
rules:
- alert: BackupNotRecent
expr: time() - file_timestamp{job="mysql_backup"} > 86400
for: 5m
labels:
severity: critical
annotations:
summary: "MySQL备份超过24小时未更新"
十、总结
MySQL数据备份是数据库管理的重要环节。在Ubuntu LNMP环境下,建议采用以下备份策略:
- 每日完整备份 + 增量备份:保障数据完整性
- 本地存储 + 远程云存储:符合3-2-1原则
- 自动化定时任务:减少人工干预
- 定期恢复演练:确保备份可用
- 实时监控告警:及时发现问题
通过以上方案,可以有效保障MySQL数据安全,应对各种数据丢失风险。
注:本文基于MySQL 8.0、Ubuntu 22.04编写。生产环境请根据实际情况调整参数。