备份没那么简单

查看原文 HN 讨论

文章摘要

Aleksandar Filipovski 这篇文章用一条递进的思路,演示了「自己写个备份脚本」这件看似一下午能搞定的事,是如何一层层滚成庞然大物的。文章开头引用了那句在系统管理员圈里有无数变体的老话:世界上只有两种人,已经遭遇过灾难性数据丢失的,和即将遭遇的。

作者先讲了自家的故事:小时候全家把所有照片从笔记本和台式机上挪到一块移动硬盘以腾出空间,一切完美,直到有一天他父亲想拿这块盘给老式机顶盒当存储,机顶盒提示格式化,他就点了确认。文件索引被清空,硬盘名义上空了。作者说很容易把责任归到父亲身上,但真正入行之后才明白,导致这类事故的是一连串错误:首先是把所有照片只放在一个地方、完全没有备份;其次是消费级软件通常会用醒目的提示告诉你格式化意味着数据丢失(那台机顶盒没有,这是糟糕的 UI);更何况,凭什么指望一个非技术人员懂这些?所幸照片最终被恢复了,成了一堂便宜的课。

接下来是逐层加码的推演。第一条原则是有备份,也就是在别处留一份副本。但这不覆盖「插着的盘」本身的风险:勒索软件会加密你的文件,你自己也可能误删、甚至跑了个把一切清零的脚本。所以备份不能是第一块盘的镜像,你需要能回到过去,这意味着 RAID 1 这类镜像方案直接出局,必须有快照。快照多久一次?这就是 IT 里的恢复点目标(RPO),真实场景从金融机构的 30 秒以内到小企业的 24 小时甚至更长。快照带来存储负担,于是需要轮转。而简单的「保留 14 天、新进老出」很快就显出问题:离今天越近的时间点越需要密集,越久远的越不需要——一年里第二天和第三天之间发生了什么,到了第 364 天几乎毫无意义。于是演化出「日备保留 14 天、周备保留 7 周、月备保留 12 个月」,也就是所谓的 GFS 轮转(祖父-父亲-儿子)。

再往下,作者用 MPEG 视频压缩做类比:一段主角在静止背景前说话的平静镜头之所以能被高效压缩,是因为帧与帧之间大部分相同,变化部分可以用向量表示。快照遵循同样的模式,而且文件变更服从肥尾分布——绝大多数文件在一段时间内根本不变,极少数文件却一直在变。结论是不该存重复副本,而应去重:用硬链接引用已存在的文件,磁盘上只有一份,每个快照各自引用;这还能在轮转中存活,因为你从不删文件,只删目录项。rsnapshot 走的就是这条路,属于增量备份(只存相邻快照之间的变化),与之相对的差异备份在恢复时更健壮但更占空间。去重带来的不只是存储节省,还有带宽节省——既然第二台机器可能在云上,这直接关系到你的钱包。到这一步,方案已经是「增量的、去重的、GFS 轮转的、基于快照的备份」,用 rsync 拉文件、用 cron 跑脚本,加新机器很容易,文件权限和属主等元数据也能保留。

然后现实开始咬人。用这套方案去备份跑着十个 Docker 容器的家庭实验室,日志显示备份在失败——原因是很多容器喜欢创建 root 属主的文件,而 cron 任务却跑在默认用户下。更糟的是几乎每个 Web 应用都有数据库,而数据库为了性能常把数据先放内存再批量刷盘,这意味着运气不好时从备份恢复会因数据损坏而失败,所以备份还得顺带 dump 数据库,并对 Docker 卷拥有完整文件系统权限。接着你读到某型号硬盘的高故障率事件,开始考虑把备份放在两种不同介质上,以免硬件特定的故障一次性抹掉全部备份;再考虑物理安全,还得有一份异地副本放在云上或亲戚家,这样电涌、水灾、火灾就很难同时毁掉一切——这就是 3-2-1 的由来:3 份副本、2 种介质、1 份异地。

