跨境 TCP 傳輸優化實錄 — 使用 BBR 解決 LFN 問題


背景

公司近期開通了一條訪問美國機房的 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.

從上圖可以觀察到存在以下問題:

  1. 網絡狀況不穩定,低速率時也會偶爾會出現 TCP 重傳
  2. 傳輸速率波動較大,無法長時間維持在最佳的 105M 帶寬,導致帶寬利用率低

長肥管道 (LFN)

跨境專線具有較長的往返時間RTT與較高帶寬 Bandwidth,這類具有大管道容量 BDP = RTT * Bandwidth 的網絡我們稱之為長肥管道LFN (Long Fat Networks)

LFN 的 RTT 較長,因此一個包從發送到接收到 ACK 需要經歷的時間比普通的網絡更長。由於 TCP 滑動窗口的特性,網絡會存在較長的空閑時間,導致網絡的利用率不高。這篇文章中的動畫很好的展示了這一點,推薦觀看。因此一個簡單的方案就是:增大在途未確認數據量amount inflight,使其填滿整個管道

決定在途數據量的因素有以下幾個方面:

  • 發送端:擁塞窗口大小 cwnd 以及 發送緩沖大小
  • 接收端:接收窗口大小 rwnd 以及 接收緩沖大小

由於 cwndrwnd 大小是系統根據網絡狀況進行自適應調整的,無法無法直接干預。因此決定先嘗試調整 TCP 緩沖配置,觀察傳輸效果是否有提升。

TCP 緩沖調參

首先計算管道容量:已知專線帶寬為 1Gb,通過 ping 查看專線 RTT 約為 210ms,據此 計算專線 BDP 約為 25MB。

做過 TCP 開發的同學應該都熟悉 SO_RECVBUFSO_SENDBUF 這兩個 socekt 選項,我們可以通過這兩個參數來設置接收與發送緩沖區的大小。如果我們在建立連接 TCP 時指定了這兩個參數,那么操作系統就會使用一個固定的緩沖區大小,而不再會根據網絡進行動態調整,因此這兩個選項要慎用。

然而當指定參數過后,會發現實際的 TCP 緩沖區大小與參數有所出入。這是什么原因造成的呢?首先來看幾個重要的內核參數:

[lhop@localhost ~]$ sysctl -a  2>&1 | egrep 'core.wmem_max|core.rmem_max|ipv4.tcp_wmem|ipv4.tcp_rmem|tcp_adv_win_scale|tcp_moderate_rcvbuf'
net.core.wmem_max = 124928
net.core.rmem_max = 124928
net.ipv4.tcp_wmem = 4096	16384	4194304
net.ipv4.tcp_rmem = 4096	87380	4194304
net.ipv4.tcp_adv_win_scale = 2
net.ipv4.tcp_moderate_rcvbuf = 1
  • net.ipv4.tcp_wmemnet.ipv4.tcp_rmem 是單個 tcp socket 緩沖區的最小值min、默認值default、最大值max,單位為字節。

  • net.core.wmem_maxnet.core.rmem_max 是單個 socket 所能使用的緩沖區大小上限,單位為字節。該參數的優先級高於 tcp_wmemtcp_rmem 的最大值,調整參數時需要注意兩者的對應關系。

  • net.ipv4.tcp_moderate_rcvbuf 是否允許操作系統動態調整 tcp 緩沖。開啟后,系統會根據當前可用資源對接收緩沖進行動態調整,此時接收緩沖的大小會在 tcp_rmem 最大與最小值之間浮動。當 tcp socket 連接較多時,可以系統會酌情減少每個連接的緩存內存,避免資源耗盡。

  • net.ipv4.tcp_adv_win_scale 是單個 tcp socket 接收緩沖預留給應用的比例。tcp 的接收緩沖可以分為兩部分,一部分是用作接收窗口保存未確認報文,另一部分則是緩存未被應用程序讀取的已確認報文,因此需要預留 1/2tcp_adv_win_scale 內存空間給未讀報文。這也是 tcp_rmem 的初始默認值比 tcp_wmem 大的原因。

