15 - 备份与恢复
数据是任何系统最有价值的资产。硬盘会故障、软件会出错、人也会误操作——备份是抵御数据丢失的最后防线。本章从策略到实施,覆盖 Linux 下备份与恢复的完整知识链。
15.1 备份的核心原则
3-2-1 备份法则
这是备份领域的黄金法则,任何规模的系统都应遵循:
| 原则 | 具体要求 |
|---|---|
| 3 份副本 | 1 份原始数据 + 2 份备份 |
| 2 种介质 | 至少两种不同的存储类型(本地磁盘 + 云/磁带/另一台服务器) |
| 1 份异地 | 至少 1 份存放在地理位置不同的地方(云存储、远程服务器) |
备份类型
| 类型 | 说明 | 优点 | 缺点 |
|---|---|---|---|
| 全量备份 | 复制所有数据 | 恢复最简单 | 耗时长、空间大 |
| 增量备份 | 仅备份上次备份后变化的数据 | 空间和时间最优 | 恢复需所有增量链 |
| 差异备份 | 备份自上次全量后所有变化 | 恢复只需全量+最后一次差异 | 比增量慢、比全量快 |
| 快照备份 | 文件系统级别快照(Btrfs/ZFS/LVM) | 秒级创建 | 依赖文件系统,需同一系统恢复 |
备份什么
# 必须备份的目录(按优先级)
/etc/ # 系统配置
/home/ # 用户数据
/var/log/ # 日志(保留审计追溯)
/var/spool/cron/ # 用户的 crontab
/root/ # root 用户的数据
/var/lib/ # 数据库、Docker 等运行时数据
/opt/ # 手动安装的应用
# 不必备份
/tmp/ # 临时文件
/proc/ /sys/ /dev/ # 虚拟文件系统
/run/ # 内存文件系统
/mnt/ /media/ # 其他文件系统的挂载点
/var/cache/ # 缓存(可重建)
/swapfile # 交换文件15.2 tar——归档与增量备份
tar 是 Linux 最基础的备份工具。完整 tar 指南见 44 章,这里聚焦备份场景。
全量备份
# 创建完整备份(gzip 压缩)
sudo tar -czf backup-$(date +%Y%m%d).tar.gz \
/etc /home /var/lib /var/spool/cron
# 使用 zstd 压缩(速度更快)
sudo tar --zstd -cf backup-$(date +%Y%m%d).tar.zst \
/etc /home /var/lib
# 排除不需要的目录
sudo tar -czf system-backup.tar.gz \
--exclude='/home/*/.cache' \
--exclude='/var/cache' \
--exclude='/tmp/*' \
--exclude='/proc' \
--exclude='/sys' \
--exclude='/dev' \
--exclude='/run' \
--exclude='/mnt' \
--exclude='/media' \
--exclude='node_modules' \
--exclude='__pycache__' \
--exclude='.git' \
/增量备份
# 第一次:创建全量备份 + 生成快照文件
sudo tar --listed-incremental=/backup/snapshot.snar \
-czf /backup/full-backup-$(date +%Y%m%d).tar.gz \
/home/user/data
# 第二次及以后:增量备份(使用同一快照文件)
sudo tar --listed-incremental=/backup/snapshot.snar \
-czf /backup/incr-backup-$(date +%Y%m%d).tar.gz \
/home/user/data
# 恢复:先恢复全量
sudo tar --listed-incremental=/dev/null \
-xzf /backup/full-backup-20250101.tar.gz -C /restore
# 再依次恢复增量
sudo tar --listed-incremental=/dev/null \
-xzf /backup/incr-backup-20250102.tar.gz -C /restore
sudo tar --listed-incremental=/dev/null \
-xzf /backup/incr-backup-20250103.tar.gz -C /restore保留元数据
# 保留权限、ACL、扩展属性和 SELinux 上下文
sudo tar --acls --xattrs --xattrs-include='*' --selinux \
--numeric-owner -cpf /backup/full-system.tar /
# 恢复时同理
sudo tar --acls --xattrs --xattrs-include='*' --selinux \
--numeric-owner -xpf /backup/full-system.tar -C /15.3 rsync——增量同步备份
rsync 是最常用的增量同步工具,通过仅传输差异内容大幅减少备份时间和带宽。
基本用法
# 本地同步
rsync -av /source/ /dest/
# 本地→远程
rsync -av /source/ user@backup-server:/dest/
# 远程→本地
rsync -av user@server:/source/ /local/dest/
# 常用参数
rsync -avz # -z 压缩传输
rsync -avP # -P 显示进度 + 断点续传
rsync -av --delete # 删除目标中源没有的文件(镜像)
rsync -av --delete --link-dest=/prev/backup /src/ /new/backup/常用参数速查
| 参数 | 说明 |
|---|---|
-a | 归档模式(保留权限、时间等) |
-v | 详细输出 |
-z | 传输时压缩 |
-P | 显示进度 + 断点续传 |
--delete | 删除目标多余文件 |
--exclude='pattern' | 排除匹配文件 |
--exclude-from=FILE | 从文件读取排除列表 |
--link-dest=DIR | 硬链接去重(快照式备份) |
--bwlimit=1000 | 限速 1MB/s |
-n / --dry-run | 模拟运行(不实际传输) |
--remove-source-files | 传输成功后删除源文件 |
快照式备份(—link-dest)
利用硬链接实现类似 Time Machine 的增量备份,每次备份看起来完整,但相同文件只占一份空间:
#!/bin/bash
# 基于 rsync + 硬链接的快照备份脚本
BACKUP_ROOT="/backup/home"
BACKUP_DIR="$BACKUP_ROOT/backup-$(date +%Y%m%d-%H%M)"
LATEST_LINK="$BACKUP_ROOT/latest"
mkdir -p "$BACKUP_ROOT"
rsync -av --delete \
--link-dest="$LATEST_LINK" \
--exclude='.cache' \
--exclude='node_modules' \
/home/alice/ "$BACKUP_DIR/"
# 删除旧备份:
# 保留最近 7 个
ls -dt "$BACKUP_ROOT"/backup-* | tail -n +8 | xargs rm -rf
# 更新软链接指向最新
rm -f "$LATEST_LINK"
ln -s "$BACKUP_DIR" "$LATEST_LINK"每次备份后,未变化的文件通过硬链接共享 inode(不占用额外空间),变化文件独立存储。
SSH 远程备份
# 带 SSH 密钥的远程备份
rsync -avz -e "ssh -p 2222" /data/ backup@server:/backups/data/
# 管道传输(通过 SSH 直接在两端压缩/解压)
tar -czf - /data | ssh backup@server "cat > /backups/data-$(date +%Y%m%d).tar.gz"15.4 dd——磁盘镜像
dd 是底层磁盘复制工具,用于创建完整的磁盘镜像(含分区表和引导)。
# 创建磁盘镜像
sudo dd if=/dev/sda of=/backup/disk-$(date +%Y%m%d).img bs=4M status=progress
# 恢复磁盘镜像
sudo dd if=/backup/disk-20250101.img of=/dev/sda bs=4M status=progress
# 只备份分区表
sudo dd if=/dev/sda of=/backup/sda-mbr.img bs=512 count=1
# 备份 + 压缩(减少空间)
sudo dd if=/dev/sda bs=4M status=progress | gzip > /backup/disk.img.gz
# 恢复压缩镜像
gunzip -c /backup/disk.img.gz | sudo dd of=/dev/sda bs=4M status=progress
# 克隆到另一块磁盘
sudo dd if=/dev/sda of=/dev/sdb bs=4M status=progress警示:dd 是危险的”数据毁灭器”。
if(input file) 和of(output file) 绝不可颠倒,写错就是永久覆盖。
15.5 BorgBackup——去重 + 压缩 + 加密
BorgBackup(简称 Borg)是现代化的去重备份工具,特别适合每天备份大量重复内容。同一文件在不同时间点的版本只存储差异。
安装
# Debian/Ubuntu
sudo apt install borgbackup
# Fedora/RHEL
sudo dnf install borgbackup
# Arch
sudo pacman -S borg
# openSUSE
sudo zypper install borgbackup基本流程
# 1. 初始化仓库(仅一次)
borg init --encryption=repokey /backup/borg-repo
# 可选加密方式:
# none 无加密
# repokey 密码+密钥文件(默认)
# keyfile 密码+密钥文件分离
# authenticated 仅验证(无加密)
# 记录下密码——丢失后无法恢复!
# 2. 创建备份(存档)
borg create --stats --progress \
/backup/borg-repo::home-{now:%Y%m%d-%H%M} \
/home/alice
# 属性占位符
# {now} 当前时间(可带 strftime 格式)
# {hostname} 主机名
# {user} 执行备份的用户
# 3. 列出存档
borg list /backup/borg-repo
# 4. 查看存档信息
borg info /backup/borg-repo::home-20250101-0300
# 5. 提取(恢复)
cd /restore
borg extract /backup/borg-repo::home-20250101-0300
# 挂载为 FUSE 文件系统(浏览式恢复)
borg mount /backup/borg-repo /mnt/borg
ls /mnt/borg # 列出所有存档
borg umount /mnt/borg高级用法
# 排除文件/目录
borg create /backup/borg-repo::home-{now} /home/alice \
--exclude '*.pyc' \
--exclude 'node_modules' \
--exclude '.cache' \
--exclude '*.log' \
--exclude-from /etc/borg-exclude.txt
# 精简(删除指定时间之前的存档)
borg prune --list /backup/borg-repo \
--keep-daily 7 # 保留最近 7 天的每日备份
--keep-weekly 4 # 保留最近 4 周的每周备份
--keep-monthly 6 # 保留最近 6 个月的每月备份
# 紧凑化(回收空间)
borg compact /backup/borg-repo
# 检查仓库完整性
borg check /backup/borg-repo
# 远程仓库(通过 SSH)
borg init backup@server:/backup/borg-repo --encryption=repokey
borg create backup@server:/backup/borg-repo::home-{now} /home/alice自动化备份脚本
#!/bin/bash
# 使用 Borg 的每日自动化备份
export BORG_REPO="/backup/borg-repo"
export BORG_PASSPHRASE="your-secure-password"
# 建议使用 BORG_PASSCOMMAND 从密码管理器读取
# export BORG_PASSCOMMAND="pass show backup/borg-password"
borg create --stats --compression zstd,9 \
--exclude '/home/*/.cache' \
--exclude '/tmp/*' \
::'{hostname}-{now:%Y%m%d-%H%M}' \
/etc /home
borg prune --list --stats \
--keep-daily 7 \
--keep-weekly 4 \
--keep-monthly 6
borg compactBorg 的核心优势
| 特性 | 说明 |
|---|---|
| 去重 | 相同数据块只存储一次,极大节省空间 |
| 压缩 | 内置 zstd/lz4/zlib 压缩 |
| 加密 | 客户端加密(AES-256),传输安全 |
| 校验 | 数据完整性自动验证 |
| 挂载 | FUSE 挂载,像浏览文件系统一样浏览备份 |
15.6 Restic——现代备份新选择
Restic 是另一款现代化备份工具,以简洁易用著称,原生支持多种云存储后端。
# 安装
# Debian/Ubuntu: apt install restic
# Fedora: dnf install restic
# Arch: pacman -S restic
# 初始化仓库
restic init --repo /backup/restic-repo
# 或远程仓库:
# restic init --repo sftp:user@server:/backup
# restic init --repo s3:s3.amazonaws.com/bucket-name
# 备份
restic backup --repo /backup/restic-repo /home/alice /etc
# 列出快照
restic snapshots --repo /backup/restic-repo
# 恢复
restic restore --repo /backup/restic-repo <snapshot-id> --target /restore
restic restore --repo /backup/restic-repo latest --target /restore
# 清理旧快照
restic forget --repo /backup/restic-repo \
--keep-daily 7 --keep-weekly 4 --keep-monthly 6
# 验证
restic check --repo /backup/restic-repoBorg vs Restic:
- Borg:去重算法更激进,同一台机器上的持续备份最省空间
- Restic:原生支持 S3、Azure、GCS 等云存储,跨平台更好
15.7 Timeshift——系统快照
Timeshift 为系统快照而设计,类似 Windows 的系统还原或 macOS 的 Time Machine。适合在系统大更新前创建可回滚的检查点。
# 安装
# Debian/Ubuntu
sudo apt install timeshift
# Fedora
sudo dnf install timeshift
# Arch
sudo pacman -S timeshift
# 图形界面
sudo timeshift-gtk
# 命令行——创建快照
sudo timeshift --create --comments "Before kernel upgrade"
# 列出快照
sudo timeshift --list
# 恢复快照
sudo timeshift --restore
# 交互式选择要恢复的快照
# 快照计划(通过 cron,自动配置)
# 默认策略:每天保留 5 个,每周保留 3 个注意事项:
- 仅备份系统文件(
/除/home外),用户数据需单独备份 - 需要 Btrfs 文件系统以获得秒级快照体验;ext4 使用 rsync 模式(较慢)
- 快照不是备份——如果同一磁盘损坏,快照也会丢失
15.8 数据库备份注意事项
生产环境中最容易出错的就是数据库备份。数据库在运行时文件持续变化,直接复制可能产生不一致的备份。
MySQL / MariaDB
# 逻辑备份(SQL 导出)
mysqldump -u root -p --all-databases --single-transaction \
| gzip > /backup/mysql-all-$(date +%Y%m%d).sql.gz
# 备份单个数据库
mysqldump -u root -p mydb | gzip > /backup/mydb-$(date +%Y%m%d).sql.gz
# 恢复
gunzip -c /backup/mydb-20250101.sql.gz | mysql -u root -p mydbPostgreSQL
# 逻辑备份
pg_dumpall -U postgres | gzip > /backup/pg-all-$(date +%Y%m%d).sql.gz
# 备份单个数据库
pg_dump -U postgres mydb | gzip > /backup/mydb-$(date +%Y%m%d).sql.gz
# 恢复
gunzip -c /backup/mydb-20250101.sql.gz | psql -U postgres mydb数据库备份的详细策略、WAL 归档、流复制等内容见 58-数据库运维(主从+备份+优化)。
15.9 恢复流程与测试
恢复不是”有备份就够了”
没有经过验证的备份等于没有备份。必须定期执行恢复测试。
# 基本验证流程
# 1. 检查备份文件是否存在且大小合理
ls -lh /backup/system-$(date +%Y%m%d).tar.gz
# 2. 验证 tar 归档完整性
tar -tzf /backup/system-20250101.tar.gz > /dev/null && echo "OK" || echo "损坏"
# 3. 验证 Borg 仓库完整性
borg check --verify-data /backup/borg-repo
# 4. 测试恢复——在临时目录尝试恢复关键文件
mkdir -p /tmp/restore-test
borg extract /backup/borg-repo::latest --target /tmp/restore-test \
--pattern '+/etc/nginx' --pattern '-**'
diff -r /etc/nginx /tmp/restore-test/etc/nginx
rm -rf /tmp/restore-test灾难恢复流程
当系统完全不可用时(硬件故障、根分区损坏):
1. 准备新磁盘/服务器
2. 使用 Live USB / 恢复介质启动
3. 分区并格式化磁盘
4. 恢复系统镜像(dd 或 rsync)
5. 修复引导加载程序
6. 检查 fstab 与 UUID 匹配
7. 重启验证
具体步骤(使用 tar + rsync 的简单恢复):
# 1. 从 Live USB 启动
# 2. 分区、格式化新磁盘
sudo parted /dev/sda mklabel gpt
sudo parted /dev/sda mkpart primary ext4 1MiB 100%
sudo mkfs.ext4 /dev/sda1
# 3. 挂载
sudo mount /dev/sda1 /mnt
# 4. 恢复数据
sudo tar -xzf /media/backup/system-20250101.tar.gz -C /mnt
# 5. 修复 fstab UUID(新分区 UUID 不同)
lsblk -f /dev/sda1 # 获取新 UUID
# 编辑 /mnt/etc/fstab
# 6. 重新生成 initramfs
sudo arch-chroot /mnt mkinitcpio -P
# 或对应发行版命令:sudo chroot /mnt update-initramfs -u
# 7. 修复引导
sudo arch-chroot /mnt grub-install /dev/sda
# 或 sudo chroot /mnt grub-install /dev/sda
# 8. 重启15.10 备份方案对比
| 工具 | 类型 | 去重 | 加密 | 云存储 | 适用场景 |
|---|---|---|---|---|---|
tar | 文件归档 | 否 | 需外部(gpg) | 需外部 | 一次性打包、源码分发 |
rsync | 增量同步 | 否 | SSH | SSH 远程 | 每日文件同步 |
dd | 磁盘镜像 | 否 | 否 | 否 | 整盘克隆、取证 |
| BorgBackup | 块级去重 | 是 | 是 | SSH 管道 | 持续增量备份 |
| Restic | 块级去重 | 是 | 是 | S3/Azure/GCS 原生 | 多云存储备份 |
| Timeshift | 系统快照 | Btrfs 模式 | 否 | 否 | 系统级回滚 |
| LVM 快照 | 块级快照 | 否 | 否 | 否 | 数据库热备份前预处理 |
15.11 自动化备份最佳实践
一个生产级备份方案应考虑以下要素:
#!/bin/bash
# 综合性每日备份脚本
set -euo pipefail
BACKUP_ROOT="/backup"
DATE=$(date +%Y%m%d)
LOG_FILE="$BACKUP_ROOT/backup-$DATE.log"
exec > >(tee -a "$LOG_FILE") 2>&1
echo "=== Backup started at $(date) ==="
# 1. 文件备份(rsync 快照式)
echo "[1/3] File backup..."
rsync -av --delete \
--link-dest="$BACKUP_ROOT/rsync/latest" \
--exclude='.cache' \
--exclude='node_modules' \
/home/ "$BACKUP_ROOT/rsync/backup-$DATE/"
# 2. 系统配置备份(Borg 去重)
echo "[2/3] System config backup..."
borg create --stats "$BACKUP_ROOT/borg::system-$DATE" \
/etc /var/spool/cron /var/lib
# 3. 数据库备份
echo "[3/3] Database dump..."
mysqldump --all-databases --single-transaction \
| gzip > "$BACKUP_ROOT/mysql/all-$DATE.sql.gz"
# 清理
echo "[Cleanup] Removing old backups..."
borg prune --keep-daily 7 --keep-weekly 4 --keep-monthly 6 "$BACKUP_ROOT/borg"
find "$BACKUP_ROOT/rsync" -maxdepth 1 -name 'backup-*' -mtime +7 -exec rm -rf {} +
find "$BACKUP_ROOT/mysql" -name '*.sql.gz' -mtime +30 -delete
echo "=== Backup completed at $(date) ==="将此脚本配合 systemd timer 或 cron 定时执行即可实现自动化备份。详见 15-计划任务与自动化。
备份通知
备份脚本应包含告警机制:
# 备份完成后发送通知(示例:通过 healthchecks.io)
curl -fsS --retry 3 https://hc-ping.com/your-uuid/$?
# 或通过邮件/Webhook 通知
# mail -s "Backup Report" admin@example.com < "$LOG_FILE"15.12 文件误删恢复
紧急操作流程
发现文件误删后,立即停止一切写入操作,防止被删除的数据块被覆盖:
- umount 分区:
umount /dev/sdXn(如果在 /home 等非根分区) - 只读重挂载:
mount -o remount,ro /(根分区无法 umount 时) - 判断文件系统类型:
df -Th /path或blkid /dev/sdXn - 选择恢复路径:根据文件系统类型选择对应工具
- 决策流程:ext4 → extundelete/debugfs;Btrfs → snapper rollback;格式化后 → photorec;分区表损坏 → testdisk
ext4 恢复:extundelete
原理:基于 ext4 的 journal(日志)回溯,扫描 journal 中尚未提交的 inode 和间接块引用,恢复被删除的文件。
# 安装
apt install extundelete # Debian/Ubuntu
yum install extundelete # RHEL/CentOS
# 恢复单个文件
extundelete /dev/sdXn --restore-file path/to/deleted/file
# 恢复整个目录
extundelete /dev/sdXn --restore-dir path/to/deleted/dir/
# 恢复所有已删除文件
extundelete /dev/sdXn --restore-all
# 指定输出目录
extundelete --output-dir /tmp/recovered /dev/sdXn --restore-all限制:必须卸载或只读挂载分区;如果 journal 已被覆写或已执行 fsck,恢复率大幅下降。
通用文件雕刻:photorec
原理:不依赖文件系统元数据,按文件头(magic bytes)逐扇区扫描。支持 ext2/3/4、NTFS、FAT、exFAT 等几乎所有文件系统,甚至格式化后的磁盘。
# 安装
apt install testdisk # photorec 包含在 testdisk 中
# 交互式运行
photorec /dev/sdXn
# 操作步骤:
# 1. 选择磁盘/分区
# 2. 选择文件系统类型(通常选 [Other] → ext4)
# 3. 选择恢复文件的存储位置(不要写回原分区!)
# 4. 选择要恢复的文件类型
# 5. 等待扫描完成适用场景:格式化后恢复、文件系统严重损坏、多种文件类型混合恢复。
限制:文件名丢失,恢复出的文件按编号命名(f12345.jpg);大文件可能被截断;恢复速度取决于磁盘大小。
分区恢复:testdisk
# 安装
apt install testdisk
# 启动
testdisk /dev/sdX
# 主要功能:
# 1. 分区表恢复(Advanced → 选择磁盘 → Boot → Recovery)
# 2. 修复引导(Boot → Rebuild BS)
# 3. 恢复已删除分区(Analyse → Quick Search)操作流程:
- 选择目标磁盘
- 选择分区表类型(Intel/PC、EFI GPT)
- Analyse → Quick Search → 找到丢失的分区
- 选择分区 → Write 写入分区表
ext4 底层调试:debugfs
# 安装
apt install e2fsprogs
# 打开文件系统
debugfs /dev/sdXn
# 在 debugfs 中:
# 列出最近删除的 inode
debugfs -R 'lsdel' /dev/sdXn
# 查看 inode 详情
debugfs -R 'stat <12345>' /dev/sdXn
# 恢复指定 inode
debugfs -R 'dump <12345> /tmp/recovered_file' /dev/sdXn精确恢复流程:
lsdel列出最近删除的 inode- 根据大小和时间找到目标 inode
stat <inode>确认文件内容dump <inode> <output>导出文件undel <inode> <pathname>恢复文件名关联
Btrfs 快照回滚恢复
# 列出快照,找到误删前的时间点
snapper list
# 找到目标快照后回滚
snapper rollback <snapshot-number>
# 或者直接从快照复制文件
cp /mnt/.snapshots/<snap>/subvol/@/path/to/file /mnt/recovered/优势:秒级完成、数据完整、无需第三方工具、保留原始文件名和权限。
xfs 恢复
# xfs_repair — 修复文件系统(类似 fsck)
xfs_repair /dev/sdXn
# xfs_db — 底层调试
xfs_db /dev/sdXn
# xfs_db 中:
# p — 打印当前 inode 信息
# ls — 列出目录内容
# ftree — 遍历文件树
# quit — 退出恢复工具选择表
| 工具 | 文件系统 | 场景 | 优势 | 限制 |
|---|---|---|---|---|
| extundelete | ext4 | 删除后恢复 | 基于 journal,恢复率高 | 需卸载,journal 被覆写后效果差 |
| photorec | 通用 | 格式化/损坏后恢复 | 不依赖文件系统 | 文件名丢失,大文件截断 |
| testdisk | 通用 | 分区表损坏/分区恢复 | 恢复分区表和引导 | 不直接恢复文件 |
| debugfs | ext4 | 精确恢复单个文件 | 底层精确操作 | 操作复杂,需手动定位 inode |
| snapper rollback | Btrfs | 快照回滚 | 秒级、完整、无损 | 依赖预先创建的快照 |
| xfs_repair | XFS | 文件系统修复 | 官方工具,可靠性高 | 不恢复已删除文件 |