09 - 备份与恢复
09 - 备份与恢复
9.1 备份策略
9.1.1 为什么备份如此重要
| 风险场景 | 后果 | 备份能否解决 |
|---|
| 世界文件损坏 | 玩家建筑丢失 | ✅ |
| 恶意破坏(Grief) | 区域被毁 | ✅ |
| 误操作删除 | 数据丢失 | ✅ |
| 插件数据损坏 | 配置丢失 | ✅ |
| 服务器硬件故障 | 全部数据丢失 | ✅(异地备份) |
| 勒索软件攻击 | 数据被加密 | ✅(离线备份) |
9.1.2 备份策略 3-2-1 原则
3 份副本:数据本身 + 2 份备份
2 种介质:本地 + 异地(或不同存储设备)
1 份离线:至少 1 份离线备份(防勒索软件)
9.1.3 备份频率建议
| 服务器类型 | 建议频率 | 保留时间 | 备份类型 |
|---|
| 小型私人服 | 每天 1 次 | 7 天 | 全量 |
| 中型社区服 | 每 6 小时 | 14 天 | 增量 + 全量 |
| 大型公共服 | 每 2 小时 | 30 天 | 增量 + 全量 |
| 生产/商业服 | 每小时 | 90 天 | 增量 + 全量 + 异地 |
9.2 全量备份
9.2.1 简单备份脚本
#!/bin/bash
# simple-backup.sh - 简单全量备份脚本
# ============ 配置 ============
SERVER_DIR="/opt/minecraft/paper"
BACKUP_DIR="/opt/minecraft/backups"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
BACKUP_NAME="mc_backup_${TIMESTAMP}"
SCREEN_NAME="minecraft"
KEEP_COUNT=10 # 保留最近 N 个备份
# ============ 初始化 ============
mkdir -p "$BACKUP_DIR"
echo "[$(date)] === 开始备份 ==="
# ============ 通知服务器 ============
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "say §e[备份] 正在创建备份,请稍候...\015"'
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "save-off\015"'
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "save-all\015"'
sleep 5
# ============ 执行备份 ============
echo "[$(date)] 正在备份世界文件..."
tar -czf "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" \
-C "$SERVER_DIR" \
--exclude='cache' \
--exclude='libraries' \
--exclude='logs/latest.log' \
world world_nether world_the_end \
plugins config \
server.properties \
bukkit.yml spigot.yml \
banned-players.json banned-ips.json \
ops.json whitelist.json \
2>/dev/null
# ============ 恢复自动保存 ============
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "save-on\015"'
# ============ 检查备份结果 ============
if [ -f "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" ]; then
SIZE=$(du -h "${BACKUP_DIR}/${BACKUP_NAME}.tar.gz" | cut -f1)
echo "[$(date)] 备份成功: ${BACKUP_NAME}.tar.gz (${SIZE})"
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "say §a[备份] 备份完成!\015"'
else
echo "[$(date)] 备份失败!"
screen -S "$SCREEN_NAME" -p 0 -X eval 'stuff "say §c[备份] 备份失败!\015"'
exit 1
fi
# ============ 清理旧备份 ============
echo "[$(date)] 清理旧备份(保留最近 ${KEEP_COUNT} 个)..."
ls -t ${BACKUP_DIR}/mc_backup_*.tar.gz 2>/dev/null | tail -n +$((KEEP_COUNT + 1)) | while read f; do
echo "[$(date)] 删除旧备份: $(basename $f)"
rm -f "$f"
done
echo "[$(date)] === 备份完成 ==="
9.2.2 完整服务器备份
#!/bin/bash
# full-backup.sh - 完整服务器备份(包含 JAR 和所有配置)
SERVER_DIR="/opt/minecraft/paper"
BACKUP_DIR="/opt/minecraft/backups/full"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# 备份整个服务器目录(排除缓存和日志)
tar -czf "${BACKUP_DIR}/full_${TIMESTAMP}.tar.gz" \
-C "$(dirname $SERVER_DIR)" \
--exclude='*.cache' \
--exclude='logs/*.log' \
--exclude='cache' \
--exclude='libraries' \
"$(basename $SERVER_DIR)"
echo "完整备份完成: full_${TIMESTAMP}.tar.gz"
ls -lh "${BACKUP_DIR}/full_${TIMESTAMP}.tar.gz"
9.3 增量备份
增量备份仅备份自上次备份后变更的文件,节省空间和时间。
9.3.1 使用 rsync 增量备份
#!/bin/bash
# incremental-backup.sh - 使用 rsync 增量备份
SERVER_DIR="/opt/minecraft/paper"
BACKUP_DIR="/opt/minecraft/backups/incremental"
LATEST_LINK="${BACKUP_DIR}/latest"
TIMESTAMP=$(date +%Y%m%d_%H%M%S)
mkdir -p "$BACKUP_DIR"
# rsync 增量备份(硬链接未变更文件)
rsync -a --delete \
--link-dest="$LATEST_LINK" \
--exclude='cache' \
--exclude='libraries' \
--exclude='logs/latest.log' \
"$SERVER_DIR/" \
"${BACKUP_DIR}/${TIMESTAMP}/"
# 更新 latest 链接
rm -f "$LATEST_LINK"
ln -s "${BACKUP_DIR}/${TIMESTAMP}" "$LATEST_LINK"
echo "增量备份完成: ${TIMESTAMP}"
echo "备份大小: $(du -sh ${BACKUP_DIR}/${TIMESTAMP} | cut -f1)"
9.3.2 使用 restic 增量备份
# 安装 restic
sudo apt install restic # Debian/Ubuntu
sudo dnf install restic # Fedora
# 初始化备份仓库
restic init --repo /opt/minecraft/backups/restic
# 执行增量备份
restic backup /opt/minecraft/paper \
--repo /opt/minecraft/backups/restic \
--exclude cache \
--exclude libraries \
--tag minecraft
# 查看备份列表
restic snapshots --repo /opt/minecraft/backups/restic
# 恢复到指定时间点
restic restore latest \
--repo /opt/minecraft/backups/restic \
--target /opt/minecraft/paper-restored
# 设置保留策略
restic forget \
--repo /opt/minecraft/backups/restic \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6 \
--prune
9.4 WorldEdit 区域还原
对于局部破坏(如熊孩子破坏),WorldEdit 的还原比全量备份恢复更精准。
9.4.1 WorldEdit 备份与还原
# 1. 选中要保护的区域
//pos1 # 选择第一个角
//pos2 # 选择第二个角
# 2. 创建快照(保存到文件)
//save my_backup # 保存为 my_backup.schematic
# 3. 还原区域
//load my_backup # 加载快照
//paste # 粘贴到当前位置
# 4. 还原并匹配空气
//paste -a # 粘贴(包含空气方块)
9.4.2 CoreProtect 区域回滚
CoreProtect 是回滚玩家操作的首选工具:
# 查看 50 格范围内最近 24 小时的操作
/co lookup u:Griefer t:24h r:50
# 回滚特定玩家的操作
/co rollback u:Griefer t:24h r:50
# 回滚方块破坏
/co rollback u:Griefer t:24h r:50 a:break
# 回滚方块放置
/co rollback u:Griefer t:24h r:50 a:place
# 回滚容器操作(拿取物品)
/co rollback u:Griefer t:24h r:50 a:container
# 恢复回滚(如果回滚错误)
/co restore u:Griefer t:24h r:50
# 查看回滚结果
/co lookup u:Griefer t:24h r:50 a:+break,-place
9.4.3 CoreProtect 操作查询
# 检查特定方块
/co inspect # 开启检查模式
# 然后点击方块查看操作历史
# 查看谁破坏了某个方块
/co lookup t:7d r:5 a:break
# 查看最近的 TNT 爆炸
/co lookup a:explode t:1h r:100
# 查看容器被谁打开过
/co lookup a:container t:24h r:20
9.5 云备份方案
9.5.1 使用 rclone 上传到云存储
# 安装 rclone
curl https://rclone.org/install.sh | sudo bash
# 配置云存储(以 Google Drive 为例)
rclone config
# 按提示选择 Google Drive 并完成授权
# 上传备份
rclone copy /opt/minecraft/backups/mc_backup_latest.tar.gz \
remote:minecraft-backups/ \
--progress
# 自动同步
rclone sync /opt/minecraft/backups/ \
remote:minecraft-backups/ \
--include "*.tar.gz" \
--progress
9.5.2 支持的云存储
| 服务 | 配置命令 | 特点 |
|---|
| Google Drive | rclone config | 15GB 免费 |
| OneDrive | rclone config | 5GB 免费 |
| Dropbox | rclone config | 2GB 免费 |
| S3 (AWS) | rclone config | 按量付费 |
| 阿里云 OSS | rclone config | 国内首选 |
| 腾讯云 COS | rclone config | 国内备选 |
| 坚果云 | rclone config | WebDAV 协议 |
9.5.3 使用 Duplicity 加密备份
# 安装
sudo apt install duplicity
# 加密备份到云存储
duplicity /opt/minecraft/paper/world \
s3://s3.amazonaws.com/my-bucket/minecraft-backup \
--encrypt-key YOUR_GPG_KEY \
--full-if-older-than 7D
# 恢复
duplicity restore \
s3://s3.amazonaws.com/my-bucket/minecraft-backup \
/opt/minecraft/paper/world-restored
9.6 自动备份定时任务
9.6.1 Crontab 配置
# 编辑 crontab
crontab -e
# 每 6 小时全量备份
0 */6 * * * /opt/minecraft/scripts/backup.sh >> /var/log/mc-backup.log 2>&1
# 每天凌晨 2 点做完整备份
0 2 * * * /opt/minecraft/scripts/full-backup.sh >> /var/log/mc-backup.log 2>&1
# 每周日凌晨 3 点上传到云存储
0 3 * * 0 /opt/minecraft/scripts/cloud-upload.sh >> /var/log/mc-backup.log 2>&1
# 每月 1 日清理旧云备份
0 4 1 * * rclone delete remote:minecraft-backups/ --min-age 90d
9.6.2 Systemd Timer(替代 Crontab)
# /etc/systemd/system/mc-backup.timer
[Unit]
Description=Minecraft Backup Timer
[Timer]
OnCalendar=*-*-* */6:00:00
Persistent=true
[Install]
WantedBy=timers.target
# /etc/systemd/system/mc-backup.service
[Unit]
Description=Minecraft Backup Service
[Service]
Type=oneshot
ExecStart=/opt/minecraft/scripts/backup.sh
User=minecraft
sudo systemctl daemon-reload
sudo systemctl enable mc-backup.timer
sudo systemctl start mc-backup.timer
# 查看定时器状态
sudo systemctl list-timers mc-backup.timer
9.7 备份验证
9.7.1 自动验证脚本
#!/bin/bash
# verify-backup.sh - 验证备份完整性
BACKUP_FILE="$1"
VERIFY_DIR="/tmp/mc-backup-verify"
if [ -z "$BACKUP_FILE" ]; then
echo "用法: $0 <备份文件路径>"
exit 1
fi
echo "=== 备份验证 ==="
echo "文件: $BACKUP_FILE"
# 1. 检查文件是否存在
if [ ! -f "$BACKUP_FILE" ]; then
echo "错误: 备份文件不存在"
exit 1
fi
# 2. 检查文件大小
SIZE=$(stat -c%s "$BACKUP_FILE")
if [ "$SIZE" -lt 1024 ]; then
echo "错误: 备份文件过小 (${SIZE} bytes)"
exit 1
fi
echo "文件大小: $(du -h "$BACKUP_FILE" | cut -f1)"
# 3. 验证压缩完整性
if [[ "$BACKUP_FILE" == *.tar.gz ]]; then
if gzip -t "$BACKUP_FILE" 2>/dev/null; then
echo "压缩完整性: 通过"
else
echo "错误: 压缩文件损坏"
exit 1
fi
fi
# 4. 检查关键文件是否存在
rm -rf "$VERIFY_DIR"
mkdir -p "$VERIFY_DIR"
tar -xzf "$BACKUP_FILE" -C "$VERIFY_DIR" 2>/dev/null
MISSING=0
for f in world/level.dat plugins; do
if [ ! -e "${VERIFY_DIR}/$f" ]; then
echo "警告: 缺少 $f"
MISSING=$((MISSING + 1))
fi
done
if [ "$MISSING" -eq 0 ]; then
echo "关键文件: 全部存在"
else
echo "警告: 缺少 ${MISSING} 个关键文件"
fi
# 5. 清理
rm -rf "$VERIFY_DIR"
echo "=== 验证完成 ==="
9.8 备份管理最佳实践
9.8.1 备份存储策略
| 时间段 | 保留策略 | 存储位置 |
|---|
| 最近 24 小时 | 每 6 小时保留 | 本地 SSD |
| 最近 7 天 | 每天保留 | 本地 HDD |
| 最近 30 天 | 每周保留 | NAS/云存储 |
| 30 天以上 | 每月保留 | 冷存储/归档 |
9.8.2 备份清单文档
## 备份清单
| 备份类型 | 频率 | 保留时间 | 存储位置 | 负责人 |
|----------|------|----------|----------|--------|
| 世界增量 | 每 6h | 7 天 | 本地 | 自动脚本 |
| 全量备份 | 每天 | 30 天 | NAS | 自动脚本 |
| 异地备份 | 每周 | 90 天 | 云存储 | 手动触发 |
| 配置备份 | 每次变更 | 永久 | Git | 开发者 |
## 恢复测试
- [ ] 每月执行一次恢复测试
- [ ] 验证恢复后服务器可正常启动
- [ ] 验证玩家数据完整性
9.9 灾难恢复流程
9.9.1 完整恢复步骤
# 1. 停止服务器
sudo systemctl stop minecraft
# 2. 备份当前损坏的数据(以防万一)
mv /opt/minecraft/paper /opt/minecraft/paper_damaged_$(date +%s)
# 3. 从备份恢复
BACKUP_FILE="/opt/minecraft/backups/full/full_20260510.tar.gz"
mkdir -p /opt/minecraft/paper
tar -xzf "$BACKUP_FILE" -C /opt/minecraft/
# 4. 确认权限
chown -R minecraft:minecraft /opt/minecraft/paper
# 5. 启动服务器测试
sudo systemctl start minecraft
# 6. 检查日志
sudo journalctl -u minecraft -f
# 7. 验证服务器状态
# 在游戏内连接并检查世界是否正常
9.9.2 部分恢复(仅恢复世界)
# 1. 停止服务器
sudo systemctl stop minecraft
# 2. 备份当前世界
mv /opt/minecraft/paper/world /opt/minecraft/paper/world_broken
# 3. 从备份中仅提取世界
tar -xzf /opt/minecraft/backups/latest.tar.gz -C /opt/minecraft/paper/ world/
# 4. 启动服务器
sudo systemctl start minecraft
9.10 常见问题
Q1:备份时服务器卡顿?
# 使用 nice 降低备份进程优先级
nice -n 19 /opt/minecraft/scripts/backup.sh
# 使用 ionice 降低 IO 优先级
ionice -c 3 /opt/minecraft/scripts/backup.sh
# 使用 pigz 多线程压缩
tar -cf - world | pigz -p 4 > backup.tar.gz
Q2:备份文件太大?
# 使用 zstd 压缩(比 gzip 更快更小)
tar --zstd -cf backup.tar.zst world/
# 修剪世界中未使用的区块(详见第 04 章)
java -jar mcaselector.jar --mode delete --world world --radius 10000 --center 0,0
# 排除不必要的文件
tar -czf backup.tar.gz --exclude='world/region/r.10.*' world/
Q3:如何恢复被删除的玩家数据?
# 从 CoreProtect 恢复(如果有记录)
/co restore u:<玩家名> t:7d
# 从备份中提取玩家数据
tar -xzf backup.tar.gz world/playerdata/<uuid>.dat
# 从 LuckPerms 恢复权限
/lp user <玩家名> import
9.11 本章小结
| 要点 | 说明 |
|---|
| 遵循 3-2-1 原则 | 3 份副本、2 种介质、1 份离线 |
| 定期自动备份 | Crontab 或 Systemd Timer |
| 增量备份节省空间 | rsync 或 restic |
| 定期验证备份 | 确保备份可恢复 |
| CoreProtect 用于局部回滚 | 比全量恢复更精准 |
| 云备份防灾难 | 异地存储是最后防线 |
扩展阅读