混合以太网速度下的 Windows 2008 Server — 从共享下载速度慢,但普通 TCP 速度快

Tom*_*zky 6 networking windows-server-2008 performance file-server gigabit-ethernet

我有一个 Windows Server 2008 R2 x64 服务器,它是 AD 控制器和文件服务器。我有一个问题,Windows XP客户端可怕遇到缓慢(10Mbps以上少了,真是不到十兆比特-per秒)从共享文件的下载。

服务器使用 1Gbps Nvidia NForce 卡连接到 1Gbps 交换机,客户端使用 100Mbps 内置卡连接。

当我从 CentOS Linux 5.5 Live-USB 启动客户端计算机并使用 smbclient 进行下载时,也可以看到这种缓慢的下载。但是从 Linux 服务器上的 Samba 共享下载,它也使用 1Gbps 链接连接,速度很快。

非常奇怪的是,我创建了两个程序(附在下面),它们在 C# 中测试普通 TCP 吞吐量,并且它们按预期执行 - 大约为 89Mbps。

我在客户端上禁用了防火墙,我dot_nc_l 21000 > NIL在客户端和dot_nc [client_ip] < 100m.datWindows 服务器上使用。当从共享中复制相同的 100MB 文件需要 2 分钟时,我得到大约 9 秒。

如何消除这种情况?


Linux客户端用wireshark生成的一些图片:

从连接1Gbps网卡的Windows 2008 CIFS文件服务器下载100MB文件到连接100Mbps网卡和smbclient的Centos 5 Linux客户端: 看起来像鲨鱼牙齿的图表

从连接1Gbps网卡的Samba上的Fedora Linux CIFS文件服务器下载100MB文件到连接100Mbps网卡和smbclient的Centos 5 Linux客户端(同上): 不是在地震期间看起来像地震仪的图表


以下是这些程序(链接是使用 mono 的 gmcs 编译的,需要 .NET2):

dot_nc.cs

using System;
using System.IO;
using System.Diagnostics;
using System.Net.Sockets;

public class dot_nc
{
 public static void Main(string[] args) {
  string hostname = args[0];
  int port = int.Parse(args[1]);

  Stopwatch stopwatch = new Stopwatch();

  stopwatch.Start();
  TcpClient client = new TcpClient(hostname, port);
  stopwatch.Stop();
  Console.WriteLine("Connection: {0}ms", stopwatch.ElapsedMilliseconds);

  stopwatch.Reset();
  stopwatch.Start();
  byte[] buffer = new byte[4096];
  {
   Stream stdin = Console.OpenStandardInput();
   NetworkStream netout = client.GetStream();
   while ( true ) {
    int bytesread = stdin.Read(buffer, 0, buffer.Length);
    if ( bytesread <= 0 ) {
     break;
    }
    netout.Write(buffer, 0, bytesread);
   }
  }
  stopwatch.Stop();
  Console.WriteLine("Sending: {0}ms", stopwatch.ElapsedMilliseconds);
  client.Close();
 }
}
Run Code Online (Sandbox Code Playgroud)

dot_nc_l.cs

using System;
using System.IO;
using System.Diagnostics;
using System.Net;
using System.Net.Sockets;

public class dot_nc
{
 public static void Main(string[] args) {
  int port = int.Parse(args[0]);

  TcpListener server = new TcpListener(IPAddress.Any, port);
  server.Start();
  TcpClient client = server.AcceptTcpClient();
  NetworkStream netin = client.GetStream();

  byte[] buffer = new byte[4096];

  Stream stdout = Console.OpenStandardOutput();
  int processed_bytes = 0;
  int processed_chunks = 0;
  while ( true ) {
   int bytesread = netin.Read(buffer, 0, buffer.Length);
   if ( bytesread <= 0 ) {
    break;
   }
   stdout.Write(buffer, 0, bytesread);
   processed_bytes += bytesread;
   processed_chunks++;
  }
  netin.Close();
  client.Close();
  server.Stop();
  Console.Error.WriteLine(
   "Received: {0} chunks of data of {1} average size", 
   processed_chunks, processed_bytes/processed_chunks
  );
 }
}
Run Code Online (Sandbox Code Playgroud)

Tom*_*zky 5

问题是由以下原因引起的:

  • 廉价的千兆交换机中的数据包缓冲区太小;
  • Windows Server 2008 文件服务中使用的拥塞避免算法不足;
  • 禁用网络适配器中的流量控制(默认情况下禁用)。

由于流量控制被禁用,Windows 使用 1Gbps 连接批量发送最大窗口大小的数据包。由于 100Mbps 客户端接收数据包的速度要慢得多,因此几乎所有窗口大小的数据都需要由交换机缓冲。由于这款廉价交换机的缓冲区非常小(规格中甚至没有说明缓冲区大小,但每个端口必须小于 64kB,因为即使禁用窗口缩放也无济于事),它不得不丢弃多余的数据包。数据包丢失导致延迟约 0.25 秒,如图所示。但是文件服务中使用的拥塞避免算法,或缺乏拥塞避免算法,并没有减小 TCP 窗口大小,因此下一批数据包并没有变小——它一次又一次地拥塞连接,导致拥塞崩溃

标准 TCP 连接(不是文件服务)必须使用不同的拥塞控制算法并且不会重复拥塞。我想通过 Windows TCP 堆栈专门处理文件服务有助于对例如 Samba 进行基准测试。

所以解决办法是:

  • 在网络适配器属性中启用流量控制。这不是一个理想的解决方案,因为任何传输到 100Mbps 客户端的文件服务也会将并发传输到 1Gbps 客户端的速度减慢到低于 100Mbps 的速度。

  • 或者将 100Mbps 客户端连接到具有更大缓冲区的企业级交换机。这是我使用过的解决方案。我有一个 10 岁的“3Com SuperStack 3 3300 SM”交换机,带有一个 1000Base-SX 光纤千兆以太网 MT-RJ 端口。我为我的 Linksys 千兆交换机和 LC/MT-RJ 多模光纤跳线购买了一个带有 LC 端口的Cisco 1000BASE-SX mini-Gbic 模块 (MGBSX1)(两者均约 150 美元),并将所有 100Mbps 客户端连接到这台 3com 交换机。我也启用了流量控制,但它不会导致没有 100Mbps 客户端连接的速度变慢。

感谢SpacemanSpiff,他的评论帮助解决了这个问题。