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传输成功后删除源文件

利用硬链接实现类似 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 是底层磁盘复制工具,用于创建完整的磁盘镜像(含分区表和引导)。

存储管理详细内容见第 10 章

# 创建磁盘镜像
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 compact

Borg 的核心优势

特性说明
去重相同数据块只存储一次,极大节省空间
压缩内置 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-repo

Borg 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 mydb

PostgreSQL

# 逻辑备份
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增量同步SSHSSH 远程每日文件同步
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 文件误删恢复

紧急操作流程

发现文件误删后,立即停止一切写入操作,防止被删除的数据块被覆盖:

  1. umount 分区umount /dev/sdXn(如果在 /home 等非根分区)
  2. 只读重挂载mount -o remount,ro /(根分区无法 umount 时)
  3. 判断文件系统类型df -Th /pathblkid /dev/sdXn
  4. 选择恢复路径:根据文件系统类型选择对应工具
  5. 决策流程: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)

操作流程

  1. 选择目标磁盘
  2. 选择分区表类型(Intel/PC、EFI GPT)
  3. Analyse → Quick Search → 找到丢失的分区
  4. 选择分区 → 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

精确恢复流程

  1. lsdel 列出最近删除的 inode
  2. 根据大小和时间找到目标 inode
  3. stat <inode> 确认文件内容
  4. dump <inode> <output> 导出文件
  5. 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   — 退出

恢复工具选择表

工具文件系统场景优势限制
extundeleteext4删除后恢复基于 journal,恢复率高需卸载,journal 被覆写后效果差
photorec通用格式化/损坏后恢复不依赖文件系统文件名丢失,大文件截断
testdisk通用分区表损坏/分区恢复恢复分区表和引导不直接恢复文件
debugfsext4精确恢复单个文件底层精确操作操作复杂,需手动定位 inode
snapper rollbackBtrfs快照回滚秒级、完整、无损依赖预先创建的快照
xfs_repairXFS文件系统修复官方工具,可靠性高不恢复已删除文件