场景:我们有许多Windows客户端定期上传大文件(FTP / SVN / HTTP PUT / SCP)到Linux服务器,距离大约100-160ms。 我们在办公室拥有1Gbit / s的同步带宽,服务器可以是AWS实例,也可以物理托pipe在美国的DC中。
最初的报告是,上传到一个新的服务器实例比他们可能慢得多。 这在testing和多个地点都出现了; 客户从他们的Windows系统看到主机稳定的2-5Mbit / s。
我在AWS实例上发现了iperf -s
,然后从办公室的Windows客户端发出了:
iperf -c 1.2.3.4
[ 5] local 10.169.40.14 port 5001 connected with 1.2.3.4 port 55185 [ 5] 0.0-10.0 sec 6.55 MBytes 5.48 Mbits/sec
iperf -w1M -c 1.2.3.4
[ 4] local 10.169.40.14 port 5001 connected with 1.2.3.4 port 55239 [ 4] 0.0-18.3 sec 196 MBytes 89.6 Mbits/sec
后面的数字在随后的testing(AWS的Vagaries)中可能会有很大的不同,但通常在70到130Mbit / s之间,这对我们的需求来说已经足够了。 通过对会话进行线切割,我可以看到:
iperf -c
Windows SYN – Window 64kb,Scale 1 – Linux SYN,ACK:窗口14kb,比例:9(* 512) iperf -c -w1M
Windows SYN – Windows 64kb,Scale 1 – Linux SYN,ACK:窗口14kb,比例:9 显然这个链接可以保持这个高吞吐量,但是我必须明确地设置窗口大小来使用它,大多数现实世界的应用程序都不会让我这样做。 TCP握手在每种情况下使用相同的起点,但是强制的握手缩放
相反,从同一个networking上的一个Linux客户端直接, iperf -c
(使用系统默认的85kb)给了我:
[ 5] local 10.169.40.14 port 5001 connected with 1.2.3.4 port 33263 [ 5] 0.0-10.8 sec 142 MBytes 110 Mbits/sec
没有任何的强迫,它如预期地缩放。 这不能在干预的跳跃或我们的本地交换机/路由器,似乎影响Windows 7和8客户端。 我已经阅读了很多关于自动调整的指南,但是这些通常是关于彻底禁用扩展以解决糟糕的家庭networking工具包。
谁能告诉我这里发生了什么,给我一个修复它的方法? (最好是我可以通过GPO坚持registry。)
有问题的AWS Linux实例在sysctl.conf
应用了以下内核设置:
net.core.rmem_max = 16777216 net.core.wmem_max = 16777216 net.core.rmem_default = 1048576 net.core.wmem_default = 1048576 net.ipv4.tcp_rmem = 4096 1048576 16777216 net.ipv4.tcp_wmem = 4096 1048576 16777216
我使用了dd if=/dev/zero | nc
dd if=/dev/zero | nc
redirect到/dev/null
在服务器端排除iperf
并删除任何其他可能的瓶颈,但结果是相同的。 使用ncftp
(Cygwin,Native Windows,Linux)进行testing的规模与上述各自平台上的iperftesting非常相似。
我在这里发现了另一个一致的东西,可能是相关的:
这是1MB捕获的第一秒,放大。当窗口放大并且缓冲区变大时,您可以看到“ 慢启动 ”操作。 那么就有一个这么小的高度〜0.2s,就是默认窗口iperftesting永远展平了。 这当然会扩展到很多高潮,但是在这种情况下,在缩放(值为1022bytes * 512 = 523264)时会出现这种暂停。
跟进各种回应:
O,所以按照Kyle的build议,我启用了ctcp和禁用的烟囱卸载:TCP全局参数
---------------------------------------------- Receive-Side Scaling State : enabled Chimney Offload State : disabled NetDMA State : enabled Direct Cache Acess (DCA) : disabled Receive Window Auto-Tuning Level : normal Add-On Congestion Control Provider : ctcp ECN Capability : disabled RFC 1323 Timestamps : enabled Initial RTO : 3000 Non Sack Rtt Resiliency : disabled
但可悲的是,吞吐量没有变化。
不过,我在这里确实有一个因果关系的问题:这些graphics是在服务器对客户端的ACK中设置的RWIN值。 对于Windows客户端,我是否认为Linux不会将这个值扩展到最低点以下,因为客户端的CWIN限制了这个缓冲区的填充? Linux是否会人为限制RWIN还有其他一些原因吗?
注意:我已经试过打开ECN的地狱了, 但没有改变,那里。
禁用启发式和RWIN自动调整后没有改变。 英特尔networking驱动程序更新到最新(12.10.28.0)与软件通过设备pipe理器选项卡公开function调整。 该卡是82579V芯片组板载网卡 – (我打算用realtek或其他供应商进行更多的testing)
关注NIC一会儿,我尝试了以下(主要是排除不可能的罪魁祸首):
试图消除Linux服务器端,我启动了Server 2012R2实例,并重复使用iperf
(cygwin二进制)和NTttcptesting 。
有了iperf
,我必须明确指定双方的-w1m
,然后才能连接超过〜5Mbit / s。 (顺便说一句,我可以检查,在延迟91毫秒〜5Mbits的BDP几乎正好是64kb。发现极限…)
ntttcp二进制文件现在显示了这样的限制。 在服务器上使用ntttcpr -m 1,0,1.2.3.5
,在客户端上使用ntttcpr -m 1,0,1.2.3.5
ntttcp -s -m 1,0,1.2.3.5 -t 10
,可以看到更好的吞吐量:
Copyright Version 5.28 Network activity progressing... Thread Time(s) Throughput(KB/s) Avg B / Compl ====== ======= ================ ============= 0 9.990 8155.355 65536.000 ##### Totals: ##### Bytes(MEG) realtime(s) Avg Frame Size Throughput(MB/s) ================ =========== ============== ================ 79.562500 10.001 1442.556 7.955 Throughput(Buffers/s) Cycles/Byte Buffers ===================== =========== ============= 127.287 308.256 1273.000 DPCs(count/s) Pkts(num/DPC) Intr(count/s) Pkts(num/intr) ============= ============= =============== ============== 1868.713 0.785 9336.366 0.157 Packets Sent Packets Received Retransmits Errors Avg. CPU % ============ ================ =========== ====== ========== 57833 14664 0 0 9.476
8MB / s在iperf
使用明确的大窗口时会达到这个水平。 奇怪的是,1273缓冲区中的80MB = 64KB缓冲区。 另一个wireshark显示一个好的,可变的RWIN从服务器返回(比例因子256),客户似乎履行; 所以也许ntttcp是误报发送窗口。
在@ karyhead的请求,我已经做了一些更多的testing,并产生了更多的捕获,在这里: https ://www.dropbox.com/s/dtlvy1vi46x75it/iperf%2Bntttcp%2Bftp-pcaps-2014-07-03.zip
iperf
:一个具有128k的Socket大小和默认的64k窗口(限制到〜5Mbit / s),一个带有1MB的发送窗口和默认的8kb套接字大小。 (规模较高) ntttcp
跟踪。 这里吞吐量很好。 注意:在打开testing连接之前,NTttcp在端口6001上做了一些奇怪的事情。 不知道那里发生了什么事。 ncftp
将20MB的/dev/urandom
上传到一个几乎完全相同的linux主机(1.2.3.6)。 再次,限制在那里。 使用Windows Filezilla的模式非常相似。 更改iperf
缓冲区长度确实会使时间序列图(更多垂直部分)的预期差异,但实际的吞吐量不变。
你有没有尝试在Windows 7/8客户端启用化合物TCP (CTCP)。
请阅读:
提高发送端的高BDP传输性能
http://technet.microsoft.com/en-us/magazine/2007.01.cableguy.aspx
…
这些algorithm适用于小BDP和较小的接收窗口大小。 但是,如果您的TCP连接具有较大的接收窗口大小和较大的BDP ,例如在跨越高速WAN链接的两台服务器之间复制数据(往返时间为100ms) ,则这些algorithm不会增加发送窗口快到足以充分利用连接的带宽 。
为了在这些情况下更好地利用TCP连接的带宽,下一代TCP / IP协议栈包括复合TCP(CTCP)。 CTCP更积极地增加 大接收窗口大小和BDP连接 的发送窗口 。 CTCP试图通过监测延迟变化和损失来使这些types的连接的吞吐量最大化。 此外,CTCP确保其行为不会对其他TCP连接产生负面影响。
…
运行Windows Server 2008的计算机默认情况下启用CTCP,并且在运行Windows Vista的计算机上默认情况下禁用CTCP。 你可以使用
netsh interface tcp set global congestionprovider=ctcp
命令启用CTCP。 你可以使用netsh interface tcp set global congestionprovider=none
命令禁用CTCP。
编辑6/30/2014
看CTCP是否真的“开”
> netsh int tcp show global
即
PO说:
如果我正确地理解了这个,这个设置增加了 拥塞窗口被放大 的速度, 而不是 它可以达到 的最大大小
CTCP积极增加发送窗口
http://technet.microsoft.com/en-us/library/bb878127.aspx
复合TCP
现有的防止发送TCP对等体压倒networking的algorithm称为慢启动和拥塞避免。 当最初在连接上发送数据时以及从丢失的段中恢复时,这些algorithm增加了发送者可以发送的段(称为发送窗口)的数量。 对于接收到的每个确认段(对于Windows XP和Windows Server 2003中的TCP)或确认的每个段(对于Windows Vista和Windows Server 2008中的TCP),启动速度较慢均会使发送窗口增加一个完整的TCP段。 拥塞避免将发送窗口增加一个完整的TCP段,以确认每个完整的数据窗口。
这些algorithm适用于LAN介质速度和较小的TCP窗口大小。 但是,如果您的TCP接口的接收窗口大小较大,带宽延迟较大(高带宽和高延迟),则可能需要在跨越高速WAN链路的两台服务器之间复制数据(往返时间为100 ms)时间,这些algorithm不会足够快地增加发送窗口以充分利用连接的带宽。 例如,在往返时间(RTT)为100毫秒的1千兆比特每秒(Gbps)WAN链路上, 发送窗口最初 可能 需要一个小时才能增加到 由接收方广播 的 大窗口大小,当 有丢失的部分 时恢复 。
为了在这些情况下更好地利用 TCP连接的带宽 ,下一代TCP / IP协议栈包括复合TCP (CTCP)。 CTCP更积极地增加大接收窗口大小和大带宽延迟产品连接的发送窗口。 CTCP试图通过监测延迟变化和损失来使这些types的连接的吞吐量最大化。 CTCP还确保其行为不会对其他TCP连接产生负面影响。
在Microsoft内部进行的testing中,使用50ms RTT进行1 Gbps连接的大文件备份时间减less了将近一半。 具有更大带宽延迟产品的连接可以具有更好的性能。 CTCP和接收窗口自动调谐一起工作,以提高链路利用率,并可为大带宽延迟产品连接带来显着的性能提升。
TCP有两个窗口:
在你提供的捕获文件中。 我们可以看到接收缓冲区永远不会溢出:
我的分析是发送者发送速度不够快,因为发送窗口(也就是拥塞控制窗口)没有足够的开放来满足接收者的RWIN。 所以简而言之,接收者说“给我更多”,当Windows是发送者时,发送速度不够快。
这可以从以下事实得到证实:在上面的图中,RWIN保持打开状态,往返时间为.09秒,RWIN为〜500,000字节,我们可以根据带宽延迟乘积得出最大吞吐量(500000 /0.09)* 8 =〜42 Mbit / s(而且你只能获得大约5分的胜利)。
我不知道。 interface tcp set global congestionprovider=ctcp
听起来像是对我做的正确的事情,因为它会增加发送窗口(这是拥塞窗口的另一个术语)。 你说这是行不通的。 所以只是为了确保:
netsh interface tcp show heuristics
。 我认为这可能是RWIN,但它并没有说,所以也许玩禁用/启用,如果它影响发送窗口。 我会尝试所有这些实验,所有你卸载function,以消除networking驱动程序正在做一些重写/修改的东西(保持眼睛CPU卸载时禁用)的可能性开始。 TCP_OFFLOAD_STATE_DELEGATED结构似乎至less意味着CWnd卸载至less是可能的。
@Pat和@Kyle有一些很棒的信息。 肯定要注意@Kyle对TCP的接收和发送窗口的解释 ,我觉得周围有一些困惑。 为了进一步混淆事件,iperf使用术语“TCP窗口”和-w
设置,这是关于接收,发送或整体滑动窗口的模糊术语。 它实际上是为-c
(客户机)实例设置套接字发送缓冲区,并在-s
(服务器)实例上设置套接字接收缓冲区。 在src/tcp_window_size.c
:
if ( !inSend ) { /* receive buffer -- set * note: results are verified after connect() or listen(), * since some OS's don't show the corrected value until then. */ newTCPWin = inTCPWin; rc = setsockopt( inSock, SOL_SOCKET, SO_RCVBUF, (char*) &newTCPWin, sizeof( newTCPWin )); } else { /* send buffer -- set * note: results are verified after connect() or listen(), * since some OS's don't show the corrected value until then. */ newTCPWin = inTCPWin; rc = setsockopt( inSock, SOL_SOCKET, SO_SNDBUF, (char*) &newTCPWin, sizeof( newTCPWin )); }
正如凯尔提到的那样,问题不在于Linux机器上的接收窗口,而是发送器没有足够的开放发送窗口。 这并不是说它的开放速度不够快,它只能达到64k。
Windows 7上的默认套接字缓冲区大小是64k。 以下是文档中关于与MSDN吞吐量相关的套接字缓冲区大小的说明
使用Windows套接字通过TCP连接发送数据时,为了实现最高的吞吐量,在TCP中保留足够数量的未完成数据(发送但尚未确认)是非常重要的。 为了达到TCP连接的最佳吞吐量而突出的数据量的理想值被称为理想发送积压(ISB)大小。 ISB值是TCP连接和接收者公布的接收窗口的带宽延迟乘积(部分是networking拥塞量)的函数。
好吧,等等等等,现在我们走了:
一次执行一个阻塞或非阻塞发送请求的应用程序通常依靠Winsock的内部发送缓冲来实现相当的吞吐量。 给定连接的发送缓冲区限制由SO_SNDBUF套接字选项控制。 对于阻塞和非阻塞发送方法, 发送缓冲区限制决定了TCP中有多less数据保持未完成状态 。 如果连接的ISB值大于发送缓冲区限制,则在连接上达到的吞吐量将不是最佳的。
最近使用64k窗口的iperftesting的平均吞吐量是5.8Mbps。 这是来自统计>摘要在Wireshark,统计所有的位。 可能,iperf正在计算TCP数据吞吐量为5.7Mbps。 我们也看到与FTPtesting相同的性能,〜5.6Mbps。
具有64k发送缓冲器和91ms RTT的理论吞吐量是…. 5.5Mbps。 足够接近我。
如果我们看你的1MB窗口iperftesting,输出是88.2Mbps(TCP数据为86.2Mbps)。 具有1MB窗口的理论输出是87.9Mbps。 再次,足够接近政府工作。
这certificate了发送套接字缓冲区直接控制发送窗口,并且与另一端的接收窗口一起控制吞吐量。 广告的接收窗口有空间,所以我们不受接收机的限制。
抱起来,这个自动调整业务呢? Windows 7不会自动处理这些东西? 如前所述,Windows不会处理接收窗口的自动缩放,但它也可以dynamic地处理发送缓冲区。 我们回到MSDN页面:
在Windows 7和Windows Server 2008 R2上添加了针对TCP的dynamic发送缓冲。 默认情况下,除非应用程序在stream套接字上设置SO_SNDBUF套接字选项,否则将启用TCP的dynamic发送缓冲。
当使用-w
选项时,iperf使用SO_SNDBUF
,所以dynamic发送缓冲将被禁用。 但是,如果您不使用-w
那么它不会使用SO_SNDBUF
。 dynamic发送缓冲应该在默认情况下,但你可以检查:
netsh winsock show autotuning
该文件说,你可以禁用它:
netsh winsock set autotuning off
但是这对我没有用。 我不得不做一个registry更改,并将其设置为0:
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\AFD\Parameters\DynamicSendBufferDisable
我不认为禁用这将有助于; 这只是一个FYI。
为什么当发送数据到一个在接收窗口中有足够空间的Linux机器时,你的发送缓冲区不能扩展到默认的64k以上呢? 伟大的问题。 Linux内核也有一个自动调整的TCP栈。 就像T-Pain和Kanye一起做自动调音,听起来可能不太好。 也许这两个自动调整的TCP协议栈之间存在一些问题。
另一个人就像你的问题,并能修复registry编辑,以增加默认的发送缓冲区大小。 不幸的是,这似乎不再起作用,至less在我尝试时并不适合我。
在这一点上,我认为很明显,限制因素是Windows主机上的发送缓冲区大小。 鉴于它似乎没有dynamic增长,女孩子该做什么?
您可以:
免责声明:我花了很多时间研究这个问题,这是我的最好的知识和谷歌福是正确的。 但我不会在我母亲的坟墓上发誓(她还活着)。
一旦你调整了TCP堆栈,你可能仍然在Winsock层有一个瓶颈。 我发现在Windows 7中configurationWinsock(辅助function驱动程序)对于上传速度(将数据推送到服务器)有很大的不同。微软已经承认TCP自动调用非阻塞套接字中的一个错误 – 只是浏览器使用的一种套接字;-)
为DefaultSendWindow添加DWORD键并将其设置为BDP或更高版本。 我正在使用256000。
HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\services\AFD\Parameters\DefaultSendWindow
更改下载Winsock设置可能会有所帮助 – 为DefaultReceiveWindow添加一个密钥。
您可以使用Fiddler Proxy和命令来调整客户端和服务器套接字缓冲区大小,以尝试各种套接字级别设置:
prefs set fiddler.network.sockets.Server_SO_SNDBUF 65536 fiddler.network.sockets.Client_SO_SNDBUF fiddler.network.sockets.Client_SO_RCVBUF fiddler.network.sockets.Server_SO_SNDBUF fiddler.network.sockets.Server_SO_RCVBUF
在阅读了答案中的所有分析之后,这个问题听起来像是在运行Windows7 / 2008R2又名Windows 6.1
Windows 6.1中的networking堆栈(TCP / IP&Winsock)存在可怕的缺陷,并且存在大量的错误和性能问题,微软最终从6.1的最初版本开始就经历了多年的修复。
应用这些修补程序的最佳方法是手动筛选support.microsoft.com上的所有相关页面,并手动请求并下载networking堆栈修补程序的LDR版本(其中包含许多这样的修复程序)。
要查找相关修补程序,必须将www.bing.com与以下search查询site:support.microsoft.com 6.1.7601 tcpip.sys
您还需要了解LDR / GDR修复程序在Windows 6.1中如何工作
我通常用来维护我自己的Windows 6.1的LDR修复列表(不只是networking堆栈修复),然后主动将这些修复应用到我遇到的任何Windows 6.1服务器/客户端。 定期检查新的LDR修补程序是非常耗时的工作。
幸运的是,微软已经停止了使用较新的操作系统版本的LDR修补程序的做法,现在可以通过微软的自动更新服务来修复错误。
更新 :只是Windows7SP1中的许多networking错误的一个例子 – https://support.microsoft.com/en-us/kb/2675785
更新2 :这是另一个修补程序,它添加一个netsh开关,以便在第二次重新传输SYN数据包之后强制Window缩放(默认情况下,在重新传输2个SYN数据包之后,将禁用窗口缩放) https://support.microsoft.com/zh-cn/library-我们/ KB / 2780879
我遇到了与Windows客户端(Windows 7)类似的问题。 我经历了大部分的debugging,禁用了Naglealgorithm,TCP Chimney Offloading以及其他大量的TCP相关设置更改。 其中没有任何影响。
最后修复了AFD服务registry的默认发送窗口。 这个问题似乎与afd.sys文件有关。 我testing了几个客户端,有些显示上传缓慢,有些则没有,但都是Windows 7机器。 显示缓慢行为的机器具有相同版本的AFD.sys。 对于某些AFD.sys版本的计算机,需要使用registry解决方法(对不起,请不要回忆版本#)。
HKLM \ CURRENTCONTROLSET \ SERVICES \ AFD \参数
添加 – DWORD – DefaultSendWindow
值 – 十进制 – 1640960
这个值是我在这里find的: https : //helpdesk.egnyte.com/hc/en-us/articles/201638254-Upload-Speed-Slow-over-WebDAV-Windows-
我认为要使用适当的值,你应该使用下面的方法来计算它:
例如。 广告上传:15 Mbps = 15,000 Kbps
(15000/8)* 1024 = 1920000
据我所知,客户端软件通常应该覆盖registry中的这个设置,但是如果他们不这样做的话,就会使用默认值,而且显然AFD.sys文件的某些版本的默认值非常低。
我注意到,大多数MS产品有缓慢的上传问题(IE浏览器,迷你redirect器(WebDAV),FTP通过Windows资源pipe理器等…)当使用第三方软件(例如Filezilla),我没有相同的减速。
The AFD.sys effects all Winsock connections, so this fix should apply to FTP, HTTP, HTTPS, etc…
Also, this fix was listed above somewhere as well, so I don't want to take credit for it if it works for anybody, however there was so much information in this thread that I was afraid it might have been glossed over.
Well, I've run into a similar situation myself (my question here ), and in the end I had to disable TCP scaling heuristics, manually set the autotuning profile and enable CTCP:
# disable heuristics C:\Windows\system32>netsh interface tcp set heuristics wsh=disabled Ok. # enable receive-side scaling C:\Windows\system32>netsh int tcp set global rss=enabled Ok. # manually set autotuning profile C:\Windows\system32>netsh interface tcp set global autotuning=experimental Ok. # set congestion provider C:\Windows\system32>netsh interface tcp set global congestionprovider=ctcp Ok.
I see this is a little bit older post but it could help others.
In short you have to enable "Receive Window Auto-Tuning":
netsh int tcp set global autotuninglevel=normal
CTCP means nothing without above enabled.
If you disable "Receive Window Auto-Tuning" you will be stuck at 64KB packet size which has negative impact over long RTT's in high broadband connections. You can also experiment with "restricted" and "highlyrestricted" option.
Very good reference: https://www.duckware.com/blog/how-windows-is-killing-internet-download-speeds/index.html
I don't have enough points to comment, so I'll post an "answer" instead. I'm having what appears to be a similar/identical problem (see serverfault question here ). My (and probably your) problem is the send buffer of the iperf client on windows. It does not grow beyond 64 KB. Windows is supposed to dynamically grow the buffer when it is not explicitly sized by the process. But that dynamic growth is not happening.
I'm not sure about your window scaling graph that shows the window opening up to 500,000 bytes for your "slow" Windows case. I expected to see that graph open to only ~64,000 bytes given that you are limited to 5 Mbps.
This is a fascinating thread and exactly matches issues I've had using Win7/iperf to test throughput on long fat pipes.
The solution for Windows 7 is to execute the following command on both the iperf server AND the client.
netsh interface tcp set global autotuninglevel=experimental
NB: Before you do this, be sure to record the current status of autotuning:
netsh interface tcp show global
Receive Window Auto-Tuning Level : disabled
Then run the iperf server/client at each end of the pipe.
Reset the autotuning value following your tests:
netsh interface tcp set global autotuninglevel=
autotuninglevel - One of the following values: disabled: Fix the receive window at its default value. highlyrestricted: Allow the receive window to grow beyond its default value, but do so very conservatively. restricted: Allow the receive window to grow beyond its default value, but limit such growth in some scenarios. normal: Allow the receive window to grow to accomodate almost all scenarios. experimental: Allow the receive window to grow to accomodate extreme scenarios.