tcp連接是網絡編程中最基礎的概念,基於不同的使用場景,我們一般區分為“長連接”和“短連接”,
長短連接的優點和缺點這里就不詳細展開了,有心的同學直接去google查詢,本文主要關注如何解決tcp短連接的TIME_WAIT問題。
短連接最大的優點是方便,特別是腳本語言,由於執行完畢后腳本語言的進程就結束了,基本上都是用短連接。
但短連接最大的缺點是將占用大量的系統資源,例如:本地端口、socket句柄。
導致這個問題的原因其實很簡單:tcp協議層並沒有長短連接的概念,因此不管長連接還是短連接,連接建立->數據傳輸->連接關閉的流程和處理都是一樣的。
正常的TCP客戶端連接在關閉后,會進入一個TIME_WAIT的狀態,持續的時間一般在1~4分鍾,對於連接數不高的場景,1~4分鍾其實並不長,對系統也不會有什么影響,
但如果短時間內(例如1s內)進行大量的短連接,則可能出現這樣一種情況:客戶端所在的操作系統的socket端口和句柄被用盡,系統無法再發起新的連接!
舉例來說:假設每秒建立了1000個短連接(Web場景下是很常見的,例如每個請求都去訪問memcached),假設TIME_WAIT的時間是1分鍾,則1分鍾內需要建立6W個短連接,
由於TIME_WAIT時間是1分鍾,這些短連接1分鍾內都處於TIME_WAIT狀態,都不會釋放,而Linux默認的本地端口范圍配置是:net.ipv4.ip_local_port_range = 32768 61000
不到3W,因此這種情況下新的請求由於沒有本地端口就不能建立了。
可以通過如下方式來解決這個問題:
1)可以改為長連接,但代價較大,長連接太多會導致服務器性能問題,而且PHP等腳本語言,需要通過proxy之類的軟件才能實現長連接;
2)修改ipv4.ip_local_port_range,增大可用端口范圍,但只能緩解問題,不能根本解決問題;
3)客戶端程序中設置socket的SO_LINGER選項;
4)客戶端機器打開tcp_tw_recycle和tcp_timestamps選項;
5)客戶端機器打開tcp_tw_reuse和tcp_timestamps選項;
6)客戶端機器設置tcp_max_tw_buckets為一個很小的值;
在解決php連接Memcached的短連接問題過程中,我們主要驗證了3)4)5)6)幾種方法,采取的是基本功能驗證和代碼驗證,並沒有進行性能壓力測試驗證,
因此實際應用的時候需要注意觀察業務運行情況,發現丟包、斷連、無法連接等現象時,需要關注是否是因為這些選項導致的。
雖然這幾種方法都可以通過google查詢到相關信息,但這些信息大部分都是泛泛而談,而且絕大部分都是人雲亦雲,沒有很大參考價值。
我們在定位和處理這些問題過程中,遇到一些疑惑和困難,也花費了一些時間去定位和解決,以下就是相關的經驗總結。