根據 sysctl 給出的結果,我們需要調整有:

  • net.core.wmem_max = BDP = 26214400
  • net.core.rmem_max = BDP/(1-1/2tcp_adv_win_scale) = 34952000
[lhop@localhost ~]$ cat <<EOF>> /etc/sysctl.conf
net.core.wmem_max = 26214400
net.core.rmem_max = 34952000
net.ipv4.tcp_wmem = 4096 87380 26214400
net.ipv4.tcp_rmem = 4096 87380 34952000
EOF
sysctl -p

調整后重新使用 ipref3 進行測試,發現測試結果基本上沒有變化。基本可以斷定:緩存不足不是造成 TCP 流量瓶頸的主因。

從前面的 iperf3 結果中可以看出,當出現重新傳時,擁塞窗口急劇縮小,最終導致了傳輸速度的下降。決定擁塞窗口大小的就是擁塞控制算法,因此我們將目光轉移到擁塞算法上。

擁塞控制

TCP擁塞控制算法的目的可以簡單概括為:公平效率

  • 當網絡擁塞時,TCP 連接降低傳輸速率,減少由於競爭導致的網絡資源浪費。
  • 當網絡空閑時,TCP 連接提升傳輸速率,提高通信效率。

根據實現方式不同,擁塞算法可以分為兩類:基於丟包反饋基於傳輸延時
其最終目的是找到一個適合當前網絡狀況的最佳擁塞窗口 Wbest

基於丟包反饋

基於丟包反饋的擁塞算法是目前應用最廣泛且較為成熟的算法。

Linux 系統中默認的擁塞算法 renocubic 都屬於這類:

[lhop@localhost ~]$ sysctl -a  2>&1 | egrep 'tcp_available_congestion_control|tcp_congestion_control'
net.ipv4.tcp_congestion_control = cubic
net.ipv4.tcp_available_congestion_control = cubic reno

Reno 算法

reno 是最經典的擁塞算法,其核心是基於 加性增窗/乘性減窗 AIMD 的反饋控制:當檢測到信道擁塞時,擁塞窗口會呈指數級快速減小(減少網絡丟包),然后窗口緩慢地線性增長(避免再次擁塞)。算法流程如下圖所示:

然而加性增窗的特性決定了 reno 存在一個明顯缺點:如果算法進入擁塞避免快速恢復狀這兩個階段時,每經過一個 RTT 才會將窗口大小加1,假設我們鏈路狀況好,但如果RTT很長的話,reno 需要很長時間才能達到 Wbest。實際上受限於丟包率,reno 的另一個典型問題就是還沒等 cwnd 增長到 Wbest,就已經發生丟包並削減cwnd了。

BIC 算法

為了提高 TCP 在 LFN 上的傳輸效率,后續提出了 bic 擁塞算法:

bic 也采用乘法減小的方式減小窗口,並引入一個參數 β 作為減窗因子。若發生丟包時的 cwnd 大小為 Wmax,則減小后的窗口大小為 W = β * Wmax

bic 假定 W < Wbest < Wmax,因此在恢復階段 bic 是一個變速過程:

  • 在遠離 Wmax 時,快速增大窗口,使 cwnd 盡快恢復至 Wbest(對應圖中的 Addtitive Increase 過程)
  • 在靠近 Wmax 時,緩慢增大窗口,使 cwnd 盡可能長期保持在 Wbest 附近(對應圖中的 Binary Search 過程)
  • 當到達 Wmax 時,如果仍未發生丟包,那么網絡是空閑的,應該積極地去搶占網絡資源。此時 TCP 連接會嘗試增加擁塞窗口大小,並且增加速度越來越快,直到發現新的 Wmax 為止(對應圖中的 Max Probing 過程)

CUBIC 算法