选定 S3 这类对象存储做异地备份后,你会马上发现现有方案失效:一是文件上传到 S3 后丢失元数据,二是上传大量小文件的费用高得离谱(文件大小同样服从肥尾分布)。于是最好把很多文件打成 tar 包,既保住元数据又压住成本。但怎么打?全部塞进一个巨大的 tar 包显然不行,那样硬链接增量备份就失去意义了;最好切成整齐的 50MB 分块——祝你好运,用一种可验证安全的方式做到这件事。

写到这里作者宣布投降:这已经不值得再花心智负担了。正确做法是用 Borg 或 Restic 这类久经考验的工具,它们处理了上述全部问题外加加密、块级去重、校验和;同时应当心怀感激地看待开源社区在构建、维护、实战检验这些工具过程中付出的无数试错,正是这些试错把这一切复杂度替我们抽象掉了。当然,如果你从不真正测试恢复,这一切等于零——于是待办清单上又多了一条数字卫生条款。只要你每六个月跑一次恢复演练,你就可以享用你的「加密的、块级去重的、GFS 轮转的、时间点归档的、云上的 3-2-1 备份方案」了。文末还有一句冷知识提醒:别把备份安排在凌晨 2 点到 3 点之间,不然夏令时切换时那一小时可能被跳过或者跑两遍。

文章发布后作者根据讨论补充了几条:他本该提到 ZFS 这个围绕数据完整性和快照构建的文件系统;并直接引用了 HN 用户 crabbone 的三点补充——一致性组(如果数据库和使用数据库的应用同时访问存储,快照可能捕捉到数据库状态领先或落后于应用状态的不一致画面,你需要冻结快照之外的全部 I/O)、ACL(比如用户来自 LDAP 服务器怎么办,符号链接指向快照之外同理)、稀疏文件支持(快照里若有虚拟机镜像而工具不支持稀疏文件,镜像体积会被极大膨胀)。crabbone 的结论是:要么用产品自带的快照功能(ZFS 就有),要么换一个有这功能的产品。

HN 评论精华

352 分、222 条评论,是本期讨论最热烈的一篇,也是最实用的一篇。

共识第一条:值钱的是恢复,不是备份。 readthenotes1 引用老师的话:与常见做法相反,没人真正重视备份,值得花钱的是恢复。AdieuToLogic 讲了同一个意思的另一个版本——他一位在 Veritas 做企业数据保留方案的朋友,在他说「你们是做备份的」时纠正道:我们不做备份生意,我们做的是恢复生意。darvo31 浓缩成一句:「备份是动词,恢复是名词。」TheCondor 描述了那种特殊的感受:当你打开自己手搓的备份「方案」准备做点简单恢复、却开始发现问题时,那是一种混杂着恶心、反胃、自责和失落的情绪;他反过来说从 Time Machine 恢复笔记本时几乎原样回来的体验「简直是魔法」。gerdesj 则分享了一个真实的成功案例:一位合作十五年的客户刚做完异地备份两周,一台大型印刷机着火,热损伤加烟雾毁掉大量设备,而那时正是英国首次新冠封城的前一周;他克隆了客户的备份仓库、起了 NFS 跑起虚拟机,又花一小时搭好 OpenVPN,客户靠着他数据中心里的机器度过了疫情的大半时间。他还提到自己公司按容量向客户收取备份存储费,其中包含每年一次的恢复演示——把客户的部分或全部系统在隔离环境里跑起来证明它们基本可用。

