服務器tcp鏈接timewait過多優化及詳細分析

【背景說明】前端

在7層負載均衡上,查詢網絡狀態發現timewait太多,因而開始準備優化事宜python

總體的拓撲結構,前面是lvs作dr模式的4層負載均衡,後端使用(nginx、or haproxy)作7層負載均衡nginx

【優化效果】後端

修改前,創建鏈接的有29個,timewait的就達到了900個,以下圖所示centos

wKiom1Ty5IfhAB9FAAEI5rK5xCU064.jpg

修改後,創建鏈接的有32個,timewait的從900下降到了49個,以下圖所示安全

wKioL1Ty5aOCeWn5AAEKHpcJW_c047.jpg

【具體優化方案】服務器

注意:前端使用nat時,不適用本策略。詳細「方案詳細介紹」會說明網絡

修改7層負載所在機器,/etc/sysctl.conf負載均衡

net.ipv4.tcp_tw_reuse = 1less

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鏈接的斷開,可參考如下狀態機:

wKiom1Ty5LmjaqrnAAHQ0NimpRk554.jpg

【補充說明】

若是變動後運行命令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參數(風險很大)。

wKiom1Ty5J6j_VO0AACyl62w9hk303.jpg

【總結】

一個小小的變動,背後涉及的知識是異常多的,因此須要

一、不能隨意找個方案就使用,須要深刻理解。就像說這個A藥能夠治療B症狀,可是本質是A藥能夠治療C病因狀況下得B症狀,須要把病因搞清楚了再吃藥。就算僥倖治療好了,也不能永遠都是報這種僥倖心理。

二、對於內核參數調整,須要對每一個參數都瞭解以後再行動,不然可能會有悲劇。

三、變動的時候,須要有一個灰度過程,須要觀察一段時間後,再大面積修改。

相關文章
相關標籤/搜索