树莓派自建 NAS 云盘之——数据自动备份

LIEVEZ 2018-10-15

把你的树莓派变成数据的安全之所。

在《树莓派自建 NAS 云盘》系列的 第一篇 文章中,我们讨论了建立 NAS 的一些基本步骤,添加了两块 1TB 的存储硬盘驱动(一个用于数据存储,一个用于数据备份),并且通过网络文件系统(NFS)将数据存储盘挂载到远程终端上。本文是此系列的第二篇文章,我们将探讨数据自动备份。数据自动备份保证了数据的安全,为硬件损坏后的数据恢复提供便利以及减少了文件误操作带来的不必要的麻烦。

树莓派自建 NAS 云盘之——数据自动备份

备份策略

我们就从为小型 NAS 构想一个备份策略着手开始吧。我建议每天有时间节点、有计划的去备份数据,以防止干扰到我们正常的访问 NAS,比如备份时间点避开正在访问 NAS 并写入文件的时间点。举个例子,你可以每天凌晨 2 点去进行数据备份。

另外,你还得决定每天的备份需要被保留的时间长短,因为如果没有时间限制,存储空间很快就会被用完。一般每天的备份保留一周便可以,如果数据出了问题,你便可以很方便的从备份中恢复出来原数据。但是如果需要恢复数据到更久之前怎么办?可以将每周一的备份文件保留一个月、每个月的备份保留更长时间。让我们把每月的备份保留一年时间,每一年的备份保留更长时间、例如五年。

这样,五年内在备份盘上产生大量备份:

  • 每周 7 个日备份
  • 每月 4 个周备份
  • 每年 12 个月备份
  • 每五年 5 个年备份

你应该还记得,我们搭建的备份盘和数据盘大小相同(每个 1 TB)。如何将不止 10 个 1TB 数据的备份从数据盘存放到只有 1TB 大小的备份盘呢?如果你创建的是完整备份,这显然不可能。因此,你需要创建增量备份,它是每一份备份都基于上一份备份数据而创建的。增量备份方式不会每隔一天就成倍的去占用存储空间,它每天只会增加一点占用空间。

以下是我的情况:我的 NAS 自 2016 年 8 月开始运行,备份盘上有 20 个备份。目前,我在数据盘上存储了 406GB 的文件。我的备份盘用了 726GB。当然,备份盘空间使用率在很大程度上取决于数据的更改频率,但正如你所看到的,增量备份不会占用 20 个完整备份所需的空间。然而,随着时间的推移,1TB 空间也可能不足以进行备份。一旦数据增长接近 1TB 限制(或任何备份盘容量),应该选择更大的备份盘空间并将数据移动转移过去。

利用 rsync 进行数据备份

利用 rsync 命令行工具可以生成完整备份。

  1. <span class="pln">pi@raspberrypi</span><span class="pun">:~</span><span class="pln"> $ rsync </span><span class="pun">-</span><span class="pln">a </span><span class="pun">/</span><span class="pln">nas</span><span class="pun">/</span><span class="pln">data</span><span class="str">/ /</span><span class="pln">nas</span><span class="pun">/</span><span class="pln">backup</span><span class="pun">/</span><span class="lit">2018</span><span class="pun">-</span><span class="lit">08</span><span class="pun">-</span><span class="lit">01</span>

这段命令将挂载在 /nas/data/ 目录下的数据盘中的数据进行了完整的复制备份。备份文件保存在 /nas/backup/2018-08-01 目录下。-a 参数是以归档模式进行备份,这将会备份所有的元数据,例如文件的修改日期、权限、拥有者以及软连接文件。

