在Windows上,对SMB网络共享的小写操作速度较慢,在CIFS Linux挂载上速度较快


10

在执行小写操作时,我一直在努力解决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上,在这里)测试小型写入性能:

#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挂载配置:

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

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

$ time ./nas-write-test /mnt/nas-main/home/will/test.txt

real    0m0.965s
user    0m0.148s
sys 0m0.672s

PCAP快照显示将多个行分块到一个TCP数据包中:

Linux PCAP快照

由PowerShell衡量的Windows上的程序运行时:

> 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 PCAP快照

在Windows上,相同的程序大约需要10分钟(〜2.3Mbps)。显然,Windows PCAP显示了一个非常嘈杂的SMB对话,并且负载效率非常低。

Windows上是否有任何设置可以提高小写性能?从数据包捕获看来,Windows无法正确缓冲写入操作,并立即一次将数据发送出一行。而在Linux上,数据被大量缓冲,因此具有优越的性能。让我知道PCAP文件是否有帮助,我可以找到一种上载它们的方法。

更新10/27/16:

如@sehafoc所述,我max protocol使用以下命令将Samba服务器设置减小为SMB1:

max protocol=NT1

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

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

更新:10/06/17:

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

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

更新:10/12/17:

我还设置了一个NFS共享,Windows也确实为此编写了没有缓冲的内容。因此,据我所知,这绝对是Windows客户端的根本问题,这绝对是不幸的:-/

任何帮助,将不胜感激!

Answers:


2

C ++ endl定义为输出“ \ n”,然后输出刷新。flush()是一项昂贵的操作,因此您通常应避免将endl用作默认的行尾,因为它可能会完全造成您所看到的性能问题(而不仅是SMB,而且任何使用昂贵的刷新的流(包括本地旋转)锈蚀,甚至是最新的NVMe,其产出率都高得离谱。

将endl替换为“ \ n”将通过允许系统按预期缓冲来解决上述问题。除了某些库可能会刷新“ \ n”外,在这种情况下,您会更加头疼(有关覆盖sync()方法的解决方案,请参见/programming/21129162/tell-endl-not-to-flush) )。

现在使事情复杂化的是,只针对库缓冲区内发生的情况定义了flush()。未定义刷新对操作系统,磁盘和其他外部缓冲区的影响。对于Microsoft.NET“当您调用FileStream.Flush方法时,还将刷新操作系统I / O缓冲区。” (https://msdn.microsoft.com/zh-cn/library/2bw4h516(v=vs.110).aspx)这使刷新对于Visual Studio C ++而言特别昂贵,因为它将使写操作一直往返于如您所见,位于远程服务器远端的物理介质。另一方面,GCC表示:“最后提醒:通常涉及的缓冲区不仅仅是语言/库级别的缓冲区。内核缓冲区,磁盘缓冲区等也将起作用。检查和更改它们取决于系统。”https://gcc.gnu.org/onlinedocs/libstdc++/manual/streambufs.html)您的Ubuntu痕迹似乎表明库flush()不会刷新操作系统/网络缓冲区。与系统相关的行为将是避免过度拖尾和过度冲洗的更多原因。如果您使用的是VC ++,则可以尝试切换到Windows GCC派生类,以查看系统相关行为的反应,或者使用Wine在Ubuntu上运行Windows可执行文件。

通常,您需要考虑自己的要求,以确定冲洗每一行是否合适。endl通常适用于交互式流,例如显示(我们需要用户实际看到我们的输出,而不是突发显示),但通常不适合其他类型的流,包括冲洗开销可能很大的文件。我已经看到应用程序每1、2、4和8字节写入都会刷新……这并不是很高兴看到OS磨碎了数以百万计的IO来写一个1MB的文件。

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

将您的情况与需要确保其数据完全持久保存到磁盘并且在操作系统缓冲区中不易受攻击的人员进行对比(/programming/7522479/how-do-i-ensure-data是在关闭fstream之前写入磁盘的

请注意,如前所述,outFile.flush()是多余的,因为它会刷新已刷新的流。要学究,应该单独使用endl,或者最好与outFile.flush()一起使用“ \ n”,但不能同时使用。


太感谢了!您应得的分数超过100分,但这就是我所能提供的:)绝对是问题所在!
mevatron

2

我的声誉不足,无法发表评论(考虑到对此答案的验证水平,我认为这样做会更好)。

我注意到Linux与Windows级别跟踪中的一个大差异是您在Linux上使用SMB1,在Windows中使用SMB2。也许批处理oplock机制在SMB1 samba中的性能要好于SMB2独占租用的实现。在两种情况下,这些都应允许一定数量的客户端缓存。

1)也许尝试在Samba中设置较低的最大协议级别以尝试使用SMB1的Windows 2)验证是否排除了独占oplock或租约

希望这可以帮助 :)


2

使用SMB协议的远程文件操作(例如读/写)的性能可能会受到服务器和客户端分配的缓冲区大小的影响。缓冲区大小确定发送固定数量的数据所需的往返次数。每次在客户端和服务器之间发送请求和响应时,所花费的时间至少等于双方之间的等待时间,这对于广域网(WAN)而言可能非常重要。

SMB缓冲区-可以通过以下注册表设置来配置MaxBufferSize:

HKLM\SYSTEM\CurrentControlSet\Services\LanmanServer\Parameters\SizeReqBuf

数据类型: REG_DWORD

范围:1024至65535(根据您的要求选择值,高于5000)

但是SMB签名会影响允许的最大缓冲区大小。因此,我们还需要禁用SMB签名以实现我们的目标。需要在服务器端和客户端(如果可能)上都创建以下注册表。

HKEY_LOCAL_MACHINE\System\CurrentControlSet\Services\LanManWorkstation\Parameters

值名称: EnableSecuritySignature

数据类型: REG_DWORD

数据:0(禁用),1(启用)


谢谢你的提示; 但是,我尝试了这两种补救措施,但仍然看到上述现象:-/
mevatron '16

您可能还想检查为什么“ Synology DS215j”没有使用SMB3。默认情况下,在Win 8.1上启用SMB3。
阿迪贾(Adi Jha)

1

有趣的现象。这是我会尝试的方法-我不知道这是否真的有帮助。如果这是我的机器,那么我将广泛监视SMB性能指标。其中之一显示原因。

更多尝试

添加更多工作线程

万一SMB_RDR obens了一个写I /每行O请求(我应该不会在这里发生),它可以帮助一些线程添加到执行引擎。

将“ AdditionalCriticalWorkerThreads”设置为2,然后设置为4。

HKLM\System\CurrentControlSet\Control\Session Manager\Executive\AdditionalCriticalWorkerThreads

默认值为0,这意味着不添加任何其他关键内核工作线程。通常是可以的。该值影响文件系统缓存用于预读和后写请求的线程数。增大此值可以使存储子系统中有更多排队的I / O(这很不错,当您要逐行编写时),但是CPU开销更大。

添加更多队列长度

增加“ AdditionalCriticalWorkerThreads”的值将增加文件服务器可用于服务并发请求的线程数。

HKLM\System\CurrentControlSet\Services\LanmanServer\Parameters\MaxThreadsPerQueue

默认值为20。如果SMB2工作队列增长得​​非常大(性能计数器'Server Work Queues \ Queue Length \ SMB2 *'应该小于100),则可能需要增加该值。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.