然而在 RTT 較小的非 LFN 環境中,bic 的增長策略顯得過於激進,會搶占其他其他擁塞算法的 TCP 連接資源。后來,該算法的作者提出了普適性更好的 cubic 算法。
為了減少 RTT(受物理設備影響)對算法的影響,cubic 會記錄最近一次發生網絡擁塞的時間 treduce,距離最近一次擁塞發生的時間可以表示為 t = tnow - treduce

cubic 的減窗與增窗過程可以簡化為一個的與時間 t 為自變量的窗口增長函數 W(t):

\[W(t) = C(t-K)^3 + W_{max} \\ K=\sqrt[3]{\frac{W_{max}\beta}{C}}\\ \beta = 0.2 \quad C = 0.4 \]

cubic 的窗口增長函數僅僅取決於與擁塞事件的時間間隔,從而將窗口增長獨立於網絡的時延RTT,因而能夠在多條共享瓶頸鏈路的 TCP 連接之間保持良好的RTT公平性。

cubicreno 的擁塞窗口行為比較:

cubic 保證了 TCP 盡可能的長時間保持在 Wbest,從而避免了 reno 算法漫長增窗過程導致傳輸效率低下的問題。

Bufferbloat 現象

隨着內存越來越便宜,TCP 鏈路上的網絡設備的 Buffer 傾向於配置的特別大。但這一做法對於基於丟包反饋的 TCP 擁塞算法相當不友好:

  • 發送方無法及時感知到擁塞:當數據開始在隊列排隊時,鏈路已經出現擁塞,但因為 Buffer 很大,數據包不會被丟棄,發送端根本無法感知到擁塞的發生。
  • 無效的數據包占用網絡資源:等真的出現丟包時候,重傳的包放在鏈路上還得等之前積壓在 Buffer 的數據包都送達接收端后才能被處理,對網絡網絡資源造成了浪費。
  • 接收方隊頭阻塞並丟棄數據:接收端在等待重傳的過程中,如果 Buffer 不足夠大,大量數據送達接收端后都會被丟棄,無形中增加了重傳率,極大增加傳輸延遲。

Bufferbloat 造成的高重傳率,無形中增加了網絡傳輸的延遲,並且還會導致網絡傳輸不穩定,有時候延遲很小,有的時候延遲又很大。這一表現正好符合我們之前的 iperf3 的測試結果:

  • 較長的 RTT 導致網絡非擁塞時頻繁丟包,基於丟包反饋的擁塞算法的窗口會比較小,對帶寬的利用率很低,吞吐量下降很明顯,但是實際上網絡負載並不高。
  • 在網絡擁塞但無丟包情況下算法一直加窗,丟包事件很快就發生了,乘性減窗使發送速率迅速降低,造成整個網絡的瞬時抖動性,總體呈現較大的鋸齒狀波動。

基於傳輸時延

下圖是 TCP 傳輸鏈路上某個緩存隊列,根據網絡狀況變化,隊列可能處於以下 3 種狀態之一:

  • State 1: 網絡空閑,沒有排隊的數據。網絡延遲最低
  • State 2: 網絡占滿,數據開始排隊,網絡延遲開始增大
  • State 3: 隊列溢出,網絡出現丟包

cubic 的擁塞避免策略是讓擁塞窗口盡可能保持在上一個 Wmax 附近,即 State 2 與 State 3 之間的狀態。相當於盡可能把鏈路資源(線路帶寬+中繼Buffer)占滿,也因此造成了較高的網絡延遲。

而理想狀態是維持在 State 1 和 State 2 之間,即沒有出現排隊導致延遲升高,又能完全占滿鏈路帶寬發送數據,高效且低延遲。為了實現這一點,需要使用 基於傳輸時延 的擁塞避免算法:

