![在较大的 RTT 条件下,1Gbps 服务器的 TCP 吞吐量低于 100Mbps 服务器](https://linux22.com/image/611869/%E5%9C%A8%E8%BE%83%E5%A4%A7%E7%9A%84%20RTT%20%E6%9D%A1%E4%BB%B6%E4%B8%8B%EF%BC%8C1Gbps%20%E6%9C%8D%E5%8A%A1%E5%99%A8%E7%9A%84%20TCP%20%E5%90%9E%E5%90%90%E9%87%8F%E4%BD%8E%E4%BA%8E%20100Mbps%20%E6%9C%8D%E5%8A%A1%E5%99%A8.png)
我们的基础设施分布在世界各地的几个主要地点 - 新加坡、伦敦和洛杉矶。任何两个地点之间的 RTT 都超过 150 毫秒。
我们最近将所有服务器升级为使用 1Gbps 链路(从 100Mbps 升级)。我们在不同位置的服务器之间运行了一些基于 TCP 的测试,并看到了一些令人惊讶的结果。这些结果是完全可重复的。
- 洛杉矶(100Mbps)到伦敦(100Mbps):吞吐量约为 96Mbps
- 洛杉矶(100Mbps)至伦敦(1Gbps):吞吐量约为 96Mbps
- 洛杉矶(1Gbps)至伦敦(100Mbps):10-40Mbps吞吐量(不稳定)
- 洛杉矶(1Gbps)至伦敦(1Gbps):10-40Mbps吞吐量(不稳定)
- 洛杉矶(1Gbps)到洛杉矶(1Gbps):>900Mbps 吞吐量
看来每当发送方以 1Gbps 的速度运行时,长链路上的吞吐量就会受到严重影响。
之前的测试方法非常简单 - 我只是使用 cURL 从目标服务器下载 1GB 的二进制文件(因此在上述情况下,cURL 客户端在伦敦服务器上运行并从洛杉矶下载,因此洛杉矶是发送方)。当然,这是使用单个 TCP 连接。
使用 iperf 通过 UDP 重复相同的测试,问题消失了!
- 洛杉矶(100Mbps)到伦敦(100Mbps):吞吐量约为 96Mbps
- 洛杉矶(100Mbps)至伦敦(1Gbps):吞吐量约为 96Mbps
- 洛杉矶(1Gbps)至伦敦(100Mbps):吞吐量约为 96Mbps
- 洛杉矶(1Gbps)至伦敦(1Gbps):>250Mbps 吞吐量
在我看来,这直接指向一些 TCP 或 NIC/端口配置问题。
两台服务器都运行 CentOS 6.x,具有 TCP 立方。两台服务器的最大 TCP 发送和接收窗口均为 8MB,并且启用了 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
附件是一些测试用例的 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 控制。
非常感谢大家的建议!如果我能在这里提供赏金,我会的!
答案1
主要问题是 WAN 延迟大。如果还有随机数据包丢失,情况会更糟。
1、tcp_mem 也需要设置大一些,以分配更多内存。例如设置为 net.ipv4.tcp_mem = 4643328 6191104 9286656
2、你可以用wireshark/tcpdump抓包几分钟,然后分析是否有随机丢包。你也可以上传数据包文件。
3,您可以尝试调整其他 tcp 参数,例如设置 tcp_westwood=1 和 tcp_bic=1
答案2
解决了!有关详细信息,请参阅http://comments.gmane.org/gmane.linux.drivers.e1000.devel/11813
简而言之,在 TCP 指数增长阶段,1Gbps 连接的服务器似乎会发送突发流量,从而淹没一些中间设备(谁知道是什么)。这留下了两个选择:
1) 联系每个中间网络运营商,让他们配置适当的缓冲区,以满足我所需的带宽和 RTT。不太可能!2) 限制突发。
我选择将每个 TCP 流限制为最高 100Mbps。这里的数字相当随意 - 我选择 100Mbps 纯粹是因为我知道之前的路径可以处理 100Mbps,我不需要更多对于单个流量。
希望这对将来的某人有所帮助。
答案3
使用 iperf 通过 UDP 重复相同的测试,问题消失了!
洛杉矶(1Gbps)至伦敦(1Gbps):>250Mbps 吞吐量
问题似乎没有消失,大约 75% 的数据包被丢弃了?如果 TCP 一直处于慢启动状态,则您的平均带宽可能相当低。
顺便问一下,您有从伦敦到洛杉矶、从伦敦到伦敦的基准吗?