我们有一个应用程序会定期将自身备份到本地文件系统上的目录。该目录中还有几个文件和目录。
我想生成所有这些文件的“快照”,可以将其复制到备份存储中。
最重要的是,我如何以原子方式生成这个“快照”?请记住,任何这些文件都可能被备份守护进程修改,从而导致我们的“快照”不一致。
编辑:
也许我应该提到系统有一个ext4
文件系统。
答案1
如果您知道哪些进程正在写入该目录中的文件,则可以使用 冻结它们kill -SIGSTOP <pid>
,进行备份,然后使用 恢复进程kill -SIGCONT <pid>
。
答案2
据我所知,如果没有并发访问数据的应用程序的配合,ext4 本身无法保证此类事务的原子性。在底层设备映射器中使用某些快照机制也不起作用,因为您基本上需要卸载文件系统(或至少重新挂载-ro)才能在块设备级别获得一致的状态。
我认为如果没有关于应用程序行为的额外知识,这将会非常复杂。因此,最简单的方法可能是以某种方式修改应用程序(例如引入锁定文件)。但是,如果您需要将其视为黑匣子,我将对此做出一些假设:
- 与执行间隔相比,应用程序的定期备份只花费很短的时间
- 完成备份后,它将关闭所有文件句柄,直到下一次备份运行
基于这些假设,我建议采取乐观的方法。简而言之,只需尝试制作目录的常规、递归、非原子副本,然后检查应用程序是否已触及任何文件。如果是这样,则表明您的副本不幸与应用程序的定期自我备份同时发生。在这种情况下,请丢弃您刚刚创建的副本并重试。也许会退缩一段时间;避免占用资源的无限循环。
您可以通过使用 Linux 中的 inotify 机制来实现这一点,作为在此过程中监视要复制的文件的一种手段。如果您想要一个简单的 shell 脚本,请看一下inotify 工具。大多数发行版上都包含它。我不完全确定当文件已经打开时 inotify 的行为如何,因此参考假设 2,您可能还想使用它lsof
来确保您的应用程序在源目录的任何内容上都没有打开的文件句柄。去做后您设置了 inotify 手表。
所以这就是我要解决你的情况的方法。我希望您不介意我是否跳过勾画其实际实现。如果有任何不清楚的地方,请随时问我。
答案3
/sbin/fsfreeze --freeze /data
# do a backup
/sbin/fsfreeze --unfreeze /data
fsfreeze - 暂停对文件系统的访问(Ext3/4、ReiserFS、JFS、XFS)
如果需要更多信息:https://manpages.ubuntu.com/manpages/focal/man8/fsfreeze.8.html