監控每個數據包的 RTT,先盡力增大 CWND 提高發送率:
  • 速率提高后 RTT 不變(無需排隊),則此時鏈路處於 State 1,可以繼續提高發送速率
  • 速率提高后 RTT 升高(開始排隊),說明此時鏈路從 State 1 切換到了 State 2,需要降低發送效率,使其恢復到 State 1

最優控制點

下面通過一張圖直觀地感受一下網絡擁塞的變化過程:

  • RTprop round-trip propagation time:鏈路固有的傳播時延
  • BtlBw bottleneck bandwidth:鏈路的帶寬上限
  • Amount Inflight:在途數據量
  • Delivery Rate:數據送達速率

橫向將網絡狀態分為 3 個階段:

  • app limited:性能瓶頸是應用本身(網絡空閑)
  • bandwidth limited:性能瓶頸是網絡帶寬(網絡擁塞)
  • buffer limit:性能瓶頸是中繼 buffer 容量(網絡耗盡)

縱向兩幅圖分別描繪了網絡延遲與吞吐量的變化:

  • 上圖展示了 RTT在途數據量 的之間的關系:

    • app limited:網絡空閑時,RTT 大小僅取決於 線路 RTprop
    • bandwidth limited:網絡擁塞時,RTT 大小取決於 網絡帶寬 BtlBwbuffer 數據量(BtlBw限制了隊列的消費速率)
    • buffer limit:網絡資源耗盡,開始丟包
  • 下圖展示了 送達率在途數據量 的之間的關系:

    • app limited:網絡空閑時,送達速率取決於 應用發送速率線路 RTprop(RTprop限制了ACK響應速率)
    • bandwidth limited:網絡擁塞時,送達速率僅取決於 網絡帶寬 BtlBw
    • buffer limit:網絡資源耗盡,開始丟包

注意圖中的兩個點:

  • 最優點optimum operating point is here:理想的擁塞算法應該將在途數據量控制在 BDP 附近。
  • 丟包點loss-based congestion control opreates here:基於丟包的擁塞算法將在途數據量控制在 BDP + BtlneckBufSize 附近。

在最優點附近,發送速率達到 BltBw,從而占滿鏈路帶寬,最高效的利用帶寬;在途數據量不超過鏈路的 BDP = BtlBw * RTprop,從而有最優的延遲。

當鏈路上 Buffer 較小時,最優點與丟包點十分接近,此時基於丟包的算法延遲就不會很高。當鏈路上 Buffer 很大時,基於丟包的擁塞算法就容易導致將 Buffer 占滿,就容易出現 BufferBloat。

反過來說,如果鏈路的 BtlBw 與 RTprop 已知,那么擁塞控制算法就可以根據這兩個值,計算得出最優的發送速率 BDP。這也為擁塞算法的開發提供了新的思路。

BBR 算法

bbr 是 Google 開源的擁塞算法,其目的就是為了解決基於丟包的擁塞控制算法存在的弊端:

  • 在 Buffer 較大的鏈路中,容易造成 BufferBloat,增加了傳輸延遲
  • 在 Buffer 較小的長距離鏈路中,會對突發流量造成的丟包反應過度,導致吞吐量極低

其核心理念就是建立一套探測模型,動態評估鏈路上 BtlBw 與 RTprop 的變化情況:

  • 將最近一個時間窗口 WR(一般是在幾十秒到幾分鍾之間)內監控到的 RTT 最小值作為近似的 RTprop
  • 將最近一個時間窗口 WB(一般是 10 個 RRT)內監控到的 送達率 最大值作為近似的 BtlBw

\[\hat{RT_{prop}} = min(RTT_t) \quad \forall t \in [T-W_R,T] \\ \hat{BltBw} = max(deliveryRate_t) \quad \forall t \in [T-W_B,T] \]

bbr 算法可以分為 4 個階段:

StartUp

剛啟動時, bbr以指數形式增大發送速率,每經過一個 RTT 發送速率會增大 $2/ln(2)$ 倍,從而保證能夠在 O(log(BDP)) 個 RRT 內找到 BtlBw。 當 bbr發現增大速率后,送達率沒有明顯上升時,會認為鏈路上的 Buffer 已經開始積壓,於是認為已經探測到 BtlBw。

