前言
有一次商戶反映訪問我們服務(wù)出現(xiàn)問題,很多超時現(xiàn)象萄涯,我們登陸服務(wù)器查詢問題時绪氛,發(fā)現(xiàn)-bash: fork: retry: 資源暫時不可用,并檢查了系統(tǒng)的tcp連接的情況涝影,發(fā)現(xiàn)closewait非常多枣察。
問題描述
現(xiàn)象有
- 商戶連接不到我們的服務(wù)
- xshell登陸服務(wù)器報 bash: fork: retry: 資源暫時不可用
- 查看系統(tǒng)tcp連接情況,發(fā)現(xiàn) closewait非常多
- 應(yīng)用進程存活燃逻,日志正常打印序目。
我準備從外到內(nèi)分析問題。網(wǎng)絡(luò)-》系統(tǒng)-》應(yīng)用伯襟。
1. 網(wǎng)絡(luò)
商戶訪問不到我們服務(wù)猿涨,這牽扯到的網(wǎng)絡(luò)測問題非常多。我聯(lián)系了網(wǎng)絡(luò)部同事姆怪,詢問這個時間段是否有商戶訪問我司網(wǎng)絡(luò)出現(xiàn)問題叛赚,網(wǎng)絡(luò)部確定沒有問題澡绩。
2. 系統(tǒng)
2.1 資源暫時不可用
出現(xiàn) bash: fork: retry: 資源暫時不可用。我查詢資料俺附,結(jié)果如下:
可能是因為資源限制肥卡,要么是系統(tǒng)自己的,要么是系統(tǒng)的用戶下昙读。資源限制可用通過 ulimit -a 查看召调。ulimit -u 會打印最大用戶進程數(shù)。如果超過了最大進程數(shù)蛮浑,fork不能創(chuàng)建新的進程唠叛,就會打印上面的錯誤。也有可能是因為交換內(nèi)存資源問題沮稚。
我就使用ulimit -u查看最大用戶進程數(shù)是1024艺沼。
2.2 tcp closewait很多
tcp closewait 是在關(guān)閉連接時,服務(wù)端的一個中間狀態(tài)蕴掏。這里先介紹下tcp連接釋放障般。
2.2.1 tcp 釋放連接過程
tpc建立連接完成,數(shù)據(jù)傳輸結(jié)束后盛杰,通信的雙方都可以釋放連接⊥斓矗現(xiàn)在A和B都處于建立連接的狀態(tài)。A的應(yīng)用進程先向其TCP發(fā)出連接釋放報文段即供,并停止再發(fā)送數(shù)據(jù)定拟,主動關(guān)閉TCP連接。A把連接釋放報文段首部FIN置1逗嫡,其序號seq=u青自,它等于前面已傳送過的數(shù)據(jù)最后一個字節(jié)的序號加1。這時A處于FIN-WAIT-1(終止等待1)驱证,等待B確認延窜。注意,TPC規(guī)定抹锄,fin報文即使不攜帶數(shù)據(jù)逆瑞,也要消耗一個序號。
B收到連接釋放報文段后即發(fā)出確認伙单,而這個報文段自己的序號是v呆万,等于B前面已經(jīng)傳送過的數(shù)據(jù)最后一個字節(jié)的序號加1,然后B就進入CLOSE-WAIT狀態(tài)车份。TCP服務(wù)器進程就應(yīng)通知高層應(yīng)用進程,因而從A到B這個方向的連接就釋放了牡彻,這是TCP處于半關(guān)閉狀態(tài)扫沼,即A已經(jīng)沒有數(shù)據(jù)要發(fā)送了出爹,但是B若發(fā)送數(shù)據(jù),A仍要接收缎除。也就是說严就,從B到A這個方向的連接并未關(guān)閉。這個狀態(tài)可能會持續(xù)一些時間
A收到來自B的確認后器罐,就進入了FIN-WAIT-2(終止等待2)梢为,等待B發(fā)出的連接釋放報文段。
若B已經(jīng)沒有要向A發(fā)送的數(shù)據(jù)轰坊,其應(yīng)用程序就通知TCP釋放連接铸董。這時B發(fā)出的連接釋放報文段必須使FIN=1。現(xiàn)假設(shè)B的序號是w(在半關(guān)閉狀態(tài)B有可能發(fā)送了一些數(shù)據(jù))肴沫。B還必須重復(fù)上次已發(fā)送過的確認號ack=u+1粟害。這時B就進入LAST-ACK(最后確認狀態(tài)),等待A的確認颤芬。
A在收到B的連接釋放報文后段后悲幅,必須對此發(fā)出確認。在確認報文段中把ACK置1站蝠,確認號ack=w+1汰具,而自己的序號是seq=u+1(根據(jù)TCP標準,前面發(fā)送過的FIN報文段要消耗一個序號)菱魔。然后進入TIME-WAIT(時間等待狀態(tài))留荔。請注意新增的TCP連接還沒有釋放掉。必須經(jīng)過時間等待計數(shù)器設(shè)置的時間2MSL后豌习,A才進入CLOSED狀態(tài)存谎。時間MSL叫做最長報文段壽命,RFC793建議設(shè)為2分鐘肥隆。但這完全是從工程上考慮既荚,對于現(xiàn)在的網(wǎng)絡(luò),MSL=2分鐘可能太長了栋艳。因此TCP允許不同的實現(xiàn)可根據(jù)具體情況使用最小的MSL值恰聘。因此從A進入TIME-WAIT狀態(tài)后,要經(jīng)過4分鐘才能進入到CLOSED的狀態(tài)吸占,才能開始建立下一個新的連接晴叨。當A撤銷相應(yīng)的傳輸控制塊TCB后,就結(jié)束了這次TCP連接矾屯。
B只要接收到了A發(fā)出的確認兼蕊,就進入CLOSED狀態(tài)。同樣件蚕,B在撤銷相應(yīng)的傳輸控制塊TCB后孙技,就結(jié)束了這次TCP連接产禾。我們注意到,B結(jié)束TCP連接的時間要比A早一些牵啦。
上述連接釋放是四次握手亚情,但也可以看作是兩個兩次握手。
2.2.2 存在大量 close-wait的原因
CLOSE-WAIT的狀態(tài)是B已經(jīng)知道A不在向B發(fā)送數(shù)據(jù)哈雏,因此B在合適的時間段內(nèi)可以讓其應(yīng)用程序通知TCP釋放連接楞件。那現(xiàn)在的問題是B的應(yīng)用程序為什么遲遲不通知TCP釋放連接,是應(yīng)用程序掛了裳瘪,還是應(yīng)用程序的資源達到臨界值土浸,不能夠做出 通知TCP釋放連接這個操作。回想到剛才提到了系統(tǒng)資源不可用盹愚,會不會是因為B的應(yīng)用程序想通知TCP釋放連接栅迄,但是由于沒有系統(tǒng)資源,而無法執(zhí)行這個操作皆怕。
我們查看了服務(wù)器的應(yīng)用部署情況毅舆,發(fā)現(xiàn)該服務(wù)器部署很多應(yīng)用,每個應(yīng)用響應(yīng)tcp請求的線程池都是100+愈腾,在業(yè)務(wù)高峰期憋活,很有可能達到最大用戶進程數(shù)1024,從而引發(fā)這一系列的問題虱黄。
應(yīng)用
應(yīng)用測設(shè)置的響應(yīng)tcp請求的線程池都是100+悦即,并且當時服務(wù)器部署應(yīng)用很多。
解決方案
- 增大系統(tǒng)用戶進程數(shù)限制
- 遷移部分不重要的應(yīng)用到其他服務(wù)器橱乱,降低服務(wù)器壓力
思考
- 為什么之前沒有暴漏出來辜梳。業(yè)務(wù)高峰期,為什么會將系統(tǒng)資源吃滿泳叠。實際的系統(tǒng)吞吐量和tps是多少作瞄。是不是我們業(yè)務(wù)處理能力較之前有降低。
- 質(zhì)量監(jiān)控體系中缺少壓測環(huán)節(jié)危纫。
后記
隨著5g的普及宗挥,網(wǎng)絡(luò)的速度得到巨大的提升,掌握網(wǎng)絡(luò)知識已經(jīng)是必不可少的技能之一种蝶。