247 lines
11 KiB
Markdown
247 lines
11 KiB
Markdown
# 11.9 备份与恢复
|
||
|
||
:::danger 生产环境必须备份
|
||
数据库和上传文件必须定期备份,建议每天自动备份。备份文件应存储在独立于服务器的安全位置。
|
||
:::
|
||
|
||
## 数据库备份
|
||
|
||
### 手动备份
|
||
|
||
```bash
|
||
# -----------------------------------------------------------------------------
|
||
# MySQL 全量备份(结构 + 数据)
|
||
# -----------------------------------------------------------------------------
|
||
# -u root → 数据库用户名
|
||
# -proot → 数据库密码(生产环境建议用 -p 后不跟密码,交互式输入)
|
||
# rxthinkcmf... → 要备份的数据库名
|
||
# > backup_*.sql → 输出到文件,$(date +%Y%m%d) 自动生成日期后缀
|
||
mysqldump -u root -proot rxthinkcmf.thinkphp8.elevue > backup_$(date +%Y%m%d).sql
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 压缩备份(推荐 — 可节省 70%+ 磁盘空间)
|
||
# -----------------------------------------------------------------------------
|
||
# | gzip → 将 mysqldump 输出通过管道传给 gzip 压缩
|
||
mysqldump -u root -proot rxthinkcmf.thinkphp8.elevue | gzip > backup_$(date +%Y%m%d).sql.gz
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 仅备份表结构(不含数据 — 用于对比表结构变更)
|
||
# -----------------------------------------------------------------------------
|
||
# --no-data → 只导出 CREATE TABLE 语句,不导出数据
|
||
mysqldump -u root -proot --no-data rxthinkcmf.thinkphp8.elevue > schema_$(date +%Y%m%d).sql
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 仅备份数据(不含表结构 — 用于数据迁移)
|
||
# -----------------------------------------------------------------------------
|
||
# --no-create-info → 只导出 INSERT 语句,不导出 CREATE TABLE
|
||
mysqldump -u root -proot --no-create-info rxthinkcmf.thinkphp8.elevue > data_$(date +%Y%m%d).sql
|
||
```
|
||
|
||
### 自动备份脚本
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# =============================================================================
|
||
# backup_db.sh — 数据库自动备份脚本
|
||
# =============================================================================
|
||
# 用途:自动备份 MySQL 数据库,压缩存储,自动清理过期备份
|
||
# 用法:crontab 定时调用,或手动执行 bash backup_db.sh
|
||
# =============================================================================
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 配置参数(按实际环境修改)
|
||
# -----------------------------------------------------------------------------
|
||
BACKUP_DIR="/backup/mysql" # 备份文件存放目录
|
||
DB_NAME="rxthinkcmf.thinkphp8.elevue" # 要备份的数据库名
|
||
DB_USER="root" # 数据库用户名
|
||
DB_PASS="root" # 数据库密码
|
||
DATE=$(date +%Y%m%d_%H%M%S) # 当前时间戳(年月日_时分秒)
|
||
KEEP_DAYS=30 # 保留最近 N 天的备份
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 创建备份目录(-p 参数:目录不存在时自动创建)
|
||
# -----------------------------------------------------------------------------
|
||
mkdir -p $BACKUP_DIR
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 执行备份(mysqldump 输出通过管道传给 gzip 压缩)
|
||
# -----------------------------------------------------------------------------
|
||
mysqldump -u $DB_USER -p$DB_PASS $DB_NAME | gzip > $BACKUP_DIR/backup_$DATE.sql.gz
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 检查备份结果($? 为上一条命令的退出码,0=成功)
|
||
# -----------------------------------------------------------------------------
|
||
if [ $? -eq 0 ]; then
|
||
echo "[$(date)] 备份成功: backup_$DATE.sql.gz"
|
||
else
|
||
echo "[$(date)] 备份失败!"
|
||
exit 1 # 非零退出码表示失败,便于监控系统捕获
|
||
fi
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 清理过期备份
|
||
# -----------------------------------------------------------------------------
|
||
# find 参数说明:
|
||
# -name "backup_*.sql.gz" → 匹配备份文件名格式
|
||
# -mtime +$KEEP_DAYS → 修改时间超过 N 天的文件
|
||
# -delete → 删除匹配的文件
|
||
find $BACKUP_DIR -name "backup_*.sql.gz" -mtime +$KEEP_DAYS -delete
|
||
|
||
echo "[$(date)] 清理完成,保留最近 $KEEP_DAYS 天的备份"
|
||
```
|
||
|
||
### 配置定时备份
|
||
|
||
```bash
|
||
# 编辑当前用户的 crontab 定时任务
|
||
crontab -e
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 定时备份规则
|
||
# -----------------------------------------------------------------------------
|
||
# 格式:分 时 日 月 周 命令
|
||
# 0 3 * * * → 每天凌晨 3:00 执行
|
||
# 0 4 * * 0 → 每周日凌晨 4:00 执行(0=周日)
|
||
# >> /var/log/backup.log 2>&1 → 追加日志(2>&1 将错误也写入日志)
|
||
# -----------------------------------------------------------------------------
|
||
0 3 * * * /www/scripts/backup_db.sh >> /var/log/backup.log 2>&1
|
||
0 4 * * 0 /www/scripts/backup_db_full.sh >> /var/log/backup.log 2>&1
|
||
```
|
||
|
||
## 上传文件备份
|
||
|
||
```bash
|
||
# -----------------------------------------------------------------------------
|
||
# 备份上传目录为压缩包
|
||
# -----------------------------------------------------------------------------
|
||
# tar 参数说明:
|
||
# -c → 创建新归档
|
||
# -z → 用 gzip 压缩
|
||
# -f → 指定输出文件名
|
||
# $(date +%Y%m%d) → 自动生成日期后缀
|
||
tar -czf /backup/uploads_$(date +%Y%m%d).tar.gz /opt/data/uploads/
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 上传文件自动备份脚本
|
||
# -----------------------------------------------------------------------------
|
||
#!/bin/bash
|
||
BACKUP_DIR="/backup/uploads" # 备份存放目录
|
||
DATE=$(date +%Y%m%d) # 日期后缀
|
||
mkdir -p $BACKUP_DIR # 创建目录(如不存在)
|
||
tar -czf $BACKUP_DIR/uploads_$DATE.tar.gz /opt/data/uploads/ # 压缩打包
|
||
find $BACKUP_DIR -name "uploads_*.tar.gz" -mtime +30 -delete # 清理 30 天前的备份
|
||
```
|
||
|
||
## 恢复
|
||
|
||
### 恢复数据库
|
||
|
||
```bash
|
||
# -----------------------------------------------------------------------------
|
||
# 从 SQL 文件恢复(全量覆盖)
|
||
# -----------------------------------------------------------------------------
|
||
# < backup_*.sql → 将文件内容作为 mysql 命令的输入
|
||
mysql -u root -proot rxthinkcmf.thinkphp8.elevue < backup_20260920.sql
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 从压缩文件恢复(gunzip 解压后传给 mysql)
|
||
# -----------------------------------------------------------------------------
|
||
# gunzip < file.sql.gz → 解压并输出到标准输出
|
||
# | mysql → 通过管道传给 mysql 命令执行
|
||
gunzip < backup_20260920.sql.gz | mysql -u root -proot rxthinkcmf.thinkphp8.elevue
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 恢复到新数据库(安全起见 — 先验证再切换)
|
||
# -----------------------------------------------------------------------------
|
||
# 1. 创建临时验证数据库
|
||
mysql -u root -proot -e "CREATE DATABASE `rxthinkcmf.thinkphp8.elevue_restore`;"
|
||
# 2. 恢复备份到临时库
|
||
mysql -u root -proot rxthinkcmf.thinkphp8.elevue_restore < backup_20260920.sql
|
||
# 3. 验证数据无误后,重命名数据库(需停机操作)
|
||
```
|
||
|
||
### 恢复上传文件
|
||
|
||
```bash
|
||
# -----------------------------------------------------------------------------
|
||
# 恢复上传目录到原始位置
|
||
# -----------------------------------------------------------------------------
|
||
# tar 参数说明:
|
||
# -x → 解压归档
|
||
# -z → 解压 gzip
|
||
# -f → 指定归档文件
|
||
# -C → 解压到指定目录(/ 表示按归档内的绝对路径还原)
|
||
tar -xzf /backup/uploads_20260920.tar.gz -C /
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 仅恢复特定子目录(如只恢复文章附件)
|
||
# -----------------------------------------------------------------------------
|
||
# 在归档文件名后追加要解压的路径前缀
|
||
tar -xzf /backup/uploads_20260920.tar.gz -C / www/uploads/article/
|
||
```
|
||
|
||
## 备份验证
|
||
|
||
:::warning 必须定期验证备份
|
||
备份文件必须定期恢复验证,确保备份可用。建议每月进行一次恢复测试。
|
||
:::
|
||
|
||
```bash
|
||
#!/bin/bash
|
||
# =============================================================================
|
||
# verify_backup.sh — 备份验证脚本
|
||
# =============================================================================
|
||
# 用途:将备份恢复到临时数据库,验证数据完整性后清理
|
||
# 用法:bash verify_backup.sh backup_20260920.sql.gz
|
||
# =============================================================================
|
||
|
||
BACKUP_FILE=$1 # 第一个参数:备份文件路径
|
||
VERIFY_DB="rxthinkcmf.thinkphp8.elevue_verify" # 临时验证数据库名
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 创建验证数据库(先删除旧的,再创建新的)
|
||
# -----------------------------------------------------------------------------
|
||
# DROP DATABASE IF EXISTS → 如果存在则删除(避免同名冲突)
|
||
mysql -u root -p -e "DROP DATABASE IF EXISTS $VERIFY_DB; CREATE DATABASE $VERIFY_DB;"
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 恢复备份到验证数据库
|
||
# -----------------------------------------------------------------------------
|
||
gunzip < $BACKUP_FILE | mysql -u root -p $VERIFY_DB
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 验证数据完整性
|
||
# -----------------------------------------------------------------------------
|
||
# -N → 不输出表头(只输出数据值)
|
||
# information_schema.tables → MySQL 系统表,存储所有表的元信息
|
||
TABLE_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM information_schema.tables WHERE table_schema='$VERIFY_DB';")
|
||
echo "恢复的表数量: $TABLE_COUNT"
|
||
|
||
# 检查用户表数据量(验证核心数据是否完整)
|
||
USER_COUNT=$(mysql -u root -p -N -e "SELECT COUNT(*) FROM $VERIFY_DB.think_user;")
|
||
echo "用户数量: $USER_COUNT"
|
||
|
||
# -----------------------------------------------------------------------------
|
||
# 清理验证数据库(验证完毕后删除临时库)
|
||
# -----------------------------------------------------------------------------
|
||
mysql -u root -p -e "DROP DATABASE $VERIFY_DB;"
|
||
|
||
echo "备份验证完成"
|
||
```
|
||
|
||
## 备份存储建议
|
||
|
||
| 存储方式 | 优点 | 缺点 |
|
||
|----------|------|------|
|
||
| 本地磁盘 | 速度快 | 服务器故障可能丢失 |
|
||
| NAS / 网络存储 | 独立于服务器 | 需要网络 |
|
||
| 云存储(OSS/S3) | 高可靠、异地 | 需要付费 |
|
||
| 异地服务器 | 灾难恢复 | 需要维护 |
|
||
|
||
:::tip 最佳实践
|
||
- 本地保留最近 7 天的备份
|
||
- 异地保留最近 30 天的备份
|
||
- 每月进行一次恢复测试
|
||
- 备份文件加密存储(如含敏感数据)
|
||
:::
|