导读:本站cron篇写过备份的定时任务,Docker Registry篇叮嘱过"镜像数据要纳入备份计划",但备份本身从来没有被正面讲过——而它恰恰是所有运维动作里"平时最没用、出事最要命"的那一个。这篇把备份这件事一次讲透:先想清楚备什么(很多人备份了半年才发现备的全是能重装的东西)、3-2-1原则怎么在小预算下落地、rsync增量同步为什么省流量、数据库为什么不能直接抄文件、rclone怎么把备份推到对象存储、restic的加密去重快照适不适合你、以及最重要的一章——没做恢复演练的备份等于没有备份。
一、先想清楚备什么:数据分层,别备份垃圾
备份的第一课不是工具,是清单。把机器上的东西分三层:第一层,"死了也无法重建"的数据——数据库文件、用户上传的图片、证书的私钥、你手写的配置文件,这是备份的全部意义所在;第二层,"能重建但很费劲"的东西——装好的环境、拉好的镜像、编译过的依赖,它们可以用一份文档或一个Compose文件描述,本站Compose篇的"配置即文件"思想就是把这一层从备份变成代码;第三层,"随便丢"的——系统本身、软件包缓存、临时文件。新手的典型错误是把整台机器tar打包:费空间、费流量、恢复时还要在垃圾堆里翻东西。正确的做法是第一层全备、第二层用代码描述(docker-compose.yml、.env模板、一份README),恢复时新机器跑一遍Compose就回来了。
二、3-2-1原则:个人小预算的落地版
备份界的金科玉律叫3-2-1:至少三份副本、存放于两种不同介质、其中一份异地。对个人VPS玩家,落地版可以是:原始数据一份(机器上)、本机或同机房快照一份(够快但不够独立)、对象存储异地一份(独立但恢复慢)。云厂商的快照功能算一份,但注意它和机器在同一厂商的账号体系里——账号被封、厂商跑路、计费纠纷,快照和机器一起没。真正算数的那份异地,应该在另一家厂商的对象存储里,比如用另一家的S3兼容存储。多花的钱每月几块钱,买到的是"任何单一厂商出事都伤不到你"的独立性——这个思路和本站监控篇"数据要自己收"的立场一脉相承。
三、rsync:增量同步的瑞士军刀
rsync的杀手锏是增量:只传输两端有差异的部分。第一次全量,之后每次只传变化量,数据库几百兆、每天变化几兆的场景,流量节省是数量级的。本站VPS迁移篇已经讲过rsync搬家,备份场景的用法核心参数就一个:
rsync -a --delete /data/ backup-host:/backup/this-vps/
-a保留权限、属主、时间戳等元数据,--delete让目标端和源端严格一致(源删了的目标也删)。注意结尾斜杠的语义:/data/同步的是目录内容,/data同步的是目录本身,搞反了会多套一层目录。--delete要慎用:它是双向对齐的利器,也是误删同步的凶器——源端被勒索软件加密后跑一次rsync,备份端也被对齐成加密文件了。这就是为什么rsync只适合做"同步",真正的时间机器要靠快照,后面几节展开。
四、数据库不能直接抄文件:dump的正确姿势
MySQL、PostgreSQL的数据目录在运行时是"写了一半"的状态,直接cp或rsync这些文件,恢复时大概率报错。正确做法是用dump工具导出一致性快照:
mysqldump -u备份用户 -p --single-transaction --routines --triggers mysite | gzip > mysite_$(date +%F).sql.gz
--single-transaction保证InnoDB导出期间不锁表,--routines和--triggers把存储过程和触发器一并带走,gzip把几倍的体积压回去。PostgreSQL对应的是pg_dump。导出的sql.gz文件才是备份对象——纯文本格式、可diff、可部分恢复。备份频率上,dump出来的东西和binlog是两条腿:dump保底,binlog保增量进阶玩法,个人站长先做好每日dump这一条腿就够。
五、rclone:把备份推到对象存储
rclone是对象存储界的rsync,S3、B2、R2、各家OSS通吃。配置好remote后(rclone config交互式走一遍,记下access key和secret),推送就一行:
rclone copy /backup/ remote:yvps-backup/ --transfers 4 --min-age 1m
--min-age 1m跳过一分钟内还在写入的文件,避免把半成品推上去。rclone copy只新增不删除,适合备份场景;sync版本会把云端多余文件删掉,慎用,道理同rsync的--delete。对象存储按量计费,备份几百兆每月成本几毛到几块钱,是异地副本性价比最高的载体。有个细节值得注意:部分S3兼容服务有免费出口流量(比如专门做备份的B2),恢复时不用心疼流量费——选型时把"恢复成本"也考虑进去,别只看存储单价。
六、restic:加密、去重、真快照
rsync加rclone组合的短板是没有版本历史:昨天的备份被今天覆盖,误删的文件在下次同步后彻底消失。restic补上这块:每次备份是一个不可变的快照,自动全局去重(重复内容只存一份),客户端加密(密钥不在你手里云端就是一堆乱码),保留策略一条参数搞定:
restic forget --keep-daily 7 --keep-weekly 4 --keep-monthly 6
保每日7份、每周4份、每月6份,老的自动清理。restic直接支持S3后端,本地加密后推送,流量和存储双重省。代价是操作比rsync抽象一层,恢复要指定快照ID。选型建议:文件量不大、想要时间机器能力,restic一步到位;纯搬运大文件、不需要历史,rsync更直接。两者都能跑在cron里,配合本站cron篇的姿势自动化。
七、恢复演练:没恢复过的备份等于没有
这是全篇最重要的一节。备份系统最大的谎言是"配置了就等于生效了"——直到你真的恢复一次,才知道dump是不是带了权限表、Compose引用的卷路径在不在备份范围、加密的restic仓库密码你是不是真的还留着。演练方法简单粗暴:找一台干净机器(或本站虚拟化篇里说的便宜小鸡、甚至Docker容器),把备份恢复上去,把服务跑起来,点一遍核心功能。个人站长至少一季度一次,改过备份脚本后立即一次。把恢复步骤写成文档存在备份里(对,备份自己的说明书),出事当晚你不需要凭记忆操作。演练还会逼你回答一个平时回避的问题:恢复一台机器到底要多久?这个数字决定了你能接受多长的停机,也决定了RPO(能容忍丢多少数据)该设多紧。
八、把整套串起来:cron里的完整备份流水线
0 3 * * * mysqldump -ubackup -pPass --single-transaction mysite | gzip > /backup/db_$(date +%F).sql.gz 15 3 * * * rsync -a /data/ /backup/data/ 30 3 * * * restic backup /backup --repo s3:remote:yvps-backup 45 3 * * * find /backup -name '*.sql.gz' -mtime +7 -delete
四条任务分别是:dump数据库、同步数据文件、推加密快照、清理过期文件。注意时间错开——上一条没跑完下一条就启动,是备份流水线最经典的隐性故障(restic推到一半的仓库比没有仓库更危险)。每条任务配上输出重定向到日志,出问题时cron篇讲过的journalctl一查便知。备份成功与否的告警也值得加一条:结尾追加 || echo 'backup failed' | mail -s 'backup alert' you@example.com,失败时收到邮件,比每天成功时收邮件有价值得多。
结语
备份的全部智慧可以压缩成三句:备那些重建不了的东西,用代码描述能重建的;副本要跨厂商跨地域,单一厂商不算异地;恢复演练是备份的一部分,没演练过的备份只是心理安慰。工具链按需组合:rsync管同步,mysqldump管数据库一致性,rclone管上云,restic管版本历史——每一层都可以单独开始,串起来就是个人站长的完整灾备体系。希望你永远用不上这套东西,但它必须在那天到来之前就跑很久了。


