記一次TCP TIME_WAIT引發(fā)的血案

前言

記錄線上一次故障黎棠,狀態(tài)延遲,狀態(tài)使用短連接镰绎,長(zhǎng)輪訓(xùn)的方式獲取脓斩,在每天的固定時(shí)間點(diǎn),出現(xiàn)狀態(tài)延遲畴栖,持續(xù)幾分鐘随静,然后又莫名其妙的恢復(fù)了,很是怪異吗讶,下面就來(lái)復(fù)盤(pán)下燎猛,這次問(wèn)題的定位和思考。

冰山一角

我們可以掌握的線索有 1.固定的時(shí)間點(diǎn)照皆,發(fā)生扛门。2.通過(guò)監(jiān)控可以看到,流量并不高纵寝,但是TCP TIMEWAIT一瞬間瘋漲 3.出問(wèn)題的時(shí)間點(diǎn)论寨,遠(yuǎn)程客戶的電腦(全內(nèi)網(wǎng)),ping網(wǎng)關(guān)和服務(wù)器爽茴,發(fā)現(xiàn)有大量延時(shí) 4.有同事通過(guò)jstat看葬凳,發(fā)現(xiàn)gc的次數(shù)很多,認(rèn)為gc導(dǎo)致了接口延時(shí)室奏。5.接口超時(shí)的時(shí)間點(diǎn)火焰,CPU不高,內(nèi)存不高胧沫,I/O不高昌简,系統(tǒng)負(fù)載不高,也就是未達(dá)到機(jī)器的性能瓶頸绒怨。機(jī)器配置16核64g

軟件版本:

?操作系統(tǒng) centos7.9?JDK 1.6?nginx7.7

由于纯赎,這個(gè)問(wèn)題牽涉的大客戶,很多技術(shù)人員南蹂,投入進(jìn)來(lái)一起攻破犬金,每個(gè)人的想法不一致,導(dǎo)致問(wèn)題更難以統(tǒng)一突破。

一部分人晚顷,認(rèn)為是網(wǎng)絡(luò)問(wèn)題峰伙,和某為扯了半天,沒(méi)有個(gè)所以然 一部分人该默,認(rèn)為gc太頻繁瞳氓,full gc次數(shù)太多了,所以需要gc調(diào)優(yōu) 一部分人栓袖,認(rèn)為需要在測(cè)試環(huán)境顿膨,壓測(cè),測(cè)試出系統(tǒng)瓶頸

實(shí)施的方案

拋開(kāi)以上的言論叽赊,我們回到線索上?

1恋沃、每天固定時(shí)間出現(xiàn),詢問(wèn)客戶必指,這個(gè)時(shí)間段是否是業(yè)務(wù)高峰期囊咏。回答:是?

2塔橡、從監(jiān)控來(lái)看梅割,TCP-TIMEWAIT高,那我們就要先定位到系統(tǒng)部署方案葛家。

系統(tǒng)部署方案如下 1.nginx反向代理java服務(wù)户辞。nginx監(jiān)聽(tīng)443端口 java服務(wù)監(jiān)聽(tīng)8080端口

每一次輪訓(xùn),發(fā)起http請(qǐng)求癞谒,通過(guò)nginx底燎,nginx請(qǐng)求java服務(wù)

查看8080端口的tcp端口timewait個(gè)數(shù),發(fā)現(xiàn)全是timewait弹砚,現(xiàn)在可以確定的是nginx和tcp連接出現(xiàn)了大量的timewait双仍,導(dǎo)致接口延時(shí)。

翻了運(yùn)維的調(diào)優(yōu)記錄如下:

?根據(jù)監(jiān)控看桌吃,丟棄的連接數(shù)比較多

