对Windows网络共享的小写入在Windows上很慢,快于CIFS Linux安装

Modified on: Thu, 07 Nov 2019 02:40:03 +0800

在执行小写操作时,我一直在努力解决SMB / CIFS共享的性能问题。

首先,让我描述一下我当前的网络设置:

服务器强>

  • Synology DS215j(已启用SMB3支持)

客户端(同一台计算机双启动有线Gig-E)

  • Ubuntu 14.04.5 LTS,Trusty Tahr
  • Windows 8.1

的smb.conf 强>

[global] printcap name=cups winbind enum groups=yes include=/var/tmp/nginx/smb.netbios.aliases.conf socket options=TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=65536 SO_SNDBUF=65536 security=user local master=no realm=* passdb backend=smbpasswd printing=cups max protocol=SMB3 winbind enum users=yes load printers=yes workgroup=WORKGROUP

我目前正在使用以下用C ++编写的程序测试小写性能(在GitHub上这里):

[global]
    printcap name=cups
    winbind enum groups=yes
    include=/var/tmp/nginx/smb.netbios.aliases.conf
    socket options=TCP_NODELAY IPTOS_LOWDELAY SO_RCVBUF=65536 SO_SNDBUF=65536
    security=user
    local master=no
    realm=*
    passdb backend=smbpasswd
    printing=cups
    max protocol=SMB3
    winbind enum users=yes
    load printers=yes
    workgroup=WORKGROUP

Linux挂载配置:

#include <iostream>
#include <fstream>
#include <sstream>

using namespace std;

int main(int argc, char* argv[])
{
    ofstream outFile(argv[1]);
    for(int i = 0; i < 1000000; i++)
    {
        outFile << "Line #" << i << endl;   
    }

    outFile.flush();
    outFile.close();
    return 0;
}

Linux上的程序运行时间(峰值网络输出为~100Mbps):

//192.168.1.10/nas-main on /mnt/nas-main type cifs (rw,noexec,nodev)

PCAP快照显示将许多行分块为单个TCP数据包:

通过PowerShell测量Windows上的程序运行时:

&gt; Measure-Command {start-process .\nas-write-test.exe -argumentlist "Z:\home\will\test-win.txt" -wait} Days : 0 Hours : 0 Minutes : 9 Seconds : 29 Milliseconds : 316 Ticks : 5693166949 TotalDays : 0.00658931359837963 TotalHours : 0.158143526361111 TotalMinutes : 9.48861158166667 TotalSeconds : 569.3166949 TotalMilliseconds : 569316.6949

Windows上的PCAP快照显示每个SMB写入请求的单行:

这个程序在Windows上大约需要10分钟(~2.3Mbps)。显然,Windows PCAP显示出非常嘈杂的SMB会话,其有效负载效率非常低。

Windows上是否有可以提高小写性能的设置?从查看数据包捕获看来,Windows不能正确缓冲写入并立即一次发送一行数据。然而,在Linux上,数据被大量缓冲,因此具有更好的性能。让我知道PCAP文件是否有用,我可以找到上传它们的方法。

更新10/27/16:

如@sehafoc所述,我将Samba服务器max protocol设置减少为SMB1,其中包含以下内容:

max protocol=NT1

上述设置导致完全相同的行为。

我还通过在另一台Windows 10计算机上创建共享来删除Samba变量,并且它也表现出与Samba服务器相同的行为,所以我开始相信这是Windows客户端的写入缓存错误

更新:10/06/17:

完整的Linux数据包捕获(14MB)

完整的Windows数据包捕获(375MB)

更新:10/12/17:

我还设置了一个NFS共享,Windows也写了没有缓冲。所以,就我所知,它肯定是一个潜在的Windows客户端问题,这绝对是不幸的: - /

任何帮助都将不胜感激!

作者:,mevatron

最佳答案

C ++ endl被定义为输出'\ n',然后输出flush。 flush()是一项昂贵的操作,因此您通常应该避免使用endl作为默认的行尾,因为它可以准确地创建您所看到的性能问题(而不仅仅是SMB,但是任何具有昂贵刷新的流包括本地旋转生锈甚至是最新的NVMe,输出率都非常高。)

用“\ n”替换endl将通过允许系统按预期缓冲来修复上述性能。除了某些库可以刷新“\ n”,在这种情况下您会有更多的麻烦(请参阅https: //stackoverflow.com/questions/21129162/tell-endl-not-to-flush获取覆盖sync()方法的解决方案。)

现在要复杂化,flush()仅针对库缓冲区中发生的事情进行定义。未定义刷新对操作系统,磁盘和其他外部缓冲区的影响。对于Microsoft.NET“当您调用FileStream.Flush方法时,操作系统I / O缓冲区也会被刷新。” (https://msdn.microsoft.com/ en-us / library / 2bw4h516(v = vs.110).aspx)这使得flush对于Visual Studio C ++特别昂贵,因为它会将写入一直往返到远端的物理介质您正在看到的远程服务器。另一方面,GCC说:“最后提醒:通常涉及的缓冲区多于语言/库级别的缓冲区。内核缓冲区,磁盘缓冲区等也会产生影响。检查和更改这些缓冲区是系统相关的“。 (https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs .html)你的Ubuntu跟踪似乎表明操作系统/网络缓冲区没有被库flush()刷新。系统相关的行为将更有理由避免endl和过度冲洗。如果您使用的是VC ++,您可能会尝试切换到Windows GCC衍生产品,以查看系统相关行为的反应,或者使用Wine在Ubuntu上运行Windows可执行文件。

更一般地说,您需要考虑您的要求,以确定是否适当冲洗每一行。 endl通常适用于交互式流,例如显示器(我们需要用户实际看到我们的输出,而不是突发),但通常不适用于其他类型的流,包括刷新开销可能很大的文件。我已经看到应用程序在每个1和2以及4和8字节写入时刷新...看起来操作系统研磨数百万个IO来写1MB文件并不是很好。

作为示例,如果您正在调试崩溃,则日志文件可能需要刷新每一行,因为您需要在崩溃发生之前刷新ofstream;而另一个日志文件可能不需要刷新每一行,如果它只是产生在应用程序终止之前自动刷新的详细信息日志记录。它不需要/或者你可以派生出一个具有更复杂的刷新算法的类来满足特定的要求。

将您的案例与需要确保其数据完全持久保存到磁盘且在操作系统缓冲区中不易受攻击的人的对比情况进行比较(https://stackoverflow.com/questions/7522479/how-do-i-ensure-data-is-written-到磁盘之前闭-fstream的)。

请注意,如上所述,outFile.flush()是多余的,因为它会刷新已经刷新的流。要迂腐,你应该单独使用endl,或者最好使用outFile.flush()而不是两者都使用“\ n”。

作者:,Doug

相关问答

添加新评论