63

我最近使用 inotify 创建了一个保管箱系统,监视在特定目录中创建的文件。我正在观看的目录是从 NFS 服务器安装的,并且 inotify 的行为与我预期的不同。考虑以下场景,其中 inotify 脚本在机器 A 上运行,监视 /some/nfs/dir/also/visible/to/B。

- 使用机器 A 在 /some/nfs/dir/also/visible/to/B 中创建文件,脚本按预期运行。使用机器 B 执行相同的操作,脚本不会收到有关目录中删除的新文件的通知。
- 当脚本在 NFS 服务器上运行时,它会在从机器 A 和机器 B 创建文件时收到通知。

这是我用来访问 inotofy 的包中的错误中的错误,还是这是预期的行为?

4

6 回答 6

79

inotify 需要内核的支持才能工作。当应用程序跟踪目录时,它会要求内核在发生这些更改时通知它。当更改发生时,除了将这些更改写入磁盘之外,内核还会通知监视进程。

在远程 NFS 机器上,内核看不到更改;它完全发生在远程。NFS 早于 inotify 并且在 NFS 中没有网络级别的支持,或者任何等效的东西。

如果你想解决这个问题,你可以在存储服务器上运行一个服务(因为内核总是会看到对文件系统的更改),它代理对远程机器的请求,并将数据转发到远程客户端。

编辑:我觉得奇怪的是NFS应该因为它缺乏对 inotify 的支持而受到指责。

网络文件系统 (NFS) 是一种分布式文件系统协议,最初由Sun Microsystems 于 1984 年开发,维基百科文章

然而:

Inotify(inode notify)是一个Linux 内核子系统,用于扩展文件系统以通知文件系统的更改。[...] 从 2.6.13 版(2005 年 6 月 18日)开始,它已包含在主线 Linux 内核中[...]。维基百科文章

很难期望一个可移植的网络协议/应用程序支持为不同的操作系统开发的特定内核特性,并且这种特性在20 多年后才出现。即使它确实包含了它的扩展,它们在其他操作系统上也不可用或无用。

*在所有情况下都强调我的


另一个问题;假设我们根本不使用网络,而是使用具有良好 inotify 支持的本地文件系统:ext3(假设它安装在/mnt/foo)。但是文件系统不是真正的磁盘,而是从环回设备安装的;并且底层文件又可以在 vfs 中的不同位置访问(例如,/var/images/foo.img)。

现在,您不应该修改已挂载的 ext3 文件系统,但如果更改的是文件内容而不是元数据,那么这样做仍然是相当安全的。

因此,假设一个聪明的用户/var/images/foo.img在十六进制编辑器中 修改了文件系统映像(

没有合理的方式可以安排 inotify 始终通知观看过程这种变化。尽管可能需要进行一些调整才能使 ext3 注意到并尊重更改,但这些都不适用于 xfs drtiver,否则它非常相似。

也不应该。你在作弊!。inotify 只能通知您在被监视的实际挂载点通过 vfs 发生的更改。如果更改发生在该 VFS 之外,由于基础数据发生更改,inotify 无法帮助您,也并非旨在解决该问题。

您是否考虑过使用消息队列进行网络通知?

于 2010-11-20T04:48:03.600 回答
6

我发现了一个 SGI FAM使用主管守护程序来监视文件修改。它支持 NFS,你可以在wiki上看到一些描述

于 2013-04-12T06:59:54.143 回答
6

对于在寻找为什么在 Docker 上绑定挂载不会检测到主机目录中的文件更改(对于应用程序的热重载)的答案时遇到此问题的任何人,这是因为主机和容器之间的文件更改传播不是与容器内核通信。

只有来自容器本身的更改才会传达给内核。解决方案是让您的实时重新加载实用程序打开“轮询模式”而不是使用 fsnotify。

于 2018-09-21T08:33:59.183 回答
0

我同意 SingleNegationElimination 的解释,并想补充一点,iSCSI 目标会起作用,因为它们会提醒内核。

因此,“真实”文件系统(即相对于系统)上的事情将触发 Inotify 发出警报。像 Rsync'ing 一样,将某些东西网络化到已安装的分区中。

如果您必须通过 inotify 获取通知(或必须使用 inotify),您可以创建一个 cron 以 rsync -avz 到文件系统。当然,缺点是您使用的是真实的系统硬盘空间。

于 2016-05-30T23:48:45.183 回答
0

我第二个@SingleNegationElimination。

此外,您可以尝试notify-forwarder

  • 机器 A 监视本地 inotify 事件,然后将它们转发到机器 B(通过 UDP)。
  • 机器 B 不会(不能?)重播事件,但会为更改的文件触发 ATTRIB 事件。

如果您使用 vagrant,请使用vagrant-notify-forwarder

于 2019-01-17T00:46:45.740 回答
0

问题notify-forwarder在于它不会触发inotify事件。它用于utime更新远程系统上文件的时间戳,但inotify看不到这一点。

AFAIK,使用 NFS 挂载时时间戳已经更新。我已经在 Synology NAS NFS 服务器和 Raspbian NFS 挂载(客户端)之间验证了这一点。

这是我对客户端的解决方案/破解:

#!/bin/bash 
path=$1
firstmd5=`ls -laR $path | md5sum | awk ' { print $1 }'`

    while true
    do 
       lastmd5=`ls -laR $path | md5sum | awk ' { print $1 }'`
       if [ $firstmd5 !=  $lastmd5 ]
       then
          firstmd5=$lastmd5
          echo files changed
       fi
       sleep 1
    done

当然,这不会报告正在更改的特定文件,但确实提供了一个通用通知钩子,表明某些内容已更改。

这很烦人/笨拙,但如果我需要更多细节,我会做一些额外的黑客攻击来隔离实际更改的文件。

于 2021-12-15T20:18:58.690 回答