修改后| 當(dāng)前情況| 說(shuō)明| |--|--|--| | net.core.netdev_max_backlog = 16384 |net.core.netdev_max_backlog = 1000 |系統(tǒng)建立全鏈接隊(duì)列長(zhǎng)度(TCP三次握手成功后的連接放入隊(duì)列) | | net.ipv4.tcp_max_syn_backlog = 8192|net.ipv4.tcp_max_syn_backlog = 512 |系統(tǒng)建立半鏈接隊(duì)列長(zhǎng)度(TCP三次握手過(guò)程中的連接放入隊(duì)列) | | net.core.somaxconn = 4096 |net.core.somaxconn = 128 |系統(tǒng)建立全鏈接隊(duì)列(TCP三次握手成功后的連接放入隊(duì)列 系統(tǒng)級(jí)別的 |

TCP 建立連接時(shí)要經(jīng)過(guò) 3 次握手朱沃,在客戶端向服務(wù)器發(fā)起連接時(shí),對(duì)于服務(wù)器而言茅诱,一個(gè)完整的連接建立過(guò)程逗物,服務(wù)器會(huì)經(jīng)歷 2 種 TCP 狀態(tài):SYN_REVD, ESTABELLISHED

對(duì)應(yīng)也會(huì)維護(hù)兩個(gè)隊(duì)列:

一個(gè)存放 SYN 的隊(duì)列(半連接隊(duì)列) 一個(gè)存放已經(jīng)完成連接的隊(duì)列(全連接隊(duì)列)

?ESTABLISHED列長(zhǎng)度如何計(jì)算?

如果 backlog 大于內(nèi)核參數(shù) net.core.somaxconn瑟俭,則以 net.core.somaxconn 為準(zhǔn)翎卓,

即全連接隊(duì)列長(zhǎng)度 = min(backlog, 內(nèi)核參數(shù) net.core.somaxconn),net.core.somaxconn 默認(rèn)為 128尔当。

這個(gè)很好理解莲祸,net.core.somaxconn 定義了系統(tǒng)級(jí)別的全連接隊(duì)列最大長(zhǎng)度蹂安,

backlog 只是應(yīng)用層傳入的參數(shù)椭迎,不可能超過(guò)內(nèi)核參數(shù)锐帜,所以 backlog 必須小于等于 net.core.somaxconn。

?SYN_RECV隊(duì)列長(zhǎng)度如何計(jì)算畜号?

半連接隊(duì)列長(zhǎng)度由內(nèi)核參數(shù) tcp_max_syn_backlog 決定缴阎,

當(dāng)使用 SYN Cookie 時(shí)(就是內(nèi)核參數(shù) net.ipv4.tcp_syncookies = 1),這個(gè)參數(shù)無(wú)效简软,

半連接隊(duì)列的最大長(zhǎng)度為 backlog蛮拔、內(nèi)核參數(shù) net.core.somaxconn、內(nèi)核參數(shù) tcp_max_syn_backlog 的最小值痹升。

即半連接隊(duì)列長(zhǎng)度 = min(backlog, 內(nèi)核參數(shù) net.core.somaxconn建炫,內(nèi)核參數(shù) tcp_max_syn_backlog)。

這個(gè)公式實(shí)際上規(guī)定半連接隊(duì)列長(zhǎng)度不能超過(guò)全連接隊(duì)列長(zhǎng)度疼蛾,但是tcp_syncooking默認(rèn)是啟用的肛跌,如果按上文的理解,那這個(gè)參數(shù)設(shè)置沒(méi)有多大意義

其實(shí)察郁,對(duì)于 Nginx/Tomcat 等這種 Web 服務(wù)器衍慎,都提供了 backlog 參數(shù)設(shè)置入口,當(dāng)然它們都會(huì)有默認(rèn)值皮钠,通常這個(gè)默認(rèn)值都不會(huì)太大(包括內(nèi)核默認(rèn)的半連接隊(duì)列和全連接隊(duì)列長(zhǎng)度)稳捆。如果應(yīng)用并發(fā)訪問(wèn)非常高,只增大應(yīng)用層 backlog 是沒(méi)有意義的麦轰,因?yàn)榭赡軆?nèi)核參數(shù)關(guān)于連接隊(duì)列設(shè)置的都很小乔夯,一定要綜合應(yīng)用層 backlog 和內(nèi)核參數(shù)一起看,通過(guò)公式很容易調(diào)整出正確的設(shè)置

?nginx調(diào)優(yōu) nginx到j(luò)ava建立的連接Timewait比較大款侵,優(yōu)化nginx配置驯嘱,降低握手次數(shù)。

    upstream node {
server 127.0.0.1:8080;
keepalive 10000; //新增
keepalive_timeout 65s; //新增
keepalive_requests 20000; //新增
}

?從以上記錄看喳坠,似乎都和TCP連接數(shù)有關(guān)鞠评。解決思路如下:

