服務器tcp連接timewait過多優化及詳細分析
【背景說明】
在7層負載均衡上,查詢網絡狀態發現timewait太多,於是開始準備優化事宜
整體的拓撲結構,前面是lvs做dr模式的4層負載均衡,後端使用(nginx、or haproxy)做7層負載均衡
【優化效果】
修改前,建立連接的有29個,timewait的就達到了900個,如下圖所示
修改後,建立連接的有32個,timewait的從900降低到了49個,如下圖所示
【具體優化方案】
註意:前端使用nat時,不適用本策略。詳細“方案詳細介紹”會說明
修改7層負載所在機器,/etc/sysctl.conf
net.ipv4.tcp_tw_reuse = 1
net.ipv4.tcp_tw_recycle = 1
net.ipv4.tcp_timestamps = 1
net.ipv4.tcp_fin_timeout = 20
保存後sysctl -p生效
【方案詳細介紹】
net.ipv4.tcp_tw_reuse=1
#表示開啟重用。允許將TIME-WAIT sockets重新用於新的TCP連接,默認為0,表示關閉;該文件表示是否允許重新應用處於TIME-WAIT狀態的socket用於新的TCP連接(這個對快速重啟動某些服務,而啟動後提示端口已經被使用的情形非常有幫助)
net.ipv4.tcp_tw_recycle=1
#表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
net.ipv4.tcp_timestamps 開啟時,net.ipv4.tcp_tw_recycle開啟才能生效,原因可以參考以下代碼
- if(tcp_death_row.sysctl_tw_recycle&&tp->rx_opt.ts_recent_stamp)recycle_ok=icsk->icsk_af_ops->remember_stamp(sk);
- if(recycle_ok){
- tw->tw_timeout=rto;
- }
- else{tw->tw_timeout=TCP_TIMEWAIT_LEN;
- if(state==TCP_TIME_WAIT)
- timeo=TCP_TIMEWAIT_LEN;
- }
如果服務器身處NAT環境,安全起見,通常要禁止tcp_tw_recycle,如果nat下,開啟了tcp_tw_recycle,可能會導致部分用戶無法連接服務器的情況:在nat模式下(服務器一般會用到dnat,用戶一般會用到snat),nat設備(or服務器)會修改目的ip和源ip,以屏蔽內部信息。試想很多用戶snat出來,通過dnat訪問網站,在dnat這層,時而會產生時間戳錯亂的問題,那麽基於tcp的時間戳的tcp_tw_recycle,就會出錯。具體可參考
fc1323的擴展的說明
RFC1323TCPExtensionsforHighPerformanceMay1992 discardedwhenaconnectionisclosed. AnadditionalmechanismcouldbeaddedtotheTCP,aper-host cacheofthelasttimestampreceivedfromanyconnection. ThisvaluecouldthenbeusedinthePAWSmechanismtoreject oldduplicatesegmentsfromearlierincarnationsofthe connection,ifthetimestampclockcanbeguaranteedtohave tickedatleastoncesincetheoldconnectionwasopen.This wouldrequirethattheTIME-WAITdelayplustheRTTtogether mustbeatleastonetickofthesender‘stimestampclock. SuchanextensionisnotpartoftheproposalofthisRFC. Notethatthisisavariantonthemechanismproposedby Garlick,Rom,andPostel[Garlick77],whichrequiredeach hosttomaintainconnectionrecordscontainingthehighest sequencenumbersoneveryconnection.Usingtimestamps instead,itisonlynecessarytokeeponequantityperremote host,regardlessofthenumberofsimultaneousconnectionsto thathost.
大致意思為:tcp會記錄每個連接的時間戳,如果後續時間戳比之前記錄的時間戳小,就會認為這是錯誤的連接,拒絕這個連接。如果tcp_tw_recycle開啟,那麽這種規則就會被激活(那樣才能快速回收連接)。所以在lvs使用nat的情況下,用戶請求到lvs,LVS會修改地址數據後將請求轉發給後端服務器,但不會修改時間戳(因為nat的機制就是只修改源地址和目的地址)。在後端服務器看來,請求的源地址永遠都是LVS的地址,並且端口復用,原本不同客戶端的請求經過LVS的轉發,就可能會被認為是同一個連接,加之不同客戶端的時間可能不一致,所以就會出現時間戳錯亂的現象,於是後面的數據包就被丟棄了,具體的表現通常是是客戶端明明發送的SYN,但服務端就是不響應ACK,還可以通過下面命令來確認數據包不斷被丟棄的現象。就會出現部分用戶能連接服務器,部分用戶不能連接服務器的情況。
但在LVS使用用dr模式情況下,lvs只會修改mac和ip地址的映射關系,後端服務器看到的還是不通的用戶ip,所以激活這一規則,也不會有問題。我們這裏能使用這個策略,最大的原因也是在這裏。
net.ipv4.tcp_timestamps=1
#表示開啟TCP連接中TIME-WAIT sockets的快速回收,默認為0,表示關閉。
net.ipv4.tcp_fin_timeout = 15;這個參數是用來設置保持在FIN_WAIT_2狀態的時間。tcp4此揮手,正常的處理流程就是在FIN_WAIT_2情況下接收到FIN進入到TIME_WAIT的情況,tcp_fin_timeout參數對處於TIME_WAIT狀態的時間沒有任何影響。但是如果這個參數設的比較小,會縮短從FIN_WAIT_2到TIME_WAIT的時間,從而使連接更早地進入TIME_WAIT狀態。狀態開始的早,等待相同的時間,結束的也早,客觀上也加速了TIME_WAIT狀態套接字的清理速度。
tcp連接的斷開,可參考以下狀態機:
【補充說明】
如果變更後運行命令netstat -s|grep timestamp
發現packets rejects in established connections because of timestamp
數值增加的很快,你可能得回滾這個變更了:說明使用snat訪問你網站的人很多
因為:雖然服務器端沒有使用nat,但是客戶端使用snat的情況很多,如果後發現packets rejects in established connections because of timestamp增長很快,建議將這個方案回滾。那時,可使用修改net.ipv4.tcp_max_tw_buckets(centos默認似乎是 262144)可調整至100000。其實也說明,timeout數量不大的時候,其實可以不用調整tcp_tw_recycle參數(風險很大)。
【總結】
一個小小的變更,背後涉及的知識是異常多的,所以需要
1、不能隨意找個方案就使用,需要深入理解。就像說這個A藥可以治療B癥狀,但是本質是A藥可以治療C病因情況下得B癥狀,需要把病因搞清楚了再吃藥。就算僥幸治療好了,也不能永遠都是報這種僥幸心理。
2、對於內核參數調整,需要對每個參數都了解之後再行動,否則可能會有悲劇。
3、變更的時候,需要有一個灰度過程,需要觀察一段時間後,再大面積修改。
服務器tcp連接timewait過多優化及詳細分析