Drain

完成 BtlBw 探測后,會將發送速率增速調整為 $ln(2)/2$,等待鏈路上的隊列積壓數據清空,避免發生丟包。 bbr會監控在途數據量 Inflight,當 Inflight 與估計的 BDP 接近時,會進入穩定狀態。

ProbeBW

經過 StartUp 和 Drain 之后,發送方進入穩定狀態進行數據的發送。由於網絡帶寬的變化要比RTT更為頻繁,因此 ProbeBW 階段也是 bbr的主要階段。

ProbeBW 狀態分為兩個周期:

  • 增周期:提高發送率到穩定期的 1.25 倍,直到出現丟包或 Inflight 達到 1.25 倍 BDP 為止。如果觀察到延遲升高且送達率不變,說明鏈路上帶寬沒有變化且產生了隊列堆積。
  • 減周期:降低發送率到穩定期的 0.75 倍,等待一個 RTprop 或 Inflight低於 BDP 為止。讓鏈路上在增周期出現堆積的隊列清空。

ProbeRTT

前面 3 個階段在運行過程中,都可能進入 ProbeRTT 階段。 如果 bbr運行了很長時間一直沒有更新 RTprop 時,會進入 ProbeRTT 狀態並試圖探測到更小 RTprop。探測完成之后再根據最新數據來確定進入 StartUp 還是 ProbeBW 階段。

cubicrenobbr 的擁塞窗口行為比較:

bbr 保證了 TCP 盡可能的長時間保持對網絡的 100% 的利用率,規避了 cubic 過分占用網絡資源引起 Bufferbloat 現象。

此外,由於 bbr 算法本身不依賴於丟包反饋,因此在高丟包率的網絡下的表現明顯優於 cubic

優化效果

經過前面的分析,發現 bbr 算法對於正好能夠解決之前 ipref3 測試中發現的問題。於是跟運維同時協商將 CentOS6 升級為高內核版本的 CentOS7,並開啟 bbr 算法:

[lhop@localhost ~]$ sysctl -a  2>&1 | egrep 'tcp_available_congestion_control|tcp_congestion_control|default_qdisc'
net.core.default_qdisc = fq
net.ipv4.tcp_available_congestion_control = reno cubic bbr
net.ipv4.tcp_congestion_control = bbr