1.長(zhǎng)輪訓(xùn) 短連接改為websocket方案 評(píng)估:不確定因素太多,客戶要限時(shí)解決問(wèn)題壕鹉,不敢上線 2.降低tcp 連接數(shù)剃幌,根據(jù)業(yè)務(wù)拆分,降低請(qǐng)求量晾浴。3.控制timewait數(shù)量负乡,保證業(yè)務(wù)高峰期不會(huì)發(fā)生太大的抖動(dòng) 4.詢問(wèn)業(yè)務(wù)人員,請(qǐng)求會(huì)分配到一個(gè)線程的處理脊凰,并且沒(méi)有限制線程數(shù)量抖棘,所以如果請(qǐng)求量很大茂腥,應(yīng)該會(huì)有很多線程,并且cpu應(yīng)該有很高的使用量切省,而現(xiàn)在cpu的使用量很低最岗,不太正常。使用jstack打印線程情況

實(shí)施

?

找到運(yùn)維溝通朝捆,tcp的連接數(shù)設(shè)置高點(diǎn)般渡。然而被告知最多只能創(chuàng)建65535個(gè)。這個(gè)問(wèn)題我們稍后在細(xì)聊下芙盘。

?

控制TCP TIMEWAIT的數(shù)量驯用,設(shè)置參數(shù)

net.ipv4.tcp_max_tw_buckets=1024

?

jstack打印線程池,發(fā)現(xiàn)有很多線程在等待同一個(gè)鎖儒老。鎖是使用synchronized關(guān)鍵字蝴乔,鎖的是HashTable一個(gè)數(shù)組,鎖的代碼邏輯驮樊,處理比較長(zhǎng)薇正。優(yōu)化:拆分鎖的邏輯,不需要一致性的數(shù)據(jù)踢出去巩剖。

后記

一臺(tái)機(jī)器最多能創(chuàng)建多少個(gè)TCP連接铝穷?

上面的截圖中,tcp timewait的個(gè)數(shù)太多佳魔,到了65535限制曙聂,導(dǎo)致連接被重置,那為什么有這個(gè)結(jié)論呢 注意看上面的nginx配置

    upstream node {
server 127.0.0.1:8080;
keepalive 10000; //新增
keepalive_timeout 65s; //新增
keepalive_requests 20000; //新增
}

這里指定了去連接127.0.0.1的8080端口鞠鲜,那么nginx去連接java服務(wù)的時(shí)候如下:| 源ip| 源端口 |目標(biāo)ip |目標(biāo)端口 | |--|--|--|--| | 127.0.0.1|20000 |127.0.0.1 |8080 | | 127.0.0.1|20001 |127.0.0.1 |8080 | | 127.0.0.1|20002 |127.0.0.1 |8080 |

所以為什么會(huì)說(shuō)一個(gè)機(jī)器上最多65535個(gè)端口數(shù)宁脊。這個(gè)端口號(hào)16位的,可以有0~65535端口數(shù)是針對(duì)單個(gè)ip來(lái)描述的贤姆,那我們?cè)跈C(jī)器上可不是只有一個(gè)ip榆苞,所以理論上端口數(shù)是無(wú)上限的,配置nginx的時(shí)候這里需要注意上霞捡。

?端口號(hào)的上限不一定是65535 如果你有幸見(jiàn)過(guò)cannot assign requested address?那么你一定知道 Linux對(duì)可使用的范圍端口有具體限制坐漏,使用以下命令查看

cat /proc/sys/net/ipv4/ip_local_port_range 
1024 65000

?文件描述符 Linux 下一切皆文件 我們突破tcp端口限制的時(shí)候,很可能會(huì)遇到以下錯(cuò)誤too many open files

每建立一個(gè)TCP連接碧信,會(huì)分配一個(gè)文件描述符赊琳,linux 對(duì)可打開(kāi)的文件描述符的數(shù)量分別作了三個(gè)方面的限制。

系統(tǒng)級(jí):當(dāng)前系統(tǒng)可打開(kāi)的最大數(shù)量砰碴,通過(guò) cat /proc/sys/fs/file-max 查看

用戶級(jí):指定用戶可打開(kāi)的最大數(shù)量躏筏,通過(guò) cat /etc/security/limits.conf 查看

進(jìn)程級(jí):?jiǎn)蝹€(gè)進(jìn)程可打開(kāi)的最大數(shù)量,通過(guò) cat /proc/sys/fs/nr_open 查看

?C10K 每創(chuàng)建一個(gè)TCP連接呈枉,操作系統(tǒng)都需要消耗一個(gè)線程趁尼,當(dāng)我們TCP連接數(shù)過(guò)多埃碱,會(huì)導(dǎo)致線程不停的上下文切換,導(dǎo)致cpu處理時(shí)間越來(lái)越長(zhǎng)酥泞。C10K就是早期單機(jī)性能的瓶頸代名詞砚殿。所以后續(xù)有了 I/O多路復(fù)用模型。

