创建FileStream到网络共享超慢

时间:2014-03-07 10:26:48

标签: c# .net networking

我有一个Windows服务,必须在2个网络共享的约20个文件中写入大约20kB的数据。

使用Total Commander写入文件的时间:小于0.1秒。

使用我的应用程序编写文件的时间:ca 10s。

有什么问题?是的,不断从两个共享中读取文件,但它应该不是问题,因为:

public void WriteData(string text, string fileName, bool forceBackup = false) {
    foreach (var dir in Locations) {
        var path = string.Format(@"{0}\{1}", dir, fileName);
        FileStream stream = null;
        try {
            stream = new FileStream(
                path,
                FileMode.Create,
                FileAccess.Write,
                FileShare.Read
            );
            using (StreamWriter writer = new StreamWriter(stream)) {
                stream = null;
                writer.Write(text);
            }
        }
        catch (Exception) { } // irrelevant now, tested it doesn't throw exceptions anyway
        finally {
            if (stream != null) stream.Dispose();
        }
        File.SetLastWriteTime(path, DateTime.Now);
    }
}

上面的代码适用于本地文件。将所有数据写入RAM驱动器需要1毫秒。我的网络共享也位于RAM驱动器上。

重要的是 - 使用Total Commander将这些文件复制到完全相同的位置也需要一毫秒。我的意思是 - 在满负荷下复制到网络共享。

没有共享冲突,应用程序将文件写入单个线程。从Total Commander写入这些文件没有问题,使用我的应用程序在不使用网络共享的情况下写入这些文件没有问题。

没有共享冲突,因为在写入时 - 这些文件仅由Web服务器读取,FileAccess.ReadFileShare.ReadWrite显式设置。

不,我不能在不使用网络共享的情况下编写这些文件,因为我的服务是两台服务器之间的同步。不,我不能使用DFSR,因为文件经常更新(每秒2次)。不,我不能使用2个单独的服务来更新两台机器上的文件,因为它会取消故障保护功能,当我的服务的每个实例都可以停止而两台服务器上的数据更新都没有停止时。

详细说明,在我的生产环境中,有两个此服务实例,一个是更新文件,另一个是持续监视活动文件是否正常工作。检测到故障时,他们会切换角色。这一切都是实时发生的,并且充当魅力。有一个巨大的故障:写文件超长时间延迟。

如果你想知道File.SetLastWriteTime()代表什么 - 这是Windows(.NET)错误的解决方法,当文件上次写入时间没有单独使用create / write正确更新时。当然,正确的修改时间对于其他实例检测是否至关重要,如果第一个实例正在按时更新文件。

另外:据报道,有时会从这些文件中读取一些垃圾。但它很少发生。我还没有证实这个错误。

但主要问题是 - 花了这么长时间?我的测试服务器和目标服务器之间有快速的1GBit链接,生产服务器之间有10GBit链接。平低于1ms。这不是一个网络问题。


经过一些测试后,我发现缓冲区大小和文件选项对写入时间没有任何作用。我发现网络ping非常重要。我无法测试我的开发机器上的代码,因为ping太大了。

无论如何 - 如果所有文件都创建一次,那么代码可以优化为运行速度提高80%,然后在不重新创建流的情况下进行更新。当用于本地共享时,它也非常快。无论如何 - 测试代码很快,同一台服务器上的生产代码慢了50倍。但是有一点不同 - 生产文件经常被Web服务器读取,而测试文件则不是。

仍然 - 未达到目标。我需要在与10GBit / s以太网链接的2台服务器上每秒更新20 x 1kb文件。实现了200ms的延迟是可以接受的,但它只适用于测试文件,共享的真实文件每次更新仍然超过6000ms。

顺便说一句,当可靠性至关重要时,保持文件打开不是一个选项。该服务应该能够无缝地将所有更新切换到另一个实例,以防任何文件被删除,或者发生任何网络,数据库或磁盘错误。保持文件打开可能导致共享冲突,内存泄漏和其他灾难。正确处理不断打开的文件也会非常复杂,这会使代码更难调试。

也许还有另一种在服务器之间共享数据的方法?也许一个zip文件可以用来上传文件,然后另一个服务会解压缩文件?我很肯定压缩和解压缩1kB的数据不会花费长达1秒的时间!

2 个答案:

答案 0 :(得分:2)

我认为你的问题的答案在于这篇文章:

Writing to file using StreamWriter much slower than file copy over slow network

直接回答问题是它以4kbyte块而不是64Kbyte块来编写文件,这将导致更多往返。

你应该能够改变这个看到这个答案:

https://stackoverflow.com/a/14588922/3323733

答案 1 :(得分:0)

我错了,这很慢。它不是。问题出在测试程序中。我已经将基准测试代码添加到我的生产服务中,并且它显示它完全按预期工作。我的代码中没有错误,也没有滞后于我的系统。

一系列事件导致了这种情况:

  1. 一个叫我的家伙,我们的数据更新有很大的延迟(超过5秒)。
  2. 我在我的开发机器上运行了一个更新服务的调试版本,看看滞后几乎就是5到6秒。
  3. 我创建了这个帖子和测试项目,用于编写测试文件并测量时间
  4. 我在生产服务器上测试了代码,看它没有大的滞后工作
  5. 我在生产服务中添加了基准测试代码,以了解它在现实生活中的表现(并且表现完美)
  6. 我打电话给那个给我打电话的人问他是否看到了滞后 - 他说现在没有滞后
  7. 什么?好吧,这可能是HIS网络滞后!我的错!我应该从一开始就测试生产服务器上的代码。当网络连接速度和延迟对于该过程至关重要时,程序无法在任何其他环境中进行测试,或者可以对其进行测试,但不会针对速度或滞后进行测试。可能如果我有一个更大的文件,差异将不那么显着,但有20个小文件,我的机器和生产服务器之间的差异是巨大的。

    BTW,WriteData方法是最优的,没有什么可以改变的,用所有可能的文件模式和缓冲区大小进行测试。加快速度的唯一方法是保持所有文件打开,但这不值得。顺便说一句,生产服务器上传文件到远程FTP也快10倍左右。好吧,与公司局域网甚至公司广域网相比,我的广域网是一只乌龟。从一开始就应该很明显。