提高Linux socket效能—加速網路應用程式

來源:互聯網
上載者:User

在開發 socket 應用程式時,首要任務通常是確保可靠性並滿足一些特定的需求。利用本文中給出的 4 個提示,您就可以從頭開始為實現最佳效能來設計並開發 socket 程式。本文內容包括對於 Sockets API 的使用、兩個可以提高效能的 socket 選項以及 GNU/Linux 最佳化。

  為了能夠開發效能卓越的應用程式,請遵循以下技巧:

  • 最小化報文傳輸的延時。
  • 最小化系統調用的負載。
  • 為 Bandwidth Delay Product 調節 TCP 視窗。
  • 動態最佳化 GNU/Linux TCP/IP 棧。

  技巧 1. 最小化報文傳輸的延時

  在通過 TCP socket 進行通訊時,資料都拆分成了資料區塊,這樣它們就可以封裝到給定串連的 TCP payload(指 TCP 資料包中的有效負荷)中了。TCP payload 的大小取決於幾個因素(例如最大報文長度和路徑),但是這些因素在串連發起時都是已知的。為了達到最好的效能,我們的目標是使用儘可能多的可用資料來填充每個報文。當沒有足夠的資料來填充 payload 時(也稱為最大報文段長度(maximum segment size)或 MSS),TCP 就會採用 Nagle 演算法自動將一些小的緩衝區串連到一個報文段中。這樣可以通過最小化所發送的報文的數量來提高應用程式的效率,並減輕整體的網路擁塞問題。

  儘管 John Nagle 的演算法可以通過將這些資料連線成更大的報文來最小化所發送的報文的數量,但是有時您可能希望只發送一些較小的報文。一個簡單的例子是 telnet 程式,它讓使用者可以與遠程系統進行互動,這通常都是通過一個 shell 來進行的。如果使用者被要求用發送報文之前輸入的字元來填充某個報文段,那麼這種方法就絕對不能滿足我們的需要。

  另外一個例子是 HTTP 協議。通常,客戶機瀏覽器會產生一個小請求(一條 HTTP 要求訊息),然後 Web 服務器就會返回一個更大的響應(Web 頁面)。

  解決方案

  您應該考慮的第一件事情是 Nagle 演算法滿足一種需求。由於這種演算法對資料進行合并,試圖構成一個完整的 TCP 報文段,因此它會引入一些延時。但是這種演算法可以最小化線上路上發送的報文的數量,因此可以最小化網路擁塞的問題。

  但是在需要最小化傳輸延時的情況中,Sockets API 可以提供一種解決方案。要禁用 Nagle 演算法,您可以設定 TCP_NODELAY socket 選項,如清單 1 所示。

  清單 1. 為 TCP socket 禁用 Nagle 演算法 

int sock, flag, ret; 

/* Create new stream socket */ 
sock = socket ( AF_INET, SOCK_STREAM, 0 ); 

/* Disable the Nagle (TCP No Delay) algorithm */ 
flag = 1; 
ret = setsockopt ( sock, IPPROTO_TCP, TCP_NODELAY, (char *)&flag, sizeof(flag) );