何時(shí)進(jìn)行JVM調(diào)優(yōu)婶博?

還記得上面說(shuō)過(guò)瓮具,通過(guò)jstat看到gc很頻繁荧飞,full gc次數(shù)很多凡人,所以建議GC調(diào)優(yōu)嗎?

我們看關(guān)鍵指標(biāo)

YGC 59085 Young GC次數(shù) 
YGCT 318.142 Young 總時(shí)間 單位秒
FGC 407 Full GC 次數(shù)
FGCT 75.310 Full GC 總時(shí)間叹阔,單位為妙
我們看平均時(shí)間
年輕代平均gc時(shí)間
318.142/59085=0.0005
- 老年代平均gc時(shí)間
75.310/407=0.185

我們可以看到GC的次數(shù)很多挠轴,但是GC的平均時(shí)間并不高。

但是這并不是萬(wàn)能的

有一種情況比如Full GC發(fā)生了10次耳幢,平均值不高岸晦,但是某幾次的Full GC時(shí)間為5~6秒,所以為了更確定這個(gè)問(wèn)題睛藻,我們可以使用啟動(dòng)參數(shù)启上,查看每次GC的時(shí)間。

-verbose:gc -XX:+PrintGCTimeStamps -XX:+PrintGCDetails -Xloggc:./gc.log

查看當(dāng)天gc日志店印,F(xiàn)ull gc時(shí)間并不高冈在,可以排除,GC引起的問(wèn)題按摘。

所有的優(yōu)化包券,GC調(diào)優(yōu)應(yīng)該是最后的手段,更多的是優(yōu)化我們的代碼炫贤。

本文使用 文章同步助手 同步

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末溅固,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子兰珍,更是在濱河造成了極大的恐慌侍郭,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,284評(píng)論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件掠河,死亡現(xiàn)場(chǎng)離奇詭異亮元,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)口柳,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,115評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門(mén)苹粟,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人跃闹,你說(shuō)我怎么就攤上這事嵌削∶茫” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 164,614評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵苛秕,是天一觀的道長(zhǎng)肌访。 經(jīng)常有香客問(wèn)我,道長(zhǎng)艇劫,這世上最難降的妖魔是什么吼驶? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,671評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮店煞,結(jié)果婚禮上蟹演,老公的妹妹穿的比我還像新娘。我一直安慰自己顷蟀,他們只是感情好酒请,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,699評(píng)論 6 392
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著鸣个,像睡著了一般羞反。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上囤萤,一...
    開(kāi)封第一講書(shū)人閱讀 51,562評(píng)論 1 305
  • 那天昼窗,我揣著相機(jī)與錄音,去河邊找鬼涛舍。 笑死澄惊,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的做盅。 我是一名探鬼主播缤削,決...
    沈念sama閱讀 40,309評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼吹榴!你這毒婦竟也來(lái)了亭敢?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書(shū)人閱讀 39,223評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤图筹,失蹤者是張志新(化名)和其女友劉穎帅刀,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體远剩,經(jīng)...
    沈念sama閱讀 45,668評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡扣溺,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,859評(píng)論 3 336
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了瓜晤。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片锥余。...
    茶點(diǎn)故事閱讀 39,981評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖痢掠,靈堂內(nèi)的尸體忽然破棺而出驱犹,到底是詐尸還是另有隱情嘲恍,我是刑警寧澤,帶...
    沈念sama閱讀 35,705評(píng)論 5 347
  • 正文 年R本政府宣布雄驹,位于F島的核電站佃牛,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏医舆。R本人自食惡果不足惜俘侠,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,310評(píng)論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望蔬将。 院中可真熱鬧爷速,春花似錦、人聲如沸娃胆。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,904評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)里烦。三九已至,卻和暖如春禁谦,著一層夾襖步出監(jiān)牢的瞬間胁黑,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,023評(píng)論 1 270
  • 我被黑心中介騙來(lái)泰國(guó)打工州泊, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留丧蘸,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,146評(píng)論 3 370
  • 正文 我出身青樓遥皂,卻偏偏與公主長(zhǎng)得像力喷,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子演训,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,933評(píng)論 2 355

推薦閱讀更多精彩內(nèi)容