现在,你已经在 8 月 1 日创建了完整的初始备份,你将在 8 月 2 日创建第一个增量备份。

  1. <span class="pln">pi@raspberrypi</span><span class="pun">:~</span><span class="pln"> $ rsync </span><span class="pun">-</span><span class="pln">a </span><span class="pun">--</span><span class="kwd">link</span><span class="pun">-</span><span class="pln">dest </span><span class="pun">/</span><span class="pln">nas</span><span class="pun">/</span><span class="pln">backup</span><span class="pun">/</span><span class="lit">2018</span><span class="pun">-</span><span class="lit">08</span><span class="pun">-</span><span class="lit">01</span><span class="str">/ /</span><span class="pln">nas</span><span class="pun">/</span><span class="pln">data</span><span class="str">/ /</span><span class="pln">nas</span><span class="pun">/</span><span class="pln">backup</span><span class="pun">/</span><span class="lit">2018</span><span class="pun">-</span><span class="lit">08</span><span class="pun">-</span><span class="lit">02</span>

上面这行代码又创建了一个关于 /nas/data 目录中数据的备份。备份路径是 /nas/backup/2018-08-02。这里的参数 --link-dest 指定了一个备份文件所在的路径。这样,这次备份会与 /nas/backup/2018-08-01 的备份进行比对,只备份已经修改过的文件,未做修改的文件将不会被复制,而是创建一个到上一个备份文件中它们的硬链接。

使用备份文件中的硬链接文件时,你一般不会注意到硬链接和初始拷贝之间的差别。它们表现的完全一样,如果删除其中一个硬链接或者文件,其他的依旧存在。你可以把它们看做是同一个文件的两个不同入口。下面就是一个例子:

树莓派自建 NAS 云盘之——数据自动备份

左侧框是在进行了第二次备份后的原数据状态。中间的方块是昨天的备份。昨天的备份中只有图片 file1.jpg 并没有 file2.txt 。右侧的框反映了今天的增量备份。增量备份命令创建昨天不存在的 file2.txt。由于 file1.jpg 自昨天以来没有被修改,所以今天创建了一个硬链接,它不会额外占用磁盘上的空间。

自动化备份

你肯定也不想每天凌晨去输入命令进行数据备份吧。你可以创建一个任务定时去调用下面的脚本让它自动化备份。

  1. <span class="com">#</span><span class="pun">!</span><span class="str">/bin/</span><span class="kwd">bash</span>
  2. <span class="pln">TODAY</span><span class="pun">=</span><span class="pln">$</span><span class="pun">(</span><span class="kwd">date</span><span class="pun">+%</span><span class="pln">Y</span><span class="pun">-%</span><span class="pln">m</span><span class="pun">-%</span><span class="pln">d</span><span class="pun">)</span>
  3. <span class="pln">DATADIR</span><span class="pun">=</span><span class="str">/nas/</span><span class="pln">data</span><span class="pun">/</span>
  4. <span class="pln">BACKUPDIR</span><span class="pun">=</span><span class="str">/nas/</span><span class="pln">backup</span><span class="pun">/</span>
  5. <span class="pln">SCRIPTDIR</span><span class="pun">=</span><span class="str">/nas/</span><span class="pln">data</span><span class="pun">/</span><span class="pln">backup_scripts</span>
  6. <span class="pln">LASTDAYPATH</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">(</span><span class="kwd">ls</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span><span class="pun">|</span><span class="kwd">tail</span><span class="pun">-</span><span class="pln">n </span><span class="lit">1</span><span class="pun">)</span>
  7. <span class="pln">TODAYPATH</span><span class="pun">=</span><span class="pln">$</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}/</span><span class="pln">$</span><span class="pun">{</span><span class="pln">TODAY</span><span class="pun">}</span>
  8. <span class="kwd">if</span><span class="pun">[[</span><span class="pun">!</span><span class="pun">-</span><span class="pln">e $</span><span class="pun">{</span><span class="pln">TODAYPATH</span><span class="pun">}</span><span class="pun">]];</span><span class="kwd">then</span>
  9. <span class="kwd">mkdir</span><span class="pun">-</span><span class="pln">p $</span><span class="pun">{</span><span class="pln">TODAYPATH</span><span class="pun">}</span>
  10. <span class="kwd">fi</span>
  11. <span class="pln">rsync </span><span class="pun">-</span><span class="pln">a </span><span class="pun">--</span><span class="kwd">link</span><span class="pun">-</span><span class="pln">dest $</span><span class="pun">{</span><span class="pln">LASTDAYPATH</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">DATADIR</span><span class="pun">}</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">TODAYPATH</span><span class="pun">}</span><span class="pln"> $@</span>
  12. <span class="pln">$</span><span class="pun">{</span><span class="pln">SCRIPTDIR</span><span class="pun">}/</span><span class="pln">deleteOldBackups</span><span class="pun">.</span><span class="pln">sh</span>