工具推荐高度集中在 Restic、Borg、Kopia 和 ZFS 上。 PunchyHamster 详细推荐 Restic:后端选择多、能直接接受管道输入(所以可以直接管 mysqldump 或 pg_dumpall 而不落中间文件)、仓库完整性检查选项很好、去重出色,他们在几百台机器上使用并加了一个「掷骰子挑一个备份试恢复」的测试脚本。VGHN7XDuOXPAzol 给出了 Kopia 与 Restic 的对比:Kopia 不方便管道输入,配置围绕备份服务器设计,对 Ansible/NixOS 这类声明式工具不友好,而且向 Kopia 服务器备份时无法设限带宽,会拖垮笔记本的 Wi-Fi。overtone1000 的组合是 ZFS 快照加 Restic 备份到 Backblaze,他的秘诀是用一个 healthchecks.io 实例,在 ZFS scrub 报错、本地快照失败或 Restic 检查/备份失败时把手机轰炸一遍。Helmut10001 推荐 ZFS 快照配合 Jim Salter 的 sanoid/syncoid 做拉模式异地同步,认为只要把临时数据和持久数据分好、数据集组织得当,备份需求就已经满足了 90%。也有反向经验:innocent_name 讲了一次 Borg 在向 Hetzner 存储盒传 20TB 时多次失败、按文档续传后得到 2GB 静默损坏数据、且因管道断开无法做完整性校验也无法从断点续作业的惨痛经历。Scottn1 提醒 Restic 常搭配的 Backrest 会把仓库密码以明文文件存在本地硬盘上。

「过于复杂了」的反对声也很响。 cranberryjoe 直接说备份就是简单的,列了五条:数据与应用分离、用 ZFS 或 btrfs 这样的真文件系统、cron 做快照并按策略复制到本地和异地、监控卷和快照体积并按策略删除、定期 scrub,然后甩下一句「就这么回事,不需要你们搞的那些花活」。justsomehnguy 则质问读者到底是谁——如果只是一个家庭里的本机管理员,你根本不需要企业级的那一套,你需要的是用 Syncthing 同步一份到家以外的某台设备,外加一套维护历史、防手滑的备份流程;他还刻薄地补了一句,没人需要你那 555GB 的夕阳和花朵 RAW 文件,连你自己也不需要。bnegreve 的方案朴素到极致:cron 脚本每天 rsync 整个 home 目录到远程服务器,因为 rsync 不删远端文件,他每月一号从零重建一次备份并留存上一份;十五年里笔记本丢过三次,每次都能在第二天恢复完毕,用老牌标准开源工具的好处是多年来不用因系统升级修任何东西。dsego 的立场是「有总比没有强」——他刚把液体洒在 MacBook 上,机器还在店里,幸好一直用 CCC 定期克隆到一块外置 SSD;别等完美方案,先把数据放到不止一个地方就已经是好的开始。

flippingheck 提出了唯一一个质疑前提的意见: 「两种人」那句话是个经验性论断,但它成立吗?99% 的人不做备份,而这多半是对的选择——风险低,他们也无法靠自己有意义地提高恢复率,而且他们并不足够在意自己的数据以至于把丢失定义为灾难。我们难道在备份、运动、睡眠、营养、记账、房屋维护上都遵循最佳实践吗?他自己没有,而备份在这张清单上排不到前面。

几条实用的细节值得单拎出来。 LilBytes 认为最省事的恢复测试就是每周用生产备份去刷新一个较低级的环境——他们的端到端测试环境按生产的风险标准搭建,所以可以直接承载生产数据;端到端测试跑通就等于确认了备份可用,前提是备份必须不可变,跑完测试后不能被改动。关于防勒索,Gigachad 反复强调 append-only 必须由托管方强制执行而非由备份工具保证,备份脚本持有的 API key 应当只能新增数据不能删除;他认为「对象存储服务商倒闭」的概率远低于「攻击者拿到你备份脚本里的 key 去销毁备份」的概率,而后者才是现实威胁。cyberax 走了另一条路,买了磁带库——他自己那套 LTO-9 四十盘位的用于公司 AI 模型备份花了约 1.2 万美元,但他指出二手 LTO-5 驱动器现在约 300 美元,单盒磁带约 20 美元装 2TB,而 LTO-5 是第一个支持 LTFS 的现实起点。OroPla 提出了文章没解决的问题:位腐(bit rot)被提到了却没给方案,几 TB 规模可以对一切做校验和并定期验证,但这个办法扩展性不好。jllyhill 的问题也没人给出好答案:到哪儿能找到关于「如何真正测试恢复流程」的讨论——我怎么验证我那 1 万张照片真的一张不少地恢复了?

b3lvedere 的反馈可能最能代表普通读者:「今天学到了,从没想过夏令时会造成这种问题。」