近期开通了一条访问美国机房的 1G 专线,用于提供行情数据备源,并基于 TCP 建立了一套数据传输服务。上线后发现一个严重的问题:应用程序发送队列中的数据大量积压,最终导致程序 OOM Kill,但观察监控发现专线带宽利用率只有 50% - 60%。
经过沟通,发现运维同事当时使用 iperf3 测试专线带宽使用的是 UDP 协议,于是在运维同事协助下使用 TCP 进行二次测试,发现了比较严重的问题:
在国内机房使用 iperf3 测试单个 socket 流量,在同机房内部(1G交换机)可以达到的最大带宽约为 110Mb(对照组)
在跨境专线使用 iperf3 测试单个 socket 流量,发现极不稳定
Connecting to host US_NY_VM_01, port 5001 [ 4] local HK_QW_VM_01 port 58341 connected to US_NY_VM_01 port 5001 [ ID] Interval Transfer Bandwidth Retr Cwnd [ 4] 0.00-1.00 sec 109 KBytes 892 Kbits/sec 0 42.4 KBytes [ 4] 1.00-2.00 sec 1.04 MBytes 8.75 Mbits/sec 0 324 KBytes [ 4] 2.00-3.00 sec 5.45 MBytes 45.7 Mbits/sec 0 1.52 MBytes [ 4] 3.00-4.00 sec 7.50 MBytes 62.9 Mbits/sec 6 1.88 MBytes [ 4] 4.00-5.00 sec 10.0 MBytes 83.9 Mbits/sec 0 2.10 MBytes [ 4] 5.00-6.00 sec 11.2 MBytes 94.4 Mbits/sec 0 2.27 MBytes [ 4] 6.00-7.00 sec 8.75 MBytes 73.4 Mbits/sec 0 2.38 MBytes [ 4] 7.00-8.00 sec 12.5 MBytes 105 Mbits/sec 0 2.48 MBytes [ 4] 8.00-9.00 sec 12.5 MBytes 105 Mbits/sec 0 2.56 MBytes [ 4] 9.00-10.00 sec 11.2 MBytes 94.4 Mbits/sec 0 2.62 MBytes [ 4] 10.00-11.00 sec 11.2 MBytes 94.4 Mbits/sec 0 2.65 MBytes [ 4] 11.00-12.00 sec 12.5 MBytes 105 Mbits/sec 3 1.93 MBytes [ 4] 12.00-13.00 sec 7.50 MBytes 62.9 Mbits/sec 92 1.42 MBytes [ 4] 13.00-14.00 sec 6.23 MBytes 52.3 Mbits/sec 0 1.51 MBytes [ 4] 14.00-15.00 sec 7.50 MBytes 62.9 Mbits/sec 0 1.58 MBytes [ 4] 15.00-16.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.63 MBytes [ 4] 16.00-17.00 sec 6.25 MBytes 52.4 Mbits/sec 0 1.66 MBytes [ 4] 17.00-18.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.68 MBytes [ 4] 18.00-19.00 sec 7.50 MBytes 62.9 Mbits/sec 0 1.69 MBytes [ 4] 19.00-20.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.69 MBytes [ 4] 20.00-21.00 sec 6.25 MBytes 52.4 Mbits/sec 0 1.69 MBytes [ 4] 21.00-22.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.69 MBytes [ 4] 22.00-23.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.70 MBytes [ 4] 23.00-24.00 sec 6.25 MBytes 52.4 Mbits/sec 0 1.71 MBytes [ 4] 24.00-25.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.73 MBytes [ 4] 25.00-26.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.77 MBytes [ 4] 26.00-27.00 sec 8.75 MBytes 73.4 Mbits/sec 0 1.82 MBytes [ 4] 27.00-28.00 sec 7.50 MBytes 62.9 Mbits/sec 0 1.88 MBytes [ 4] 28.00-29.00 sec 10.0 MBytes 83.9 Mbits/sec 0 1.99 MBytes [ 4] 29.00-30.00 sec 10.0 MBytes 83.9 Mbits/sec 0 2.12 MBytes - - - - - - - - - - - - - - - - - - - - - - - - - [ ID] Interval Transfer Bandwidth Retr [ 4] 0.00-30.00 sec 249 MBytes 69.6 Mbits/sec 101 sender [ 4] 0.00-30.00 sec 248 MBytes 69.3 Mbits/sec receiver iperf Done.从上图可以观察到存在以下问题:
网络状况不稳定,低速率时也会偶尔会出现 TCP 重传
传输速率波动较大,无法长时间维持在最佳的 105M 带宽,导致带宽利用率低
长肥管道 (LFN)跨境专线具有较长的往返时间RTT与较高带宽 Bandwidth,这类具有大管道容量 BDP = RTT * Bandwidth 的网络我们称之为长肥管道LFN (Long Fat Networks)。
由于 LFN 的 RTT 较长,因此一个包从发送到接收到 ACK 需要经历的时间比普通的网络更长。由于 TCP 滑动窗口的特性,网络会存在较长的空闲时间,导致网络的利用率不高。这篇文章中的动画很好的展示了这一点,推荐观看。因此一个简单的方案就是:增大在途数据未确认数据量,使其填满整个管道。
决定在途数据量的因素有以下几个方面:
发送端:拥塞窗口大小 cwnd 以及 发送缓冲大小
接收端:接收窗口大小 rwnd 以及 接收缓冲大小
由于 cwnd 和 rwnd 大小是系统根据网络状况进行自适应调整的,无法无法直接干预。因此决定先尝试调整 TCP 缓冲配置,观察传输效果是否有提升。
首先计算管道容量:已知专线带宽为 1Gb,通过 ping 查看专线 RTT 约为 210ms,据此 计算专线 BDP 约为 25MB。
做过 TCP 开发的同学应该都熟悉 SO_RECVBUF 和 SO_SENDBUF 这两个 socekt 选项,我们可以通过这两个参数来设置接收与发送缓冲区的大小。如果我们在建立连接 TCP 时指定了这两个参数,那么操作系统就不会使用一个固定的缓冲区大小,而不再会根据网络进行动态调整,因此这两个选项要慎用。