提高Linux系統性能加速網絡應用程序

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

爲了能夠開發性能卓越的應用程序,請遵循以下技巧:

最小化報文傳輸的延時。

最小化系統調用的負載。

爲 Bandwidth Delay Product 調節 TCP 窗口。

動態優化 GNU/Linux TCP/IP 棧。

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

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

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

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

解決方案

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

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

int sock, flag, ret; /* Createnew 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'tsetsockopt(TCP_NODELAY)/n"); exit(-1); }清單 1. 爲 TCP socket 禁用 Nagle 算法

提示:使用 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 的性能取決於幾個方面的因素。兩個最重要的因素是鏈接帶寬(linkbandwidth)(報文在網絡上傳輸的速率)和 往返時間(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 可能永遠都不會利用最大的通告窗口。

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) );

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

在 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 轉發)。

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

清單 3. 調優:在 TCP/IP 棧中啓用 IP 轉發

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

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

GNU/Linux 工具

GNU/Linux 對我非常有吸引力,這是因爲其中有很多工具可以使用。儘管其中大部分都是命令行工具,但是它們都非常有用,而且非常直觀。GNU/Linux 提供了幾個工具 —— 有些是 GNU/Linux 自己提供的,有些是開放源碼軟件 —— 用於調試網絡應用程序,測量帶寬/吞吐量,以及檢查鏈接的使用情況。

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

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

netstat 確定有關網絡子系統、協議和連接的各種統計信息。

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

netlog 爲應用程序提供一些有關網絡性能方面的信息。

nettimer 爲瓶頸鍊接帶寬生成一個度量標準;可以用於協議的自動優化。

Ethereal 以一個易於使用的圖形化界面提供了 tcpump(報文跟蹤)的特性。

iperf 測量 TCP 和 UDP 的網絡性能;測量最大帶寬,並彙報延時和數據報的丟失情況。

結束語

嘗 試使用本文中介紹的技巧和技術來提高 socket 應用程序的性能,包括通過禁用 Nagle 算法來減少傳輸延時,通過設置緩衝區的大小來提高 socket 帶寬的利用,通過最小化系統調用的個數來降低系統調用的負載,以及使用可調節的內核參數來優化 Linux 的 TCP/IP 棧。

在進行優化時還需要考慮應用程序的特性。例如,您的應用程序是基於 LAN 的還是會通過Internet 進行通信?如果您的應用程序僅僅會在 LAN 內部進行操作,那麼增大 socket緩衝區的大小可能不會帶來太大的改進,不過啓用巨幀卻一定會極大地改進性能!

最後,還要使用 tcpdump 或 Ethereal 來檢查優化之後的結果。在報文級看到的變化可以幫助展示使用這些技術進行優化之後所取得的成功效果。
發佈了33 篇原創文章 · 獲贊 0 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章