第一段代码指定了数据路径、备份路径、脚本路径以及昨天和今天的备份路径。第二段代码调用 rsync 命令。最后一段代码执行 deleteOldBackups.sh 脚本,它会清除一些过期的没有必要的备份数据。如果不想频繁的调用 deleteOldBackups.sh,你也可以手动去执行它。

下面是今天讨论的备份策略的一个简单完整的示例脚本。

  1. <span class="com">#</span><span class="pun">!</span><span class="str">/bin/</span><span class="kwd">bash</span>
  2. <span class="pln">BACKUPDIR</span><span class="pun">=</span><span class="str">/nas/</span><span class="pln">backup</span><span class="pun">/</span>
  3. <span class="kwd">function</span><span class="pln"> listYearlyBackups</span><span class="pun">()</span><span class="pun">{</span>
  4. <span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="lit">0</span><span class="lit">1</span><span class="lit">2</span><span class="lit">3</span><span class="lit">4</span><span class="lit">5</span>
  5. <span class="kwd">do</span><span class="kwd">ls</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span><span class="pun">|</span><span class="pln"> egrep </span><span class="str">"$(date +%Y -d "</span><span class="pln">$</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> year ago</span><span class="str">")-[0-9]{2}-[0-9]{2}"</span><span class="pun">|</span><span class="kwd">sort</span><span class="pun">-</span><span class="pln">u </span><span class="pun">|</span><span class="kwd">head</span><span class="pun">-</span><span class="pln">n </span><span class="lit">1</span>
  6. <span class="kwd">done</span>
  7. <span class="pun">}</span>
  8. <span class="kwd">function</span><span class="pln"> listMonthlyBackups</span><span class="pun">()</span><span class="pun">{</span>
  9. <span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="lit">0</span><span class="lit">1</span><span class="lit">2</span><span class="lit">3</span><span class="lit">4</span><span class="lit">5</span><span class="lit">6</span><span class="lit">7</span><span class="lit">8</span><span class="lit">9</span><span class="lit">10</span><span class="lit">11</span><span class="lit">12</span>
  10. <span class="kwd">do</span><span class="kwd">ls</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span><span class="pun">|</span><span class="pln"> egrep </span><span class="str">"$(date +%Y-%m -d "</span><span class="pln">$</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> month ago</span><span class="str">")-[0-9]{2}"</span><span class="pun">|</span><span class="kwd">sort</span><span class="pun">-</span><span class="pln">u </span><span class="pun">|</span><span class="kwd">head</span><span class="pun">-</span><span class="pln">n </span><span class="lit">1</span>
  11. <span class="kwd">done</span>
  12. <span class="pun">}</span>
  13. <span class="kwd">function</span><span class="pln"> listWeeklyBackups</span><span class="pun">()</span><span class="pun">{</span>
  14. <span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="lit">0</span><span class="lit">1</span><span class="lit">2</span><span class="lit">3</span><span class="lit">4</span>
  15. <span class="kwd">do</span><span class="kwd">ls</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span><span class="pun">|</span><span class="kwd">grep</span><span class="str">"$(date +%Y-%m-%d -d "</span><span class="kwd">last</span><span class="pln"> monday </span><span class="pun">-</span><span class="pln">$</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> weeks</span><span class="str">")"</span>
  16. <span class="kwd">done</span>
  17. <span class="pun">}</span>
  18. <span class="kwd">function</span><span class="pln"> listDailyBackups</span><span class="pun">()</span><span class="pun">{</span>
  19. <span class="kwd">for</span><span class="pln"> i </span><span class="kwd">in</span><span class="lit">0</span><span class="lit">1</span><span class="lit">2</span><span class="lit">3</span><span class="lit">4</span><span class="lit">5</span><span class="lit">6</span>
  20. <span class="kwd">do</span><span class="kwd">ls</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span><span class="pun">|</span><span class="kwd">grep</span><span class="str">"$(date +%Y-%m-%d -d "</span><span class="pun">-</span><span class="pln">$</span><span class="pun">{</span><span class="pln">i</span><span class="pun">}</span><span class="pln"> day</span><span class="str">")"</span>
  21. <span class="kwd">done</span>
  22. <span class="pun">}</span>
  23. <span class="kwd">function</span><span class="pln"> getAllBackups</span><span class="pun">()</span><span class="pun">{</span>
  24. <span class="pln">listYearlyBackups</span>
  25. <span class="pln">listMonthlyBackups</span>
  26. <span class="pln">listWeeklyBackups</span>
  27. <span class="pln">listDailyBackups</span>
  28. <span class="pun">}</span>
  29. <span class="kwd">function</span><span class="pln"> listUniqueBackups</span><span class="pun">()</span><span class="pun">{</span>
  30. <span class="pln">getAllBackups </span><span class="pun">|</span><span class="kwd">sort</span><span class="pun">-</span><span class="pln">u</span>
  31. <span class="pun">}</span>
  32. <span class="kwd">function</span><span class="pln"> listBackupsToDelete</span><span class="pun">()</span><span class="pun">{</span>
  33. <span class="kwd">ls</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span><span class="pun">|</span><span class="kwd">grep</span><span class="pun">-</span><span class="pln">v </span><span class="pun">-</span><span class="pln">e </span><span class="str">"$(echo -n $(listUniqueBackups) |sed "</span><span class="pln">s</span><span class="str">/ /</span><span class="pln">\\\|</span><span class="pun">/</span><span class="pln">g</span><span class="str">")"</span>
  34. <span class="pun">}</span>
  35. <span class="kwd">cd</span><span class="pln"> $</span><span class="pun">{</span><span class="pln">BACKUPDIR</span><span class="pun">}</span>
  36. <span class="pln">listBackupsToDelete </span><span class="pun">|</span><span class="kwd">while</span><span class="pln"> read file_to_delete</span><span class="pun">;</span><span class="kwd">do</span>
  37. <span class="kwd">rm</span><span class="pun">-</span><span class="pln">rf $</span><span class="pun">{</span><span class="pln">file_to_delete</span><span class="pun">}</span>
  38. <span class="kwd">done</span>

