提高 Linux 上 socket 性能
來源: ChinaUnix博客 日期: 2008.07.07 13:13 (共有0條評論) 我要評論
加速網(wǎng)絡(luò)應用程序的 4 種方法
M. Tim Jones
,資深軟件工程師,Emulex
2006 年 2 月 13 日
使用 Sockets
API,我們可以開發(fā)客戶機和服務器應用程序,它們可以在本地網(wǎng)絡(luò)上進行通信,也可以通過 Internet 在全球范圍內(nèi)進行通信。與其他 API
一樣,您可以通過一些方法使用 Sockets API,從而提高 Socket 的性能,或者限制 Socket 的性能。本文探索了 4 種使用
Sockets API 來榨取應用程序的最大性能并對 GNU/Linux® 環(huán)境進行優(yōu)化從而達到最好結(jié)果的方法。
在開發(fā) socket 應用程序時,首要任務通常是確保可靠性并滿足一些特定的需求。利用本文中給出的 4
個提示,您就可以從頭開始為實現(xiàn)最佳性能來設(shè)計并開發(fā) socket 程序。本文內(nèi)容包括對于 Sockets API 的使用、兩個可以提高性能的
socket 選項以及 GNU/Linux 優(yōu)化。
為了能夠開發(fā)性能卓越的應用程序,請遵循以下技巧:
最小化報文傳輸?shù)难訒r。
最小化系統(tǒng)調(diào)用的負載。
為 Bandwidth Delay Product 調(diào)節(jié) TCP 窗口。
動態(tài)優(yōu)化 GNU/Linux TCP/IP 棧。
技巧 1. 最小化報文傳輸?shù)难訒r
在通過 TCP socket 進行通信時,數(shù)據(jù)都拆分成了數(shù)據(jù)塊,這樣它們就可以封裝到給定連接的 TCP
payload(指 TCP 數(shù)據(jù)包中的有效負荷)中了。TCP payload
的大小取決于幾個因素(例如最大報文長度和路徑),但是這些因素在連接發(fā)起時都是已知的。為了達到最好的性能,我們的目標是使用盡可能多的可用數(shù)據(jù)來填充
每個報文。當沒有足夠的數(shù)據(jù)來填充 payload 時(也稱為最大報文段長度(maximum segment size) 或 MSS),TCP 就會采用 Nagle 算法自動將一些小的緩沖區(qū)連接到一個報文段中。這樣可以通過最小化所發(fā)送的報文的數(shù)量來提高應用程序的效率,并減輕整體的網(wǎng)絡(luò)擁塞問題。
盡管 John Nagle
的算法可以通過將這些數(shù)據(jù)連接成更大的報文來最小化所發(fā)送的報文的數(shù)量,但是有時您可能希望只發(fā)送一些較小的報文。一個簡單的例子是 telnet
程序,它讓用戶可以與遠程系統(tǒng)進行交互,這通常都是通過一個 shell
來進行的。如果用戶被要求用發(fā)送報文之前輸入的字符來填充某個報文段,那么這種方法就絕對不能滿足我們的需要。
另外一個例子是 HTTP 協(xié)議。通常,客戶機瀏覽器會產(chǎn)生一個小請求(一條 HTTP 請求消息),然后 Web 服務器就會返回一個更大的響應(Web 頁面)。
解決方案
您應該考慮的第一件事情是 Nagle 算法滿足一種需求。由于這種算法對數(shù)據(jù)進行合并,試圖構(gòu)成一個完整的 TCP 報文段,因此它會引入一些延時。但是這種算法可以最小化在線路上發(fā)送的報文的數(shù)量,因此可以最小化網(wǎng)絡(luò)擁塞的問題。
但是在需要最小化傳輸延時的情況中,Sockets API 可以提供一種解決方案。要禁用 Nagle 算法,您可以設(shè)置 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 驅(qū)動器上讀取數(shù)據(jù)時,禁用 Nagle 算法幾乎可以加倍提高讀性能。
技巧 2. 最小化系統(tǒng)調(diào)用的負載
任何時候通過一個 socket 來讀寫數(shù)據(jù)時,您都是在使用一個系統(tǒng)調(diào)用(system call)。這個調(diào)用(例如 read 或 write)跨越了用戶空間應用程序與內(nèi)核的邊界。另外,在進入內(nèi)核之前,您的調(diào)用會通過 C 庫來進入內(nèi)核中的一個通用函數(shù)(system_call())。從 system_call() 中,這個調(diào)用會進入文件系統(tǒng)層,內(nèi)核會在這兒確定正在處理的是哪種類型的設(shè)備。最后,調(diào)用會進入 socket 層,數(shù)據(jù)就是在這里進行讀取或進行排隊從而通過 socket 進行傳輸?shù)模ㄟ@涉及數(shù)據(jù)的副本)。
這個過程說明系統(tǒng)調(diào)用不僅僅是在應用程序和內(nèi)核中進行操作的,而且還要經(jīng)過應用程序和內(nèi)核中的很多層次。這個過程耗費的資源很高,因此調(diào)用次數(shù)越多,通過這個調(diào)用鏈進行的工作所需要的時間就越長,應用程序的性能也就越低。
由于我們無法避免這些系統(tǒng)調(diào)用,因此惟一的選擇是最小化使用這些調(diào)用的次數(shù)。幸運的是,我們可以對這個過程進行控制。
解決方案
在將數(shù)據(jù)寫入一個 socket
時,盡量一次寫入所有的數(shù)據(jù),而不是執(zhí)行多次寫數(shù)據(jù)的操作。對于讀操作來說,最好傳入可以支持的最大緩沖區(qū),因為如果沒有足夠多的數(shù)據(jù),內(nèi)核也會試圖填充
整個緩沖區(qū)(另外還需要保持 TCP 的通告窗口為打開狀態(tài))。這樣,您就可以最小化調(diào)用的次數(shù),并可以實現(xiàn)更好的整體性能。
技巧 3. 為 Bandwidth Delay Product 調(diào)節(jié) TCP 窗口
TCP 的性能取決于幾個方面的因素。兩個最重要的因素是鏈接帶寬(link bandwidth)(報文在網(wǎng)絡(luò)上傳輸?shù)乃俾剩┖?往返時間(round-trip time) 或 RTT(發(fā)送報文與接收到另一端的響應之間的延時)。這兩個值確定了稱為 Bandwidth Delay Product(BDP)的內(nèi)容。
給定鏈接帶寬和 RTT 之后,您就可以計算出 BDP 的值了,不過這代表什么意義呢?BDP
給出了一種簡單的方法來計算理論上最優(yōu)的 TCP socket
緩沖區(qū)大小(其中保存了排隊等待傳輸和等待應用程序接收的數(shù)據(jù))。如果緩沖區(qū)太小,那么 TCP
窗口就不能完全打開,這會對性能造成限制。如果緩沖區(qū)太大,那么寶貴的內(nèi)存資源就會造成浪費。如果您設(shè)置的緩沖區(qū)大小正好合適,那么就可以完全利用可用的
帶寬。下面我們來看一個例子:
BDP = link_bandwidth * RTT
如果應用程序是通過一個 100Mbps 的局域網(wǎng)進行通信,其 RRT 為 50 ms,那么 BDP 就是:
100MBps * 0.050 sec / 8 = 0.625MB = 625KB
注意:此處除以 8 是將位轉(zhuǎn)換成通信使用的字節(jié)。
因此,我們可以將 TCP 窗口設(shè)置為 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 提供更大的吞吐量。因此現(xiàn)在您就知道如何為您的 socket 計算最優(yōu)的緩沖區(qū)大小了。但是又該如何來改變呢?
解決方案
Sockets API 提供了幾個 socket 選項,其中兩個可以用于修改 socket 的發(fā)送和接收緩沖區(qū)的大小。清單 2 展示了如何使用 SO_SNDBUF 和 SO_RCVBUF 選項來調(diào)整發(fā)送和接收緩沖區(qū)的大小。
注意:盡管 socket 緩沖區(qū)的大小確定了通告 TCP 窗口的大小,但是 TCP 還在通告窗口內(nèi)維護了一個擁塞窗口。因此,由于這個擁塞窗口的存在,給定的 socket 可能永遠都不會利用最大的通告窗口。
清單 2. 手動設(shè)置發(fā)送和接收 socket 緩沖區(qū)大小
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 內(nèi)核中,發(fā)送緩沖區(qū)的大小是由調(diào)用用戶來定義的,但是接收緩沖區(qū)會自動加倍。您可以進行 getsockopt 調(diào)用來驗證每個緩沖區(qū)的大小。
巨幀(jumbo frame)
我們還可以考慮將包的大小從 1,500 字節(jié)修改為 9,000 字節(jié)(稱為巨幀)。在本地網(wǎng)絡(luò)中可以通過設(shè)置最大傳輸單元(Maximum Transmit Unit,MTU)來設(shè)置巨幀,這可以極大地提高性能。
就 window scaling 來說,TCP 最初可以支持最大為 64KB 的窗口(使用 16
位的值來定義窗口的大小)。采用 window scaling(RFC 1323)擴展之后,您就可以使用 32
位的值來表示窗口的大小了。GNU/Linux 中提供的 TCP/IP 棧可以支持這個選項(以及其他一些選項)。
提示:Linux 內(nèi)核還包括了自動對這些 socket 緩沖區(qū)進行優(yōu)化的能力(請參閱下面
表 1
中的 tcp_rmem 和 tcp_wmem),不過這些選項會對整個棧造成影響。如果您只需要為一個連接或一類連接調(diào)節(jié)窗口的大小,那么這種機制也許不能滿足您的需要了。
回頁首
技巧 4. 動態(tài)優(yōu)化 GNU/Linux TCP/IP 棧
標準的 GNU/Linux 發(fā)行版試圖對各種部署情況都進行優(yōu)化。這意味著標準的發(fā)行版可能并沒有對您的環(huán)境進行特殊的優(yōu)化。
解決方案
GNU/Linux 提供了很多可調(diào)節(jié)的內(nèi)核參數(shù),您可以使用這些參數(shù)為您自己的用途對操作系統(tǒng)進行動態(tài)配置。下面我們來了解一下影響 socket 性能的一些更重要的選項。
在 /proc 虛擬文件系統(tǒng)中存在一些可調(diào)節(jié)的內(nèi)核參數(shù)。這個文件系統(tǒng)中的每個文件都表示一個或多個參數(shù),它們可以通過 cat 工具進行讀取,或使用 echo 命令進行修改。清單 3 展示了如何查詢或啟用一個可調(diào)節(jié)的參數(shù)(在這種情況中,可以在 TCP/IP 棧中啟用 IP 轉(zhuǎn)發(fā))。
清單 3. 調(diào)優(yōu):在 TCP/IP 棧中啟用 IP 轉(zhuǎn)發(fā)
[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]#
表 1 給出了幾個可調(diào)節(jié)的參數(shù),它們可以幫助您提高 Linux TCP/IP 棧的性能。
表 1. TCP/IP 棧性能使用的可調(diào)節(jié)內(nèi)核參數(shù)
可調(diào)節(jié)的參數(shù)
默認值
選項說明
/proc/sys/net/core/rmem_default
"110592"
定義默認的接收窗口大小;對于更大的 BDP 來說,這個大小也應該更大。
/proc/sys/net/core/rmem_max
"110592"
定義接收窗口的最大大小;對于更大的 BDP 來說,這個大小也應該更大。
/proc/sys/net/core/wmem_default
"110592"
定義默認的發(fā)送窗口大小;對于更大的 BDP 來說,這個大小也應該更大。
/proc/sys/net/core/wmem_max
"110592"
定義發(fā)送窗口的最大大小;對于更大的 BDP 來說,這個大小也應該更大。
/proc/sys/net/ipv4/tcp_window_scaling
"1"
啟用 RFC 1323 定義的 window scaling;要支持超過 64KB 的窗口,必須啟用該值。
/proc/sys/net/ipv4/tcp_sack
"1"
啟用有選擇的應答(Selective Acknowledgment),這可以通過有選擇地應答亂序接收到的報文來提高性能(這樣可以讓發(fā)送者只發(fā)送丟失的報文段);(對于廣域網(wǎng)通信來說)這個選項應該啟用,但是這會增加對 CPU 的占用。
/proc/sys/net/ipv4/tcp_fack
"1"
啟用轉(zhuǎn)發(fā)應答(Forward Acknowledgment),這可以進行有選擇應答(SACK)從而減少擁塞情況的發(fā)生;這個選項也應該啟用。
/proc/sys/net/ipv4/tcp_timestamps
"1"
以一種比重發(fā)超時更精確的方法(請參閱 RFC 1323)來啟用對 RTT 的計算;為了實現(xiàn)更好的性能應該啟用這個選項。
/proc/sys/net/ipv4/tcp_mem
"24576 32768 49152"
確定 TCP 棧應該如何反映內(nèi)存使用;每個值的單位都是內(nèi)存頁(通常是
4KB)。第一個值是內(nèi)存使用的下限。第二個值是內(nèi)存壓力模式開始對緩沖區(qū)使用應用壓力的上限。第三個值是內(nèi)存上限。在這個層次上可以將報文丟棄,從而減
少對內(nèi)存的使用。對于較大的 BDP 可以增大這些值(但是要記住,其單位是內(nèi)存頁,而不是字節(jié))。
/proc/sys/net/ipv4/tcp_wmem
"4096 16384 131072"
為自動調(diào)優(yōu)定義每個 socket 使用的內(nèi)存。第一個值是為 socket 的發(fā)送緩沖區(qū)分配的最少字節(jié)數(shù)。第二個值是默認值(該值會被 wmem_default 覆蓋),緩沖區(qū)在系統(tǒng)負載不重的情況下可以增長到這個值。第三個值是發(fā)送緩沖區(qū)空間的最大字節(jié)數(shù)(該值會被 wmem_max 覆蓋)。
/proc/sys/net/ipv4/tcp_rmem
"4096 87380 174760"
與 tcp_wmem 類似,不過它表示的是為自動調(diào)優(yōu)所使用的接收緩沖區(qū)的值。
/proc/sys/net/ipv4/tcp_low_latency
"0"
允許 TCP/IP 棧適應在高吞吐量情況下低延時的情況;這個選項應該禁用。
/proc/sys/net/ipv4/tcp_westwood
"0"
啟用發(fā)送者端的擁塞控制算法,它可以維護對吞吐量的評估,并試圖對帶寬的整體利用情況進行優(yōu)化;對于 WAN 通信來說應該啟用這個選項。
/proc/sys/net/ipv4/tcp_bic
"1"
為快速長距離網(wǎng)絡(luò)啟用 Binary Increase Congestion;這樣可以更好地利用以 GB 速度進行操作的鏈接;對于 WAN 通信應該啟用這個選項。
與任何調(diào)優(yōu)努力一樣,最好的方法實際上就是不斷進行實驗。您的應用程序的行為、處理器的速度以及可
用內(nèi)存的多少都會影響到這些參數(shù)影響性能的方式。在某些情況中,您認為有益的操作可能恰恰是有害的(反之亦然)。因此,我們需要逐一試驗各個選項,然后檢
查每個選項的結(jié)果。換而言之,我們需要相信自己的經(jīng)驗,但是對每次修改都要進行驗證。
提示:下面介紹一個有關(guān)永久性配置的問題。注意,如果您重新啟動了 GNU/Linux 系統(tǒng),那么您所需要的任何可調(diào)節(jié)的內(nèi)核參數(shù)都會恢復成默認值。為了將您所設(shè)置的值作為這些參數(shù)的默認值,可以使用 /etc/sysctl.conf 在系統(tǒng)啟動時將這些參數(shù)配置成您所設(shè)置的值。
GNU/Linux 工具
GNU/Linux
對我非常有吸引力,這是因為其中有很多工具可以使用。盡管其中大部分都是命令行工具,但是它們都非常有用,而且非常直觀。GNU/Linux
提供了幾個工具 —— 有些是 GNU/Linux 自己提供的,有些是開放源碼軟件 ——
用于調(diào)試網(wǎng)絡(luò)應用程序,測量帶寬/吞吐量,以及檢查鏈接的使用情況。
表 2 列出最有用的幾個 GNU/Linux 工具,以及它們的用途。表 3 列出了 GNU/Linux 發(fā)行版沒有提供的幾個有用工具。有關(guān)表 3 中工具的更多信息請參閱
參考資料
。
表 2. 任何 GNU/Linux 發(fā)行版中都可以找到的工具
GNU/Linux 工具
用途
ping
這是用于檢查主機的可用性的最常用的工具,但是也可以用于識別帶寬延時產(chǎn)品計算的 RTT。
traceroute
打印某個連接到網(wǎng)絡(luò)主機所經(jīng)過的包括一系列路由器和網(wǎng)關(guān)的路徑(路由),從而確定每個 hop 之間的延時。
netstat
確定有關(guān)網(wǎng)絡(luò)子系統(tǒng)、協(xié)議和連接的各種統(tǒng)計信息。
tcpdump
顯示一個或多個連接的協(xié)議級的報文跟蹤信息;其中還包括時間信息,您可以使用這些信息來研究不同協(xié)議服務的報文時間。
表 3. GNU/Linux 發(fā)行版中沒有提供的有用性能工具
GNU/Linux 工具
用途
netlog
為應用程序提供一些有關(guān)網(wǎng)絡(luò)性能方面的信息。
nettimer
為瓶頸鏈接帶寬生成一個度量標準;可以用于協(xié)議的自動優(yōu)化。
Ethereal
以一個易于使用的圖形化界面提供了 tcpump(報文跟蹤)的特性。
iperf
測量 TCP 和 UDP 的網(wǎng)絡(luò)性能;測量最大帶寬,并匯報延時和數(shù)據(jù)報的丟失情況。
結(jié)束語
嘗試使用本文中介紹的技巧和技術(shù)來提高 socket 應用程序的性能,包括通過禁用 Nagle
算法來減少傳輸延時,通過設(shè)置緩沖區(qū)的大小來提高 socket
帶寬的利用,通過最小化系統(tǒng)調(diào)用的個數(shù)來降低系統(tǒng)調(diào)用的負載,以及使用可調(diào)節(jié)的內(nèi)核參數(shù)來優(yōu)化 Linux 的 TCP/IP 棧。
在進行優(yōu)化時還需要考慮應用程序的特性。例如,您的應用程序是基于 LAN 的還是會通過 Internet
進行通信?如果您的應用程序僅僅會在 LAN 內(nèi)部進行操作,那么增大 socket
緩沖區(qū)的大小可能不會帶來太大的改進,不過啟用巨幀卻一定會極大地改進性能!
最后,還要使用 tcpdump 或 Ethereal 來檢查優(yōu)化之后的結(jié)果。在報文級看到的變化可以幫助展示使用這些技術(shù)進行優(yōu)化之后所取得的成功效果。
參考資料
學習
您可以參閱本文在 developerWorks 全球站點上的
英文原文
。
兩部分的系列文章 “
Linux Socket 編程
”(developerWorks,2003 年 10 月和 2004 年 1 月)可以幫助您編寫 socket 應用程序。
請參閱 Pittsburgh Supercomputing Center 有關(guān)
TCP 友好的擁塞控制算法
的其他文章。
增大 MTU 可以極大地影響性能。請參閱更多有關(guān)
巨幀
及其優(yōu)點的內(nèi)容。
請參閱
ICSI Center for Internet Research
有關(guān)
選擇性應答
的文章。
查看
TCP Westwood 主頁
,了解更多有關(guān) TCP Westwood 算法的詳細內(nèi)容。
研究 North Carolina State University 的
Binary Increase Congestion TCP
。
請閱讀本文作者編寫的書
BSD Sockets Programming from a Multilanguage Perspective
(Charles River Media,2003 年 9 月),其中介紹了使用 6 種不同的語言來編寫 socket 程序的技術(shù)。
在
developerWorks Linux 專區(qū)
中可以找到為 Linux 開發(fā)人員準備的更多資源。
跟蹤
developerWorks 技術(shù)事件和 Webcasts
的最新進展。
獲得產(chǎn)品和技術(shù)
您可以將
netlog 庫
鏈接到一個應用程序,以便為性能分析提供方便。
Ethereal
是一個圖形化的網(wǎng)絡(luò)協(xié)議分析器,其中包括了用于協(xié)議分析的插件架構(gòu)。
請閱讀
National Laboratory for Applied Network Research
上更多有關(guān)
Iperf 工具
的內(nèi)容。
訂購免費的 SEK for Linux
,這有兩張 DVD,包括最新的 IBM for Linux 的試用軟件,包括 DB2®、Lotus®、Rational®、Tivoli® 和 WebSphere®。
在您的下一個開發(fā)項目中采用
IBM 試用軟件
,這可以從 developerWorks 上直接下載。
討論
通過參與
developerWorks blogs
加入 developerWorks 社區(qū)。
關(guān)于作者
Tim Jones 是一名嵌入式軟件工程師,他是 GNU/Linux Application Programming、AI Application Programming 以及 BSD Sockets Programming from a Multilanguage Perspective 等書的作者。他的工程背景非常廣泛,從同步宇宙飛船的內(nèi)核開發(fā)到嵌入式架構(gòu)設(shè)計,再到網(wǎng)絡(luò)協(xié)議的開發(fā)。Tim 是 Emulex Corp. 的一名資深軟件工程師。
本文摘自IBM網(wǎng)站
本文來自ChinaUnix博客,如果查看原文請點:http://blog.chinaunix.net/u2/64804/showart_1074891.html