3.7、文件同步方式Hash tree

2018年11月27日 08:55 | 61次浏览 作者原创 版权保护

rsync 在同步文件时需要分析目录中每一个文件的更新标记,当有多级目录时,依然如此。如果能让它在减少扫描范围或者次数的同时,仍然可以实现目的,那当然是我们所希望的。<!--www.vxzsk.com -->

也许你已经发现,事实上在大多数时候,很多文件并没有更新,为什么不把少量文件的更新标记不断地传递到上一级目录呢?这样便可以让扫描过程少走很多冤枉路。

如图 3-3 所示,在文件服务器上,假如底层的灰色文件发生了更新,我们需要让它的上级目录也随之更新,最后修改时间,并且向上以此类推,直到顶层目录,这样一来,从这个文件到根目录的一系列节点都会更新最后修改时间,当同步扫描的时候,只需要遍历那些修改时间更新的目录即可,扫描次数将大大减少。

图 3-3 将文件的修改时间传递到上级目录

但是,操作系统本身对于文件的修改并不会自动更新上级目录的修改时间,一些特定的应用程序会这样做,比如通过 VI 编辑某个文件并保存后,你会发现它的所有上级目录都会自动更新修改时间。那么,对于文件同步,我们也必须想办法自己来实现。

幸运的是,Linux 内核中的 inotify 模块可以帮助我们完成这一工作,简单地说,它通过在内核中监视文件系统的一举一动,可以在任何文件的修改时间发生变化后,发出事件通知。这样一来,我们可以通过 inotify 提供的 API 来编写守护进程,持续不断地监视文件修改事件,一旦发现某个文件被修改,便随之更新上级甚至更上一级目录的修改时间,直到被同步目录的根节点。

inotify 本身提供了基于 C 语言的 API,除此之外,你也可以在 PHP 中使用相应的 PECL 扩展,这将大大简化我们的开发工作。有一点需要注意,inotify 已经直接包含在了 Linux2.6.13 的内核中,在此之前,我们必须安装相应的补丁,所以在编译 PHP扩展的时候,你需要检查 Linux 的内核版本。

s-colin:~ # uname -a
Linux s-mat 2.6.16.21-0.8-bigsmp #1 SMP Mon Jul 3 18:25:39 UTC 2006 i686 i686 i386 GNU/Linux

 V型知识库 www.vxzsk.com

这种将文件的修改时间不断向上传递的机制体现了 Hash tree 的动机,但有所不同的是,在 Hash tree 的存储结构中,我们通过特定的 Hash 算法,为树中的每个非叶节点生成一个可以描述它所有子节点唯一性的特征字符串,以便提供对节点信息完整性和正确性的验证,这样一来,一旦某个节点的信息发生变化,那么这种变化便会向上传递,体现在上级节点的特征字符串中。

而这里,我们直接将文件修改时间作为 Hash 值,这非常适合于文件同步这种依赖时间的特殊应用,而且易于实现,几乎不需要额外的计算开销,的确,文件系统本身就是树形结构,Hash tree 的优越性在这里得到了很好的发挥。


到目前为止,我们所做的还只是通过 inotify 实现了文件修改时间的向上传递,除此之外,我们还必须实现基于这种机制的专用服务器端和客户端程序,因为 rsync 并不支持我们所期望的 Hash tree 式扫描,当然,也许你可以尝试修改 rsync 的源代码。另一方面,利用现有的通道也是一个值得考虑的选择,比如你仍然可以借助 SFTP 来获取远程目录列表,并且分析修改时间,然后通过 SCP 来获取需要同步的文件。

利用这种同步方式,我们还需要注意一点,为了最大程度地发挥 Hash tree 的优势,我们需要在目录规划时遵循一些原则,尽量让目录中的文件或者子目录保持在较少的数量,以减少扫描次数,当然,这也必然让扁平的目录结构变得更加冗长,带来更多的目录切换次数,但是,你可以根据实际情况来很好地把握平衡。

此文章本站原创,地址 https://www.vxzsk.com/1926.html   转载请注明出处!谢谢!

感觉本站内容不错,读后有收获?小额赞助,鼓励网站分享出更好的教程