这段脚本会首先根据你的备份策略列出所有需要保存的备份文件,然后它会删除那些再也不需要了的备份目录。

下面创建一个定时任务去执行上面这段代码。以 root 用户权限打开 crontab -e,输入以下这段命令,它将会创建一个每天凌晨 2 点去执行 /nas/data/backup_scripts/daily.sh 的定时任务。

  1. <span class="lit">0</span><span class="lit">2</span><span class="pun">*</span><span class="pun">*</span><span class="pun">*</span><span class="str">/nas/</span><span class="pln">data</span><span class="pun">/</span><span class="pln">backup_scripts</span><span class="pun">/</span><span class="pln">daily</span><span class="pun">.</span><span class="pln">sh</span>

有关创建定时任务请参考 cron 创建定时任务

  • 当没有备份任务时,卸载你的备份盘或者将它挂载为只读盘;
  • 利用远程服务器作为你的备份盘,这样就可以通过互联网同步数据

你也可用下面的方法来加强你的备份策略,以防止备份数据的误删除或者被破坏:

本文中备份策略示例是备份一些我觉得有价值的数据,你也可以根据个人需求去修改这些策略。

我将会在 《树莓派自建 NAS 云盘》 系列的第三篇文章中讨论 Nextcloud。Nextcloud 提供了更方便的方式去访问 NAS 云盘上的数据并且它还提供了离线操作,你还可以在客户端中同步你的数据。

相关推荐

yanghan / 0评论 2011-06-30