“世界上有两种人:经历过灾难性数据丢失的人,和即将经历的人。”软件工程师亚历山大·菲利波夫斯基引用了系统管理员圈子里流传的这句话。它说的其实是一件很朴素的事:数据丢失比大多数人想象中更容易发生,而多数人并没有为此做好准备。

菲利波夫斯基自己就差点丢掉家人的照片。他为了给家里电脑腾出空间,把照片集中到一块外置硬盘上,结果父亲为了把这块硬盘用作电视机顶盒的存储,把它格式化了一遍。文件索引被删除,硬盘看起来空空如也。

打开网易新闻 查看精彩图片

他没有把责任全推给父亲。照片集中在一处却没有备份,机顶盒也没有明确警告“格式化会丢失数据”,这些都是原因。他甚至质疑:凭什么期待一个不懂技术的人知道格式化的含义?照片后来幸运地恢复了,但这次经历留下的教训很直接——重要数据不要只放在一个地方。

打开网易新闻 查看精彩图片

硬盘会坏,SSD也会

硬盘可能故障、可能被盗,即使闲置不用,承载记录的磁性状态也会发生变化。SSD同样不保险,保持数据的电荷会流失,数据可能因此损坏。所以第一步很明确:在别的地方准备一份文件副本。

但有了副本不等于万事大吉。连接中的硬盘可能被勒索软件加密,用户可能误删文件,也可能运行了把所有内容覆写为零的脚本。如果机制是把原盘的改动原样同步过去,那么误操作的结果也会被一并复制到副本里。

关键就不只是“有没有复制”,而是“能不能回到过去的状态”。菲利波夫斯基指出,像RAID 1那样把同一份数据写到多块硬盘上的镜像方式,满足不了这个目的,需要的是保存某一时刻状态的“快照”。

多久存一次,存多少

做快照,第一个问题是频率。能恢复到哪个时间点,这个目标叫RPO(目标恢复点)。菲利波夫斯基举例说,重要的金融机构要求不到30秒,小企业可能是24小时以上,需求水平差别很大。比如给多年积攒的家庭照片做备份,也可以判断“最多丢失6天23小时的数据是可以接受的”。

频率定了,容量问题就来了。每天做一次快照,不删旧的,一周就是7个,一年就是365个。照这样下去,光备份数据就要占用惊人的存储空间,必须有一套逐步删除旧快照的运营方式。

比如“只保留最近14天,每建一个新的就删掉最旧的”。但这种方法有个漏洞:如果数据损坏超过两周才被发现,损坏前的备份可能已经不存在了。反过来,把一整年的备份全留着,容量上又很难承受,而且久远时期的记录未必需要那么细。

于是有了折中方案:近期的备份留得细,越久远的间隔越大。比如保留14天的每日备份、7周的每周备份、12个月的每月备份。这种把快照分成日、周、月三代保存的方式,叫GFS(Grandfather-Father-Son)。

省容量,也省流量

保存内容本身也能去重。被备份的文件大多没有改动,只有一小部分频繁更新。只保存改动过的文件,同时引用已经存过的数据,就能省下容量。

打开网易新闻 查看精彩图片

其中一种做法是硬链接——同一个文件实体被多个位置引用。每个快照都指向同一个实体,所以删掉旧快照时,只要还有别的快照引用,数据就仍然保留。去重不只省存储,还能减少往另一台机器传输数据时的通信量。尤其当保存目标是云服务时,传输流量直接关系到运营成本。

菲利波夫斯基说,到这一步的机制可以用文件传输工具rsync加上定时执行任务的cron搭起来。这套备份方式具备增量保存——未改动的文件用硬链接共享——和GFS世代管理,还能增加保存目标机器,也能保留文件权限、所有者这类附带信息。

但把这套机制用到家里的服务器环境,又会冒出别的问题。比如跑10个Docker容器时,容器创建的文件所有者是root,而备份任务以普通用户权限执行,就可能读不到文件,备份失败。

数据库也不能简单复制文件。数据库为了提速,会先把数据暂存在内存里,再批量写入磁盘。复制的时机不对,保存下来的可能是不一致的状态,恢复时就会失败。这就需要为备份导出数据库内容的“转储”,同时还要拿到读取Docker数据存储区域的权限。

3-2-1,然后呢

保存的设备和地点也要留意。考虑到某些硬盘型号故障频发,把数据存到不同类型的记录介质上是一种对策。再把副本放到云端或家人家里这类较远的位置,就能降低因电源异常、洪水、火灾而全部丢失的风险。这就是“准备3份数据副本,存在2种介质上,其中1份放在别处”的3-2-1备份原则。

不过,如果选Amazon S3这类对象存储作为异地保存目标,前面这套机制就不能照搬了。直接上传文件,权限和所有者等信息不会跟着走;大量上传小文件,请求费用也会堆高。

把多个文件打包成tar归档,可以既保留附带信息又减少上传次数。但如果全部塞进一个巨大的归档,利用硬链接只存改动部分的优势就没了。菲利波夫斯基也提出了切成50MB左右小块的想法,但要以能确认安全性的形式实现,并不简单。

他说,到了这个阶段,继续自己造已经不合算。替代方案是Borg backup、Restic这类备份工具,它们支持加密、按分块去重,以及用于检测数据损坏的校验和。菲利波夫斯基说,把这些复杂处理做到用户容易上手,开源开发者们经历了大量试错。

还有一点:做了备份,不实际试一次恢复就没有意义。所以除了把备份机制搭好,还需要定期验证恢复,比如每半年执行一次。

备份要为误删或损坏保留过去的状态,要在控制容量和成本的同时保证数据一致性和存放地点的安全,再加上验证能否真正恢复,这一连串要求下来,远不是简单复制能解决的。菲利波夫斯基的结论是:备份之所以难,是因为它不只是造一份文件副本,而是要让数据在需要的时候,处于能被正确恢复的状态。