將 TCP 最佳化來提高網路效能


本頁概略說明如何計算正確的設定,以便在 Google Cloud 和混合型情況下縮短 TCP 連線的延遲時間。本頁面也說明如何改善 Google Cloud中不同程序之間的連線延遲問題。

現代化的微服務架構倡導開發人員應建構只有單一責任的小型服務。而服務必須根據預期的系統穩定性,選擇利用 TCP 或 UDP 進行通訊。因此,讓微服務式系統擁有穩定、低延遲的通訊功能至關重要。

Google Cloud 提供全球網路 (代表應用程式使用者可以與全世界通訊) 來確保穩定性和低延遲。擁有全球網路,代表您建立跨越地區和區域的虛擬私有雲 (VPC) 網路。應用程式不必離開 Google Cloud 網路,就能連線到不同地區和區域中的其他應用程式。

針對傳統的資料中心環境所編寫的應用程式,在遷移到混合式雲端環境後 (也就是有些應用程式元件在公司的資料中心執行,其他的則在雲端執行),效能可能會降低。造成效能低落的原因可能有好幾個。本文著重在封包往返的延遲,以及在會透過網路的任何部分移動大量資料的應用程式中,延遲會如何影響 TCP 的效能。

問題:延遲和 TCP 行為

TCP 會使用時間區間設定機制,防止快速的傳送方超越慢速的接收方。接收方會通知傳送方要在傳送多少資料之後,等待接收方的時間區隔更新。因此,如果接收端應用程式無法接收連線資料,能夠加入佇列等待應用程式的資料量就會有限。

TCP 時間區間可讓傳送端和接受端系統上的記憶體充分發揮效用。當接收端應用程式使用資料時,就會把時間區間更新傳送給傳送方。最快速的時間區間更新會發生在一次封包往返中,因此產生下列計算 TCP 連線的大量傳輸效能限制之一的公式:

總處理量 <= 時間區間大小 / 封包往返時間 (RTT) 延遲

在 TCP 的原始設計中,這個時間區間的大小上限為 65535 個位元組 (64 KiB 減 1)。這曾經是傳送方在收到時間區間更新以便繼續傳送資料之前,能夠傳送的資料量上限。

TCP 在受到業界採用之後的變更

TCP 自受到業界採用至今,某些重要功能已有所變化:

  • 一般網路速度提高了四個數量級。
  • 系統中的一般記憶體增加了四個數量級。

第一項變更的結果,是原始的 TCP 時間區間大小會讓系統無法善用網路資源。傳送方會以網路條件許可下的最高速度,傳送一個時間區間的資料量,然後傳送方就會閒置很長一段時間,等待 TCP 時間區間更新。而第二項變更的結果,是傳送方和接收方能夠針對網路功能使用更多的記憶體,以便處理第一項變更所暴露出來的限制。

下圖說明傳送方與接收方之間的傳輸關係。

傳送方只傳送 64K 的資料,但在傳送之後花了很長的時間等待時間區間更新

傳送方因為在等待 TCP 時間區間更新,才能傳送其他資料,所以無法完全利用網路。

一次傳送更多資料

解決方案就是一次傳送更多的資料。隨著網路頻寬的增加,管線 (網路) 能夠容納更多資料,而隨著管線越來越長,我們得花費更多時間來確認對方已收到資料。這種關係稱為「頻寬延遲乘積」(BDP),而計算方式是頻寬乘以封包往返時間 (RTT),所得的值就是為了要填滿管線而須傳送的最佳位元數。公式如下:

BDP (位元數) = 頻寬 (位元數/秒) * RTT (秒)

計算所得的 BDP 將做為最佳的 TCP 時間區間大小。

舉例來說,假設您有 10 Gbps 的網路,且 RTT 為 30 毫秒。對於時間區間大小,請使用原始 TCP 時間區間大小的值 (65535 個位元組)。然而,這個值無法善用頻寬功能的優勢。以下是這個連結的可能 TCP 效能上限:

(65535 個位元組 * 8 個位元/位元組) = 頻寬 * 0.030 秒
頻寬 = (65535 個位元組 * 8 個位元/位元組) / 0.030 秒
頻寬 = 524280 位元 / 0.030 秒
頻寬 = 17476000 位元 / 秒

換句話說,根據這些值計算出的總處理量稍微大於每秒 17 Mbit,而這只是網路 10 Gbps 頻寬的一小部分。

解決方案:擴充 TCP 時間區間大小

為解決 TCP 時間區間大小的原始設計所造成的效能限制,我們擴充了 TCP 通訊協定,將時間區間大小大幅提高。時間區間的擴充功能支援高達 1,073,725,440 個位元組,或是將近 1 GiB 的時間區間。RFC 7323 將這項功能概述為 TCP 時間區間擴充選項

時間區間擴充功能會把 TCP 時間區間的定義擴充為採用 30 個位元,然後利用隱含的縮放係數,將這個 30 位元值傳入 TCP 標頭的 16 位元時間區間欄位。如要在 Linux 系統中確認這項功能是否已啟用,請使用下列指令:

sudo sysctl net.ipv4.tcp_window_scaling

所有 Google Cloud Linux 虛擬機器預設會啟用這項功能。如果傳回的值為 1,代表該選項已啟用。如果該功能已停用,您可以利用下列指令來啟用:

sudo sysctl -w net.ipv4.tcp_window_scaling=1

較大時間區間大小的總處理量

