Sam*_*Sam 9 networking tcp gigabit
我们的基础设施分布在世界各地的几个主要地点——新加坡、伦敦和洛杉矶。任意两个位置之间的 RTT 超过 150 毫秒。
我们最近升级了所有服务器以使用 1Gbps 链接(从 100Mbps)。我们一直在不同位置的服务器之间运行一些基于 TCP 的测试,并看到了一些令人惊讶的结果。这些结果是完全可重复的。
似乎每当发送方以 1Gbps 的速度运行时,我们的吞吐量在长链接上都会受到很大影响。
之前的测试方法非常简单 - 我只是使用 cURL 从目标服务器下载一个 1GB 的二进制文件(因此在上述情况下,cURL 客户端在伦敦服务器上运行并从 LA 下载,因此 LA 是发送方) . 这当然是使用单个 TCP 连接。
使用 iperf 在 UDP 上重复相同的测试,问题就消失了!
这直接指向了我眼中的某些 TCP 或 NIC/端口配置问题。
两台服务器都运行 CentOS 6.x,带有 TCP 立方。两者都有 8MB 的最大 TCP 发送和接收窗口,并启用了 TCP 时间戳和选择性确认。所有测试用例都使用相同的 TCP 配置。完整的 TCP 配置如下:
net.core.somaxconn = 128
net.core.xfrm_aevent_etime = 10
net.core.xfrm_aevent_rseqth = 2
net.core.xfrm_larval_drop = 1
net.core.xfrm_acq_expires = 30
net.core.wmem_max = 8388608
net.core.rmem_max = 8388608
net.core.wmem_default = 131072
net.core.rmem_default = 131072
net.core.dev_weight = 64
net.core.netdev_max_backlog = 1000
net.core.message_cost = 5
net.core.message_burst = 10
net.core.optmem_max = 20480
net.core.rps_sock_flow_entries = 0
net.core.netdev_budget = 300
net.core.warnings = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_window_scaling = 1
net.ipv4.tcp_sack = 1
net.ipv4.tcp_retrans_collapse = 1
net.ipv4.tcp_syn_retries = 5
net.ipv4.tcp_synack_retries = 5
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_max_tw_buckets = 262144
net.ipv4.tcp_keepalive_time = 7200
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_retries1 = 3
net.ipv4.tcp_retries2 = 15
net.ipv4.tcp_fin_timeout = 60
net.ipv4.tcp_syncookies = 1
net.ipv4.tcp_tw_recycle = 0
net.ipv4.tcp_abort_on_overflow = 0
net.ipv4.tcp_stdurg = 0
net.ipv4.tcp_rfc1337 = 0
net.ipv4.tcp_max_syn_backlog = 2048
net.ipv4.tcp_orphan_retries = 0
net.ipv4.tcp_fack = 1
net.ipv4.tcp_reordering = 3
net.ipv4.tcp_ecn = 2
net.ipv4.tcp_dsack = 1
net.ipv4.tcp_mem = 1528512 2038016 3057024
net.ipv4.tcp_wmem = 4096 131072 8388608
net.ipv4.tcp_rmem = 4096 131072 8388608
net.ipv4.tcp_app_win = 31
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.tcp_tw_reuse = 0
net.ipv4.tcp_frto = 2
net.ipv4.tcp_frto_response = 0
net.ipv4.tcp_low_latency = 0
net.ipv4.tcp_no_metrics_save = 0
net.ipv4.tcp_moderate_rcvbuf = 1
net.ipv4.tcp_tso_win_divisor = 3
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_abc = 0
net.ipv4.tcp_mtu_probing = 0
net.ipv4.tcp_base_mss = 512
net.ipv4.tcp_workaround_signed_windows = 0
net.ipv4.tcp_dma_copybreak = 4096
net.ipv4.tcp_slow_start_after_idle = 1
net.ipv4.tcp_available_congestion_control = cubic reno
net.ipv4.tcp_allowed_congestion_control = cubic reno
net.ipv4.tcp_max_ssthresh = 0
net.ipv4.tcp_thin_linear_timeouts = 0
net.ipv4.tcp_thin_dupack = 0
Run Code Online (Sandbox Code Playgroud)
附上一些测试用例的wireshark IO图的图像(抱歉,我还不能直接发布图像):
测试用例 1 (100Mbps -> 100Mbps) - 非常流畅的传输。捕获没有损失。- http://103.imagebam.com/download/dyNftIGh-1iCFbjfMFvBQw/25498/254976014/100m.png
测试用例 3 (1Gbps -> 100Mbps) - votaile 传输,需要很长时间才能达到任何速度 - 永远不会接近 100Mbps。然而在捕获中没有丢失/重传!- http://101.imagebam.com/download/KMYXHrLmN6l0Z4KbUYEZnA/25498/254976007/1g.png
所以总而言之,当使用 1Gbps 连接的长链接时,我们获得的 TCP 吞吐量比使用 100Mbps 连接时低得多。
我非常感谢任何 TCP 专家的指点!
谢谢!
更新(2013-05-29):
我们已经通过上面的测试用例 #4 解决了这个问题(1Gbps 发送器,1Gbps 接收器,通过大型 RTT)。我们现在可以在传输开始的几秒钟内达到 ~970Mbps。问题似乎是与托管服务提供商一起使用的开关。搬到另一个地方解决了这个问题。
然而,测试用例#3 大多仍然存在问题。如果我们有一个以 100Mbps 运行的接收器和 1Gbps 的发送器,那么我们会看到大约 2-3 分钟等待接收器达到 100Mbps(但它现在确实达到了全速率,与以前不同)。一旦我们将发送器降低到 100Mbps 或将接收器增加到 1Gbps,那么问题就会消失,我们可以在一两秒内加速到全速。
根本原因是,当然,在转移开始后不久,我们就看到了损失。然而,这与我对慢启动工作原理的理解不符。接口速度不应该对此有任何影响,因为它应该由来自接收器的 ACK 控制。
建议感激收到请!如果我能在这里提供赏金,我会的!
解决了!有关完整详细信息,请参阅http://comments.gmane.org/gmane.linux.drivers.e1000.devel/11813
简而言之,1Gbps 连接的服务器似乎会在 TCP 的指数增长阶段发送突发流量,这会淹没某些中间设备中的缓冲区(谁知道是什么)。这留下了两个选择:
1) 联系每个中间网络运营商,让他们配置适当的缓冲区,以满足我所需的带宽和 RTT。不太可能!2) 限制突发。
我选择将每个 TCP 流量限制为最多 100Mbps。这里的数字是相当任意的 - 我选择 100Mbps 纯粹是因为我知道之前的路径可以处理 100Mbps 并且我不需要更多的单个流。
希望这对将来的人有帮助。