【问题标题】:System.IO.FileSystemWatcher to monitor a network-server folder - Performance considerationsSystem.IO.FileSystemWatcher 监控网络服务器文件夹 - 性能注意事项
【发布时间】:2010-09-14 04:30:08
【问题描述】:

我想查看网络服务器上的文件夹树是否有变化。这些文件都有一个特定的扩展名。树中有大约 200 个文件夹和大约 1200 个带有我正在查看的扩展名的文件。

我无法编写要在服务器上运行的服务(禁止使用!),因此解决方案必须位于客户端本地。及时性并不是特别重要。我可以忍受一分钟或更长时间的通知延迟。我正在关注创建、删除、重命名和更改。

使用 .NET System.IO.fileSystemWatcher 会在服务器上产生大量负载吗?

10 个独立的观察者如何减少被观察的文件夹/文件的数量? (从 700 个文件夹减少到 200 个,总共从 5500 个文件减少到 1200 个)更多网络流量而不是更少?我的想法是在服务器上重新洗牌,将监视的文件放在一棵树下。我可能并不总是有这个选项,因此是观察者团队。

我想另一种解决方案是定期检查 FSW 是否在服务器上造成了过度负载,或者它是否由于一大堆 SysAdmin 类型的原因而无法正常工作。

有没有更好的方法来做到这一点?