您可以利用上一個範例,展示擁有時間區間擴充功能的好處。跟之前一樣,假設您有 10 Gbps 的網路,且延遲時間為 30 毫秒,並且想利用下列公式來計算新的時間區間大小:

(連結速度 * 延遲時間) / 8 個位元 = 時間區間大小

如果您填入範例數值,就會得到以下結果:

(10 Gbps * 30 毫秒/1000 秒) / 8 位元/位元組 = 時間區間大小
(10000 Mbps * 0.030 秒) / 8 位元/位元組 = 37.5 MB

只要將 TCP 時間區間大小提高為 37 MB,就能讓 TCP 大量傳輸效能的理論上限增加到接近網路傳輸能力的值。當然,還有其他可能會限制效能的因素,包括系統負擔、平均套件大小,以及共用連結的其他流程數目,但如您所見,擴充時間區間大小可大幅改善之前有限的時間區間大小所造成的限制。

設定 Linux 可微調項目來變更 TCP 時間區間大小

在 Linux 中,TCP 時間區間大小會受到下列 sysctl(8) 可微調項目的影響:

net.core.rmem_max
net.core.wmem_max
net.ipv4.tcp_rmem
net.ipv4.tcp_wmem

如果應用程式嘗試直接控制 TCP 時間區間大小,前兩個可微調項目會將應用程式的要求限制在這幾個值中,藉此影響應用程式的 TCP 時間區間上限。後兩個可微調項目則會影響執行 Linux 自動微調功能的應用程式時間區間大小。

最佳時間區間大小的值會視您的特定情況而有所不同,但我們建議先針對您預期系統傳送資料所用的一或多個路徑設定最大的 BDP (頻寬延遲乘積)。在這種情況下,您可以按照下列步驟設定可微調項目:

  1. 確認您具備 Root 權限。
  2. 取得目前的緩衝區設定。請儲存這些設定,以免您未來想要復原變更。

    sudo sysctl -a | grep mem
    
  3. 將環境變數設為您要使用的新 TCP 時間區間大小:

    MaxExpectedPathBDP=8388608
    
  4. 針對所有連線類型,設定 OS 接收緩衝區空間上限:

    sudo sysctl -w net.core.rmem_max=$MaxExpectedPathBDP
    
  5. 針對所有連線類型,設定 OS 傳送緩衝區空間上限:

    sudo sysctl -w net.core.wmem_max=$MaxExpectedPathBDP
    
  6. 進行 TCP 接收記憶體緩衝區 (tcp_rmem) 設定:

    sudo sysctl -w net.ipv4.tcp_rmem="4096 87380 $MaxExpectedPathBDP"
    

    tcp_rmem 設定會取得三個值:

    • 可分配給 TCP 通訊端的接收緩衝區空間下限。在這個範例中,這個值為 4096 個位元組。
    • 預設的接收緩衝區空間,這會覆寫其他通訊協定所使用的 /proc/sys/net/core/rmem_default 值。在這個範例中,這個值為 87380 個位元組。
    • 可分配給 TCP 通訊端的接收緩衝區空間上限。在範例中,這個值已設為您先前設定的值 (8388608 個位元組)。
  7. 進行 TCP 傳送記憶體緩衝區 (tcp_wmem) 設定:

    sudo sysctl -w net.ipv4.tcp_wmem="4096 16384 $MaxExpectedPathBDP"
    

    tcp_wmem 設定會取得三個值:

    • 單一 TCP 通訊端可用的 TCP 傳送緩衝區空間下限。
    • 單一 TCP 通訊端可擁有的預設緩衝區空間。
    • TCP 傳送緩衝區空間上限。
  8. 設定可微調項目,已便後續連線使用您先前指定的值:

    sudo sysctl -w net.ipv4.route.flush=1
    

如要在重新啟動後繼續使用這些設定,請將您之前設定的指令附加到 /etc/sysctl.conf 檔案:

sudo bash -c 'cat << EOF >> /etc/sysctl.conf
net.core.rmem_max=8388608
net.core.wmem_max=8388608
net.ipv4.tcp_rmem=4096 87380 8388608
net.ipv4.tcp_wmem=4096 16384 8388608
net.ipv4.route.flush=1
EOF'

利用更新的時間區間大小測試 RTT

當 TCP 擁有大到足以利用 BDP 的時間區間大小時,情況就改變了,如下圖所示:

傳送方一次傳送大量資料,且花了極短的時間等待時間區間更新

您一律可以根據相關程序的可用資源,以及使用中的 TCP 演算法,調整 TCP 時間區間大小。如圖所示,時間區間擴充讓連線遠遠超出原始 TCP 規格中所定義的 65 KiB 時間區間大小。

您可以自己測試看看。首先,請確定您已經藉由設定本機電腦和遠端電腦上的可微調項目,變更這兩台機器的 TCP 時間區間大小。接著,請執行下列指令:

dd if=/dev/urandom of=sample.txt bs=1M count=1024 iflag=fullblock
scp sample.txt your_username@remotehost.com:/some/remote/directory

第一個指令會建立 1 GB 的 sample.txt 檔案,其中包含隨機資料。第二個指令會將該檔案從您的本機電腦複製到遠端機器上。

請注意,控制台上的 scp 指令輸出內容會顯示頻寬,單位為 Kbps。在結果中,您應該會看到 TCP 時間區間大小變更前後的巨大差異。

後續步驟