內核參數
本文總結Linux內核中關於TCP協議相關的內核參數含義及其相關配置。目的是指出可能在某些情況下提高TCP網絡性能的潛在內核可調參數,請確保在進行調整之前和之后進行測試以獲得可測量的定量結果。
TCP狀態轉移圖
TCP連接的任意一端,在任一時刻都處於某一狀態,當前狀態可以通過netstat命令查看。上圖中的粗虛線表示典型的服務器端的狀態轉移圖,粗實線表示典型客戶端連接的狀態轉移圖。
建立連接相關選項
TCP連接建立需要3次握手,對於服務器側來說,其維護一個內部的SYNC隊列,加大隊列長度為可以容納更多等待連接的網絡連接數:
net.ipv4.tcp_max_syn_backlog = 131072
客戶端發起SYNC連接,如果超時會進行重傳,重傳次數會由下列參數進行設置:
net.ipv4.tcp_syn_retries = 2
當服務器接收到客戶端發送的SYNC連接請求報文后,回應SYNC+ACK報文,並等待客戶端的ACK確認,如果超時會進行重傳,重傳次數由下列參數設置:
net.ipv4.tcp_synack_retries = 2
TCP進行相應次數的重連操作均失敗的情況下,將通知應用層。
預防半連接攻擊,SYN-Cookie是一種有效的機制,它的基本原理非常簡單,那就是“完成三次握手前不為任何一個連接分配任何資源”,詳細可參考RFC4987 TCP SYN Flooding Attacks and Common Mitigations,參考資料1對具體實現原理進行了講解,可參考閱讀。內核提供了參數,可以用於開啟或關閉此項功能:
net.ipv4.tcp_syncookies = 1
關閉連接相關選項
當客戶端發送FIN結束報文,並接收到服務器的ACK確認報文后,客戶端將處於FIN_WAIT_2狀態,並等待服務器發送結束報文段,才能轉移到TIME_WAIT狀態,否則它將一直停留在這個狀態。客戶端處在這個狀態時,連接處於半連接狀態,並可以繼續接收服務器端發送過來的數據。連接停留在FIN_WAIT_2狀態的情況可能發生在:客戶端執行半關閉后,未等服務器關閉連接就強行退出。此時服務器端連接由內核來接管,被稱之為孤兒連接(orphan)。Linux為了防止孤兒連接長時間存留在內核中,定義了兩個內核變量:
net.ipv4.tcp_max_orphans = 262144
net.ipv4.tcp_fin_timeout = 5
前者定義了內核接管的最大孤兒連接數,后者指定孤兒連接在內核中生存的時間。
客戶端連接在接收到服務器端端結束報文(FIN)之后,並沒有直接進入CLOSED狀態,而是轉移到TIME_WAIT狀態。在這個狀態,客戶端連接要等待2MSL(Maximum Segment Life, 報文段最大生存時間)長時間,才能完全關閉,標准RFC1122推薦為2分鍾。
net.ipv4.tcp_max_tw_buckets = 1200000
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_tw_reuse = 1
其中tcp_max_tw_buckets表示系統同時保持TIME_WAIT套接字的最大數量,如果超過這個數字,TIME_WAIT套接字將立刻被清除並打印警告信息;tcp_tw_recycle表示是否開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉;tcp_tw_reuse表示是否允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉。
高性能擴展選項
RFC7323 TCP Extensions for High Performance文檔中詳細討論了為提高性能而對TCP選項的擴展,詳細內容可以參考該文檔。
net.ipv4.tcp_sack
啟用或關閉選擇確認(Selective Acknowledgement, SACK)選項。TCP通信時,如果某個TCP報文段丟失,則TCP模塊會重傳被確認的TCP報文段后續的所有報文段。這樣已經正確傳輸的TCP報文段也可能重復發送,從而降低TCP的性能。SACK技術正是為改善這種情況而產生的,它使TCP模塊只重新發送丟失的TCP報文段,不用發送所有未被確認的TCP報文段。選擇性確認項用於在連接初始化時,表示是否支持SACK功能。
net.ipv4.tcp_timestamps
啟用或關閉時間戳選項。該選項提供了較為准確的計算通信雙方之間的回路時間(Round Trip Time)RTT的方法,從而為TCP流量控制提供重要的信息。
net.ipv4.tcp_window_scaling
啟用或關閉窗口擴大因子選項。在TCP的頭部中,接收通告窗口大小時用16位表示,故最大為65535字節,但實際上TCP模塊允許的接收通告窗口大小遠不止這個數(提高TCP通信的吞吐量)。窗口擴大因子解決了這個問題。假設TCP頭部中的接收通告窗口大小是N,窗口擴大因子(移位數)是M,則TCP報文段段實際接收通告窗口是N乘於2的M次方。M的取值范圍為0~14。
配置
確保下列選項都被配置為缺省值1,打開相關的配置選項。
sysctl net.ipv4.tcp_window_scaling
sysctl net.ipv4.tcp_timestamps
sysctl net.ipv4.tcp_sack
緩存
使用setsockopt()增加TCP max緩沖區大小(32MB):
net.core.rmem_max = 33554432
net.core.wmem_max = 33554432
要增加Linux自動調整TCP緩沖區限制要使用的最小,默認和最大字節數,1GE的最大值為16MB,10GE的最大值為32M或54M:
net.ipv4.tcp_rmem = 4096 87380 33554432
net.ipv4.tcp_wmem = 4096 65536 33554432
net.ipv4.tcp_mem參數用於配置系統對TCP內存配置:
TCP Autotuning setting. “The tcp_mem variable defines how the TCP stack should behave when it comes to memory usage. … The first value specified in the tcp_mem variable tells the kernel the low threshold. Below this point, the TCP stack do not bother at all about putting any pressure on the memory usage by different TCP sockets. … The second value tells the kernel at which point to start pressuring memory usage down. … The final value tells the kernel how many memory pages it may use maximally. If this value is reached, TCP streams and packets start getting dropped until we reach a lower memory usage again. This value includes all TCP sockets currently in use.”
tcp_mem有3個參數,單位為頁(4096字節):low, pressure, high
low:當TCP使用了低於該值的內存頁面數時,TCP不會考慮釋放內存。
pressure:當TCP使用了超過該值的內存頁面數量時,TCP試圖穩定其內存使用,進入pressure模式,當內存消耗低於low值時則退出pressure狀態。
high:允許所有tcp sockets用於排隊緩沖數據報的頁面量,當內存占用超過此值,系統拒絕分配socket,后台日志輸出“TCP: too many of orphaned sockets”。
一般情況下這些值是在系統啟動時根據系統內存數量計算得到的。 根據當前tcp_mem最大內存頁面數是1864896,當內存為(1864896*4)/1024K=7284.75M時,系統將無法為新的socket連接分配內存,即TCP連接將被拒絕。