【问题讨论】:

    标签: .net performance filesystemwatcher


    【解决方案1】:

    从服务器负载的角度来看,在您描述的场景中使用IO.FileSystemWatcher 进行远程更改通知可能是最有效的方法。它在内部使用FindFirstChangeNotificationReadDirectoryChangesW Win32 API 函数,进而以优化的方式与网络重定向器通信(假设标准 Windows 网络:如果使用第三方重定向器,它不支持所需的功能,事情根本不起作用)。 .NET 包装器还使用异步 I/O 和一切,进一步确保最高效率。

    这个解决方案的唯一问题是它不是很可靠。除了必须处理暂时断开的网络连接(这不是什么大问题,因为在这种情况下 IO.FileSystemWatcher 会触发一个您可以处理的错误事件),底层机制具有某些基本限制。来自 Win32 API 函数的 MSDN 文档:

    • ReadDirectoryChangesW 在缓冲区长度大于 64 KB 并且应用程序正在通过网络监视目录时失败并显示 ERROR_INVALID_PARAMETER。这是由于底层文件共享协议的数据包大小限制

    • 远程文件系统调用FindFirstChangeNotification时可能不会返回通知

    换句话说:在高负载下(当您需要一个大缓冲区时),或者更糟糕的是,在随机未指定的情况下,您可能不会收到您期望的通知。这甚至是本地文件系统观察者的问题,但更多的是网络上的问题。 Another question here on SO 更详细地详细说明了 API 的固有可靠性问题。

    使用文件系统观察程序时,您的应用程序应该能够处理这些限制。例如:

    • 如果您要查找的文件有序列号,请存储您收到通知的最后一个序列号,以便您可以在未来的通知中查找“空白”并处理您没有收到的文件通知;

    • 收到通知后,始终执行完整目录扫描。这听起来可能很糟糕,但由于扫描是事件驱动的,它仍然比哑轮询更有效。此外,只要您将文件总数保持在单个目录中,以及要扫描的目录数量在 1000 左右,此操作对性能的影响无论如何应该是非常小的。

    您应该尽可能避免设置多个侦听器:如果有的话,这会使事情变得更加不太可靠...

    无论如何,如果您绝对必须使用文件系统观察程序,只要您了解这些限制,一切都可以正常工作,并且不要期望每个修改的文件都会得到 1:1 通知/创建。

    所以,如果您有其他选择(基本上,让写入文件的过程以基于非文件系统的方式通知您:任何常规 RPC 方法都将是一种改进......),这些绝对值得研究可靠性的观点。

    【讨论】:

      【解决方案2】:

      我已经多次使用 C# 中的文件系统观察程序。第一次使用它们时,我遇到了它们停止工作的问题,主要是因为我正在处理报告更改的线程中的更改。

      但是,现在我只是将更改推送到一个队列并在另一个线程上处理该队列。这似乎解决了我最初遇到的问题。对于您的问题,您可以让多个观察者推送到同一个队列中。

      但是,我没有在你的问题范围内使用这个。

      【讨论】:

        【解决方案3】:

        根据我的经验,FSW 不会产生高网络流量。但是,如果存在性能问题,您使用多个观察者并将其分解为更少被观察的文件夹的方法听起来是合理的。

        不过,我在网络驱动器上使用 FSW 时遇到了一些大问题:删除文件总是引发错误事件,而不是删除事件。我没有找到解决方案,所以如果有解决方法,我现在避免使用 FSW...

        【讨论】:

          【解决方案4】:

          MSDN documentation indicates,您可以使用 FileSystemWatcher 组件来监视网络驱动器上的文件系统更改。

          它还表明观察程序组件侦听文件系统更改通知,而不是定期询问目标驱动器的更改。

          基于此,网络流量完全取决于您期望该网络驱动器的内容发生多少变化。 FSW 组件不会增加网络流量。

          【讨论】:

            【解决方案5】:

            Watcher 看起来 100% 可靠 - 只需查看 watcher 对象上的缓冲区大小。 我已经测试了数千个文件更新,没有一个丢失。

            我建议使用多线程方法 - 触发器是文件监视器。 它可以为检测到的每个文件更改启动一个线程。观察者可以更快地处理 溢出的可能性较小。 (使用异步线程)

            【讨论】:

            • 它在本地文件系统上看起来可能 100% 可靠,但在网络共享上却非常不可靠。如果提供共享服务的文件服务器被退回,则 FSW 脑死亡。
            • 补充一下 DSoa 所说的,我现在遇到了这个问题。如果 UNC 路径断开连接,网络共享不会导致在 FileShareWatcher 上触发错误事件。再一次,当重新连接 UNC 路径时,根本不会再为 FSW 触发任何事件!
            【解决方案6】:

            使用 System.IO.FileSystemWatcher 一段时间后。它不够稳定,无法处理来得太快的事件。确保 100% 读取文件。我使用简单的目录方法来搜索文件。阅读后,立即将文件复制到另一个文件夹。在您阅读文件时将其与添加的新文件隔离开来。

            定时器用于定时读取文件夹。通过将已读取的文件复制到存档文件夹,可以确保不会再次读取它。随后的读取将始终是新文件。

            var fileNames = Directory.GetFiles(srcFolder);
            foreach (string fileName in fileNames)
            {
               string[] lines = File.ReadAllLines(fileName);
            }
            

            【讨论】:

              【解决方案7】:

              我认为在带有 FSW 的计算机和其位置被监控的计算机之间没有任何类型的活动状态或通信。换句话说,FSW 不会 ping 联网操作系统来检查文件。

              人们可以想象,消息或事件在发生更改时被提出/发送到联网的 FSW。

              但这一切都只是猜测。 :)

              【讨论】:

              • 如果没有 ping 通,客户端如何知道服务器上的某些内容发生了变化? AFAIK FSW 不会在服务器上启动任何进程。不过,在这种情况下,AFIK 并不多。
              • 我们现在有了答案,但要回答您的问题:FSW 会向计算机发送请求,希望在文件更改时收到通知。您不必一直询问杂志是否有新刊,只需订阅一次,他们就会在新刊出版时发​​出。
              猜你喜欢
              • 1970-01-01
              • 2012-04-06
              • 1970-01-01
              • 2012-02-21
              • 1970-01-01
              • 1970-01-01
              • 2011-07-09
              • 2012-12-16
              • 2017-01-24
              相关资源
              最近更新 更多