if (ret == -1) { 
printf("Couldn't setsockopt(TCP_NODELAY)\n"); 
exit(-1); 

  提示: 使用 Samba 的實驗表明,在從 Microsoft? Windows? 伺服器上的 Samba 磁碟機上讀取資料時,禁用 Nagle 演算法幾乎可以加倍提高讀效能。

  技巧 2. 最小化系統調用的負載

  任何時候通過一個 socket 來讀寫資料時,您都是在使用一個系統調用(system call)。這個調用(例如 read 或 write )跨越了使用者空間應用程式與核心的邊界。另外,在進入核心之前,您的調用會通過 C 庫來進入核心中的一個通用函數( system_call() )。從 system_call() 中,這個調用會進入檔案系統層,核心會在這兒確定正在處理的是哪種類型的裝置。最後,調用會進入 socket 層,資料就是在這裡進行讀取或進行排隊從而通過 socket 進行傳輸的(這涉及資料的副本)。

  這個過程說明系統調用不僅僅是在應用程式和核心中進行操作的,而且還要經過應用程式和核心中的很多層次。這個過程耗費的資源很高,因此調用次數越多,通過這個調用鏈進行的工作所需要的時間就越長,應用程式的效能也就越低。

  由於我們無法避免這些系統調用,因此惟一的選擇是最小化使用這些調用的次數。幸運的是,我們可以對這個過程進行控制。

  解決方案

  在將資料寫入一個 socket 時,盡量一次寫入所有的資料,而不是執行多次寫資料的操作。對於讀操作來說,最好傳入可以支援的最大緩衝區,因為如果沒有足夠多的資料,核心也會試圖填充整個緩衝區(另外還需要保持 TCP 的通告視窗為開啟狀態)。這樣,您就可以最小化調用的次數,並可以實現更好的整體效能。

  技巧 3. 為 Bandwidth Delay Product 調節 TCP 視窗

TCP的效能取決於幾個方面的因素。兩個最重要的因素是連結頻寬(link bandwidth)(報文在網路上傳輸的速率)和往返時間(round-trip time) 或 RTT(發送報文與接收到另一端的響應之間的延時)。這兩個值確定了稱為 Bandwidth Delay Product(BDP)的內容。

  給定連結頻寬和 RTT之後,您就可以計算出 BDP 的值了,不過這代表什麼意義呢?BDP給出了一種簡單的方法來計算理論上最優的 TCP socket 緩衝區大小(其中儲存了排隊等待傳輸和等待應用程式接收的資料)。如果緩衝區太小,那麼 TCP視窗就不能完全開啟,這會對效能造成限制。如果緩衝區太大,那麼寶貴的記憶體資源就會造成浪費。如果您設定的緩衝區大小正好合適,那麼就可以完全利用可用的頻寬。下面我們來看一個例子: BDP = link_bandwidth * RTT

  如果應用程式是通過一個 100Mbps 的區域網路進行通訊,其 RRT 為 50 ms,那麼 BDP就是:100MBps * 0.050 sec / 8 = 0.625MB = 625KB

  注意:此處除以 8 是將位轉換成通訊使用的位元組。

  因此,我們可以將 TCP視窗設定為 BDP 或 1.25MB。但是在Linux 2.6 上預設的 TCP視窗大小是 110KB,這會將串連的頻寬節流設定為 2.2MBps,計算方法如下:

throughput = window_size / RTT

110KB / 0.050 = 2.2MBps

  如果使用上面計算的視窗大小,我們得到的頻寬就是 12.5MBps,計算方法如下:

625KB / 0.050 = 12.5MBps

  差別的確很大,並且可以為 socket提供更大的輸送量。因此現在您就知道如何為您的 socket計算最優的緩衝區大小了。但是又該如何來改變呢?

  解決方案

  Sockets API提供了幾個 socket 選項,其中兩個可以用於修改 socket的發送和接收緩衝區的大小。清單 2 展示了如何使用 SO_SNDBUF和 SO_RCVBUF 選項來調整發送和接收緩衝區的大小。

  注意:儘管 socket 緩衝區的大小確定了通告 TCP視窗的大小,但是 TCP 還在通告視窗內維護了一個擁塞視窗。因此,由於這個擁塞視窗的存在,給定的 socket可能永遠都不會利用最大的通告視窗。

  清單 2.手動設定發送和接收 socket 緩衝區大小 

int ret, sock, sock_buf_size;

sock = socket ( AF_INET, SOCK_STREAM, 0 ); 

sock_buf_size = BDP; 

ret = setsockopt ( sock, SOL_SOCKET, SO_SNDBUF, 
(char *)&sock_buf_size, sizeof(sock_buf_size) ); 

ret = setsockopt ( sock, SOL_SOCKET, SO_RCVBUF, 
(char *)&sock_buf_size, sizeof(sock_buf_size) );

  在 Linux 2.6核心中,發送緩衝區的大小是由調用使用者來定義的,但是接收緩衝區會自動加倍。您可以進行 getsockopt 調用來驗證每個緩衝區的大小。

  就 window scaling來說,TCP 最初可以支援最大為 64KB 的視窗(使用 16 位的值來定義視窗的大小)。採用 window scaling(RFC 1323)擴充之後,您就可以使用 32位的值來表示視窗的大小了。GNU/Linux 中提供的 TCP/IP棧可以支援這個選項(以及其他一些選項)。

  提示:Linux核心還包括了自動對這些 socket 緩衝區進行最佳化的能力(請參閱下面 表 1 中的 tcp_rmem 和tcp_wmem ),不過這些選項會對整個棧造成影響。如果您只需要為一個串連或一類串連調節視窗的大小,那麼這種機制也許不能滿足您的需要了。

  技巧 4.動態最佳化 GNU/Linux TCP/IP 棧

  標準的 GNU/Linux發行版試圖對各種部署情況都進行最佳化。這意味著標準的發行版可能並沒有對您的環境進行特殊的最佳化。

  解決方案

  GNU/Linux提供了很多可調節的核心參數,您可以使用這些參數為您自己的用途對作業系統進行動態配置。下面我們來瞭解一下影響 socket效能的一些更重要的選項。

  在 /proc虛擬檔案系統中存在一些可調節的核心參數。這個檔案系統中的每個檔案都表示一個或多個參數,它們可以通過 cat 工具進行讀取,或使用 echo 命令進行修改。清單 3 展示了如何查詢或啟用一個可調節的參數(在這種情況中,可以在 TCP/IP棧中啟用 IP 轉寄)。

  清單 3.調優:在 TCP/IP 棧中啟用 IP 轉寄

[root@camus]# cat /proc/sys/net/ipv4/ip_forward 

[root@camus]# echo "1" > /poc/sys/net/ipv4/ip_forward 
[root@camus]# cat /proc/sys/net/ipv4/ip_forward 

[root@camus]# 

表 1. TCP/IP 棧效能使用的可調節核心參數 可調節的參數 預設值 選項說明

 

 

/proc/sys/net/core/rmem_default

"110592"

定義預設的接收視窗大小;對於更大的BDP來說,這個大小也應該更大。

/proc/sys/net/core/rmem_max

"110592"

定義接收視窗的最大大小;對於更大的BDP來說,這個大小也應該更大。

/proc/sys/net/core/wmem_default

"110592"

定義預設的發送視窗大小;對於更大的BDP來說,這個大小也應該更大。

/proc/sys/net/core/wmem_max

"110592"

定義發送視窗的最大大小;對於更大的BDP來說,這個大小也應該更大。

/proc/sys/net/ipv4/tcp_window_scaling   

"1"

啟用 RFC 1323定義的 window scaling;要支援超過 64KB的視窗,必須啟用該值。

/proc/sys/net/ipv4/tcp_sack

"1"

啟用有選擇的應答(Selective Acknowledgment),這可以通過有選擇地應答亂序接收到的報文來提高效能(這樣可以讓寄件者只發送丟失的報文段);(對於廣域網路通訊來說)這個選項應該啟用,但是這會增加對 CPU的佔用。

/proc/sys/net/ipv4/tcp_fack

"1"

啟用轉寄應答(Forward Acknowledgment),這可以進行有選擇應答(SACK)從而減少擁塞情況的發生;這個選項也應該啟用。

/proc/sys/net/ipv4/tcp_timestamps

"1"

以一種比重發逾時更精確的方法(請參閱RFC 1323)來啟用對 RTT的計算;為了實現更好的效能應該啟用這個選項。

/proc/sys/net/ipv4/tcp_mem

"24576 32768 49152"

確定 TCP棧應該如何反映記憶體使用量;每個值的單位都是記憶體頁(通常是 4KB)。第一個值是記憶體使用量的下限。第二個值是記憶體壓力模式開始對緩衝區使用應用壓力的上限。第三個值是記憶體上限。在這個層次上可以將報文丟棄,從而減 少對記憶體的使用。對於較大的 BDP可以增大這些值(但是要記住,其單位是記憶體頁,而不是位元組)。

/proc/sys/net/ipv4/tcp_wmem

"4096 16384 131072"

為自動調優定義每個 socket使用的記憶體。第一個值是為 socket 的發送緩衝區分配的最少位元組數。第二個值是預設值(該值會被wmem_default覆蓋),緩衝區在系統負載不重的情況下可以增長到這個值。第三個值是發送緩衝區空間的最大位元組數(該值會被wmem_max覆蓋)。

/proc/sys/net/ipv4/tcp_rmem

"4096 87380 174760"

與 tcp_wmem類似,不過它表示的是為自動調優所使用的接收緩衝區的值。

/proc/sys/net/ipv4/tcp_low_latency

"0"

允許 TCP/IP棧適應在高輸送量情況下低延時的情況;這個選項應該禁用。

/proc/sys/net/ipv4/tcp_westwood

"0"

啟用寄件者端的擁塞控制演算法,它可以維護對輸送量的評估,並試圖對頻寬的整體利用情況進行最佳化;對於 WAN通訊來說應該啟用這個選項。

/proc/sys/net/ipv4/tcp_bic

"1"

為快速長距離網路啟用 Binary Increase Congestion;這樣可以更好地利用以 GB 速度進行操作的連結;對於 WAN通訊應該啟用這個選項。

 

  與任何調優努力一樣,最好的方法實際上就是不斷進行實驗。您的應用程式的行為、處理器的速度以及可用記憶體的多少都會影響到這些參數影響效能的方式。在某些情況中,您認為有益的操作可能恰恰是有害的(反之亦然)。因此,我們需要逐一實驗各個選項,然後檢查每個選項的結果。換而言之,我們需要相信自己的經驗,但是對每次修改都要進行驗證。

  提示:下面介紹一個有關永久性配置的問題。注意,如果您重新啟動了 GNU/Linux系統,那麼您所需要的任何可調節的核心參數都會恢複成預設值。為了將您所設定的值作為這些參數的預設值,可以使用 /etc/sysctl.conf在系統啟動時將這些參數配置成您所設定的值。

  GNU/Linux工具

  GNU/Linux對我非常有吸引力,這是因為其中有很多工具可以使用。儘管其中大部分都是命令列工具,但是它們都非常有用,而且非常直觀。GNU/Linux提供了幾個工具 —— 有些是GNU/Linux 自己提供的,有些是開放源碼軟體 —— 用於調試網路應用程式,測量頻寬/輸送量,以及檢查連結的使用方式。

  表 2列出最有用的幾個 GNU/Linux 工具,以及它們的用途。表 3列出了 GNU/Linux 發行版沒有提供的幾個有用工具。有關表 3中工具的更多資訊請參閱 參考資料 。

表 2. 任何 GNU/Linux發行版中都可以找到的工具

GNU/Linux工具

用途

 

 

ping

這是用於檢查主機的可用性的最常用的工具,但是也可以用於識別頻寬延時產品計算的RTT。

traceroute

列印某個串連到網路主機所經過的包括一系列路由器和網關的路徑(路由),從而確定每個 hop之間的延時。

netstat

確定有關網路子系統、協議和串連的各種統計資訊。

tcpdump

顯示一個或多個串連的協議級的報文跟蹤資訊;其中還包括時間資訊,您可以使用這些資訊來研究不同協議服務的報文時間。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.