再次使用 iperf3 進行測試,結果如下:

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   740 KBytes  6.06 Mbits/sec    0   97.6 KBytes       
[  4]   1.00-2.00   sec  4.17 MBytes  35.0 Mbits/sec    0   1.89 MBytes       
[  4]   2.00-3.00   sec  12.5 MBytes   105 Mbits/sec    0   8.76 MBytes       
[  4]   3.00-4.00   sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]   4.00-5.00   sec  11.2 MBytes  94.4 Mbits/sec    3   8.79 MBytes       
[  4]   5.00-6.00   sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]   6.00-7.00   sec  15.0 MBytes   126 Mbits/sec    0   8.79 MBytes       
[  4]   7.00-8.00   sec  12.5 MBytes   105 Mbits/sec    0   8.79 MBytes       
[  4]   8.00-9.00   sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]   9.00-10.00  sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]  10.00-11.00  sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]  11.00-12.00  sec  12.5 MBytes   105 Mbits/sec    0   8.79 MBytes       
[  4]  12.00-13.00  sec  15.0 MBytes   126 Mbits/sec    0   8.79 MBytes       
[  4]  13.00-14.00  sec  8.75 MBytes  73.4 Mbits/sec    0   8.79 MBytes       
[  4]  14.00-15.00  sec  15.0 MBytes   126 Mbits/sec    0   8.79 MBytes       
[  4]  15.00-16.00  sec  12.5 MBytes   105 Mbits/sec    0   8.79 MBytes       
[  4]  16.00-17.00  sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]  17.00-18.00  sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]  18.00-19.00  sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]  19.00-20.00  sec  12.5 MBytes   105 Mbits/sec    0   8.79 MBytes       
[  4]  20.00-21.00  sec  15.0 MBytes   126 Mbits/sec    0   8.79 MBytes       
[  4]  21.00-22.00  sec  13.8 MBytes   115 Mbits/sec    0   8.79 MBytes       
[  4]  22.00-23.00  sec  12.5 MBytes   105 Mbits/sec    0   8.79 MBytes       
[  4]  23.00-24.00  sec  11.2 MBytes  94.4 Mbits/sec    3   8.79 MBytes       
[  4]  24.00-25.00  sec  11.2 MBytes  94.4 Mbits/sec    0   7.44 MBytes       
[  4]  25.00-26.00  sec  11.2 MBytes  94.4 Mbits/sec    0   6.30 MBytes       
[  4]  26.00-27.00  sec  12.5 MBytes   105 Mbits/sec    0   6.30 MBytes       
[  4]  27.00-28.00  sec  11.2 MBytes  94.4 Mbits/sec    0   6.30 MBytes       
[  4]  28.00-29.00  sec  12.5 MBytes   105 Mbits/sec    0   6.30 MBytes       
[  4]  29.00-30.00  sec  11.2 MBytes  94.4 Mbits/sec    0   6.30 MBytes       
- - - - - - - - - - - - - - - - - - - - - - - - -
[ ID] Interval           Transfer     Bandwidth       Retr
[  4]   0.00-30.00  sec   365 MBytes   102 Mbits/sec    6             sender
[  4]   0.00-30.00  sec   364 MBytes   102 Mbits/sec                  receiver

iperf Done.

觀察測試結果發現網絡的吞吐量明顯上升,並且重傳率保持在一個較低的水平。

並且擁塞窗口變化也更穩定,不再出現之前劇烈波動的情況。

使用 10 個 socket 基本上可以跑滿整個專線,優化目標達成。

附錄

在丟包率較高的網絡中,調整 TCP 參數並不能起到很好的效果。但着這並不意味着 TCP 調參沒有意義。

某個服務在同機房內,單個 TCP 連接流量能達到 80M,但在 RTT 1.5ms 且無丟包的跨機房網絡環境上,突發流量峰值最多只能達到 60M 且不穩定。我們嘗試通過調參,將 TCP 傳輸峰值較好地穩定在 70M 左右:

調整前:

[lhop@localhost ~]$ sysctl -a  2>&1 | egrep 'net.core.[r|w]mem_|net.ipv4.tcp_[r|w]*mem|tcp_adv_win_scale'
net.core.rmem_default = 212992
net.core.wmem_default = 212992
net.core.rmem_max = 212992
net.core.wmem_max = 212992
net.ipv4.tcp_mem = 765918	1021224	1531836
net.ipv4.tcp_rmem = 4096	87380	6291456
net.ipv4.tcp_wmem = 4096	16384	4194304
net.ipv4.tcp_adv_win_scale = 1

調整后:

[lhop@localhost ~]$ sysctl -a  2>&1 | egrep 'net.core.[r|w]mem_|net.ipv4.tcp_[r|w]*mem|tcp_adv_win_scale'
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
net.core.rmem_default = 65536
net.core.wmem_default = 65536
net.ipv4.tcp_mem = 4096	87380	4194304
net.ipv4.tcp_rmem = 4096	87380	16777216
net.ipv4.tcp_wmem = 4096	87380	16777216
net.ipv4.tcp_adv_win_scale = 2

可以看到,對於大流量的 TCP 傳輸通道,調整參數仍然能顯著提升跨機房傳輸質量。

但想要獲得一組適合的參數,需要依賴大量的測試才能獲得。很多時候還是得靠業務設計來規避這類問題。


參考資料與圖片來源


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM