Ubuntu服务器在运行几个月甚至几年后,管理员最怕看到的画面不是内核崩溃,而是磁盘故障后才发现最近一次备份是半年前的手动快照。备份这件事,说穿了就是对抗墨菲定律——你越觉得不会出事,它越可能出事。所以与其讨论“要不要备份”,不如直接拆解三种最实用的方案:快照、tar打包和云备份,看看它们各自适合什么场景,怎么组合才能睡得着觉。

快照备份:秒级恢复的底层武器

快照不是复制文件,而是冻结文件系统某一时刻的状态。在Ubuntu上,如果你使用LVM(逻辑卷管理)或者ZFS文件系统,快照几乎是零成本的保护手段。LVM快照的原理是写时复制(COW),创建快照时不会立刻占用大量空间,只有当原始数据块被修改时,系统才会把旧数据拷贝到快照预留的空间里。这意味着你可以在几秒钟内创建一个数十GB逻辑卷的快照,而实际占用空间远小于卷本身。

实际操作中,假设你的根文件系统挂载在/dev/ubuntu-vg/root上,创建一个10GB预留空间的快照只需要两条命令:

sudo lvcreate -L 10G -s -n root_snapshot_202501 /dev/ubuntu-vg/root

这条命令会在同一卷组下生成名为root_snapshot_202501的快照卷。之后你可以把它挂载到某个目录,像读取普通文件系统一样恢复单个文件,或者用dd命令把整个快照导出成镜像。但LVM快照有个致命弱点:一旦预留空间被写满,快照就会自动失效,而且写时复制会拖慢写入性能。所以LVM快照更适合短期保护,比如在做系统升级前拍一张,出问题立刻回滚。

如果你用的是ZFS文件系统,快照体验会好得多。ZFS的快照同样是写时复制,但不需要预分配空间,可以无限增量,且发送和接收机制让远程备份变得极其优雅。创建ZFS快照只需:

sudo zfs snapshot tank/var@daily_202501

然后可以用zfs send把快照流式传输到另一台机器或本地文件:

sudo zfs send tank/var@daily_202501 | gzip > /backup/var_snap.gz

ZFS快照的真正威力在于增量发送。假设你已经有了昨天的快照,今天只需要发送差异部分:

sudo zfs send -i tank/var@daily_202501 tank/var@daily_202502 | ssh user@remote "zfs receive tank/backup/var"

这套机制让ZFS成为数据库和文件服务器的黄金搭档,恢复粒度可以精确到分钟级,而且增量传输节省了大量带宽。但ZFS对内存要求较高,且Ubuntu默认安装不会启用,需要手动配置。

tar归档:最朴素的瑞士军刀

tar是Unix世界最古老的备份工具之一,至今仍然无可替代。它的优势在于极度通用——任何Linux发行版都有tar,任何管理员都看得懂tar包,解压不需要特殊文件系统。但很多人用tar只是简单打包整个目录,这其实浪费了它的能力。

一个生产级的tar备份脚本至少要考虑这些细节:排除不需要的目录(/proc、/sys、/tmp、/dev等虚拟文件系统)、保留文件权限和扩展属性、处理稀疏文件、压缩时平衡CPU和空间。下面是一个可以直接放进crontab的备份脚本片段:

#!/bin/bash
BACKUP_DIR="/backup"
DATE=$(date +%Y%m%d_%H%M%S)
HOSTNAME=$(hostname)
ARCHIVE_NAME="${HOSTNAME}_full_${DATE}.tar.gz"

tar -czpf "${BACKUP_DIR}/${ARCHIVE_NAME}" \
    --exclude=/proc \
    --exclude=/sys \
    --exclude=/dev \
    --exclude=/tmp \
    --exclude=/run \
    --exclude=/mnt \
    --exclude=/media \
    --exclude=/lost+found \
    --exclude=/var/cache \
    --exclude=/var/tmp \
    --exclude=/swapfile \
    --one-file-system \
    / 2>> "${BACKUP_DIR}/error.log"

这里几个参数值得展开:-p保留权限和所有权,--one-file-system防止跨文件系统打包(比如你不小心把挂载的NFS共享也打包进来),--exclude跳过那些重启后会重新生成或根本不该备份的目录。压缩算法方面,gzip虽然古老但解压速度最快,如果你的CPU资源紧张,可以换成pigz做并行压缩,或者用zstd在压缩率和速度之间取得更好平衡。

tar最大的短板是恢复时间长。要恢复单个文件,你需要解压整个归档或者至少遍历到目标文件的位置。对于TB级别的备份,这个操作可能耗时数小时。所以tar更适合全量备份配合定期轮换的策略,比如保留最近7天的每日备份和最近4周的每周备份。可以用find命令自动清理过期归档:

find /backup -name "*.tar.gz" -mtime +7 -delete

还有一个容易被忽略的细节:tar备份的完整性验证。你至少应该在备份完成后用tar -tzf列出归档内容,确认没有报错,更严谨的做法是计算校验和并存储到独立位置,防止静默数据损坏。

云备份:异地容灾的最后防线

本地快照和tar归档解决了“快速恢复”和“历史版本”的问题,但如果机房火灾、服务器被盗或者磁盘阵列同时挂掉两块盘,本地备份再多也无济于事。这就是异地备份存在的意义,而云存储是目前成本最低的异地方案。

Ubuntu对接云备份主要有两条路:用云厂商的原生CLI工具,或者用rclone这样的统一接口。AWS CLI、Azure CLI和Google Cloud SDK都能直接上传文件,但rclone的优势在于支持50多种存储后端,配置一次就能在不同云之间迁移,而且支持加密、压缩和增量同步。

安装rclone后,配置一个S3兼容的远程存储(以Backblaze B2为例,因为它的存储费用比AWS S3低很多,且下载流量前10GB免费):

sudo apt install rclone
rclone config

交互式配置会引导你选择存储类型、输入密钥、设置端点。配置完成后,一条命令就能把本地备份目录同步到云端:

rclone sync /backup remote:bucket-name/ubuntu-backups --progress --transfers 4

sync命令会让云端目录与本地完全一致,删除云端多余文件,所以适合做镜像型备份。如果你需要保留云端的历史版本,应该用copy命令,或者开启B2的桶版本控制功能。rclone还支持crypt后端,可以在文件上传前用AES-256加密,密钥只存在于你的服务器上,云厂商即使被攻破也看不到内容。

云备份的成本结构需要仔细算账。以Backblaze B2为例,存储费约每TB每月6美元,下载费每GB 0.01美元。如果你有500GB数据,每月存储费约3美元,看起来很低,但一次完整恢复就要花5美元下载费。所以云备份更适合作为“灾难恢复的最后手段”,日常恢复优先用本地备份。另外,上传带宽是很多人的瓶颈,首次全量备份可能需要几天甚至几周,建议先用物理方式(比如把硬盘寄到数据中心)完成初始同步,之后只做增量。

自动化方面,可以把rclone命令放进crontab,但要注意设置合理的重试和日志:

0 3 * * * /usr/bin/rclone sync /backup remote:bucket/backups --log-file=/var/log/rclone.log --log-level INFO --retries 3 --timeout 30m

另外,云备份不等于“设好就忘”。你需要定期做恢复演练,至少每月一次从云端随机抽取几个文件下载验证,确认加密密钥还能用、权限没被意外修改、存储桶没欠费停服。很多公司的备份策略在纸面上完美无缺,出事时才发现云端数据因为账号欠费已经被清空三个月了。

三种方案的组合策略:3-2-1原则的落地

业界流传的3-2-1备份原则——3份副本、2种不同介质、1份异地——在Ubuntu环境下可以这样落地:主服务器上用ZFS快照实现小时级保护,每天凌晨用tar做全量归档到本地NAS或外接硬盘(不同介质),同时rclone把归档同步到云端(异地)。这样,误删文件可以从ZFS快照秒级恢复,昨天之前的版本从tar归档提取,机房级灾难从云端拉回。

对于资源有限的场景,比如个人VPS跑一个小网站,可以简化成:每天tar打包网站目录和数据库dump,rclone同步到云存储,保留最近7天的归档。脚本大概长这样:

#!/bin/bash
mysqldump -u root -p'password' --all-databases > /tmp/db_dump.sql
tar -czf /backup/site_$(date +%Y%m%d).tar.gz /var/www /tmp/db_dump.sql
rclone copy /backup/site_$(date +%Y%m%d).tar.gz remote:backups/
find /backup -mtime +7 -delete

这套组合拳虽然简陋,但成本几乎为零,恢复时只需要装好Nginx、MySQL,解压tar包导入数据库就能重新上线。

最后强调一个容易被跳过的环节:备份监控。无论你的脚本写得多完美,磁盘满了、网络断了、云凭证过期了都会导致备份静默失败。建议在crontab里加上健康检查,比如备份完成后向健康监测服务发一个HTTP请求,如果某天没收到请求就触发告警。也可以简单地在脚本末尾touch一个标记文件,然后用另一个监控脚本检查这个文件的时间戳是否在24小时内。

备份的本质不是技术问题,而是风险管理的决策。快照给你速度,tar给你通用性,云给你地理冗余,三者叠加才能覆盖从误操作到自然灾害的全频谱风险。现在就去检查一下你的服务器,最近一次成功备份是什么时候?