最近準(zhǔn)備自己動(dòng)手部署測試kubernetes集群,注備寫一個(gè) hands on 的手冊贯涎。突發(fā)奇想將 centos 原有的內(nèi)核從3.10更新到了4.14版本,并執(zhí)行一些常規(guī)的優(yōu)化操作。沒有想到在修改了 sysctl.conf 里面的一些參數(shù)荧止,希望能對新的 kubernetes 性能有所幫助。
當(dāng)我在其中一臺(tái) node 節(jié)點(diǎn) 執(zhí)行 sysctl -p 的時(shí)候發(fā)現(xiàn)如下錯(cuò)誤:
sysctl: cannot stat /proc/sys/net/ipv4/tcp_tw_recycle: No such file or directory
納尼阶剑,沒有tcp_tw_recycle這個(gè)參數(shù)了跃巡? 怎么回事。牧愁。素邪。
net.ipv4.tcp_tw_reuse = 0? 表示開啟重用。允許將TIME-WAIT sockets重新用于新的TCP連接猪半,默認(rèn)為0兔朦,表示關(guān)閉
net.ipv4.tcp_tw_recycle = 0? 表示開啟TCP連接中TIME-WAIT sockets的快速回收偷线,默認(rèn)為0,表示關(guān)閉
net.ipv4.tcp_fin_timeout = 60? 表示如果套接字由本端要求關(guān)閉沽甥,這個(gè)參數(shù)決定了它保持在FIN-WAIT-2狀態(tài)的時(shí)間(可改為30声邦,一般來說FIN-WAIT-2的連接也極少)
好像上面3個(gè)內(nèi)核調(diào)整參數(shù),都是很多 Linux 運(yùn)維工程師的標(biāo)配了摆舟,怎么我一升級內(nèi)核就不行了翔忽? 自己狠下心來好好去的看了 kernel 的文檔,Linux 從4.12內(nèi)核版本開始移除了 tcp_tw_recycle 這個(gè)參數(shù)盏檐。 好嘛歇式,小弟我手賤賤,升級到了4.14現(xiàn)在沒有這個(gè)參數(shù)胡野,只能硬著頭皮去掉材失。
但是這個(gè)參數(shù)對 linux 系統(tǒng)回收大量 tcp timeout wait 有幫助,tcp_tw_recycle通常會(huì)和tcp_tw_reuse參數(shù)一起使用硫豆,用于解決服務(wù)器TIME_WAIT狀態(tài)連接過多的問題龙巨。 但是 kernel 為什么又要取消掉呢??
簡單來說就是熊响,Linux會(huì)丟棄所有來自遠(yuǎn)端的timestramp時(shí)間戳小于上次記錄的時(shí)間戳(由同一個(gè)遠(yuǎn)端發(fā)送的)的任何數(shù)據(jù)包旨别。也就是說要使用該選項(xiàng),則必須保證數(shù)據(jù)包的時(shí)間戳是單調(diào)遞增的汗茄。同時(shí)從4.10內(nèi)核開始秸弛,官方修改了時(shí)間戳的生成機(jī)制,所以導(dǎo)致?tcp_tw_recycle 和新時(shí)間戳機(jī)制工作在一起不那么友好洪碳,同時(shí)?tcp_tw_recycle 幫助也不那么的大递览。
此處的時(shí)間戳并不是我們通常意義上面的絕對時(shí)間,而是一個(gè)相對時(shí)間瞳腌。很多情況下绞铃,我們是沒法保證時(shí)間戳單調(diào)遞增的,比如業(yè)務(wù)服務(wù)器之前部署了NAT嫂侍,LVS等情況儿捧。相信很多小伙伴上班的公司大概率實(shí)用實(shí)用各種公有云延窜,而各種公有云的 LVS 網(wǎng)關(guān)都是 FullNAT 曼尊。所以可能導(dǎo)致在高并發(fā)的情況下,莫名其妙的 TCP 建聯(lián)不是那么順暢或者丟連接损俭。
而這也是很多優(yōu)化文章中并沒有提及的一點(diǎn)痹栖,大部分文章都是簡單的推薦將net.ipv4.tcp_tw_recycle設(shè)置為1亿汞,卻忽略了該選項(xiàng)的局限性瞭空,最終造成嚴(yán)重的后果(比如我們之前就遇到過部署在nat后端的業(yè)務(wù)網(wǎng)站有的用戶訪問沒有問題揪阿,但有的用戶就是打不開網(wǎng)頁)疗我。
想深究原因? 讓我們一起來看看到底為什么南捂,一起往底層看看吴裤。。溺健。麦牺。
這次我們要關(guān)注的不是上半部分的 TCP 新建連接,而是下半部分的 TCP 斷開連接鞭缭。 別人老談 TCP 3次握手剖膳,我就來談 TCP 4次“揮手告別”。
在說 TCP 斷開連接之前岭辣,我想先插入點(diǎn)內(nèi)容吱晒。 就是為什么要在 TCP 傳輸種引入 TIMEWAIT 這個(gè)概念。
第一個(gè)作用就是避免新連接接收到重復(fù)的數(shù)據(jù)包沦童,由于使用了時(shí)間戳仑濒,重復(fù)的數(shù)據(jù)包會(huì)因?yàn)闀r(shí)間戳過期被丟棄。
第二個(gè)作用是確保遠(yuǎn)端不是處于LAST-ACK狀態(tài)偷遗,如果ACK包丟失墩瞳,遠(yuǎn)端沒有成功獲取到最后一個(gè)ACK包,則會(huì)重發(fā)FIN包氏豌。直到:
1.放棄(連接斷開)
2.收到ACK包
3.收到RST包
如果FIN包被及時(shí)接收到喉酌,并且本地端仍然是TIME-WAIT狀態(tài),那ACK包會(huì)被發(fā)送泵喘,此時(shí)就是正常的四次揮手流程瞭吃。
如果TIME-WAIT的條目已經(jīng)被新連接所復(fù)用,則新連接的SYN包會(huì)被忽略掉涣旨,并且會(huì)收到FIN包的重傳歪架,本地會(huì)回復(fù)一個(gè)RST包(因?yàn)榇藭r(shí)本地連接為SYN-SENT狀態(tài)),這會(huì)讓遠(yuǎn)程端跳出LAST-ACK狀態(tài)霹陡,最初的SYN包也會(huì)在1秒后重新發(fā)送和蚪,然后完成連接的建立,整個(gè)過程不會(huì)中斷烹棉,只是有輕微的延遲攒霹。流程如下:
BB 嘮叨了這么半天,我們回到正題浆洗,看看下面的一個(gè)完整 TCP 斷開連接的過程:
TIME_WAIT永遠(yuǎn)是出現(xiàn)在主動(dòng)發(fā)送斷開連接請求的一方(下文中我們稱之為客戶)催束,劃重點(diǎn):這一點(diǎn)面試的時(shí)候經(jīng)常會(huì)被問到。 嘿嘿伏社,這個(gè)可以做為面試官的殺手锏抠刺,上圖邏輯保證好多人不知道塔淤。(我咋這么壞呢。速妖。高蜂。)
客戶在收到服務(wù)器端發(fā)送的FIN(表示"我們也要斷開連接了")后發(fā)送ACK報(bào)文,并且進(jìn)入TIME_WAIT狀態(tài)罕容,等待2MSL(MaximumSegmentLifetime 最大報(bào)文生存時(shí)間)备恤。對于Linux,字段為TCP_TIMEWAIT_LEN硬編碼為30秒锦秒,對于Windows為2分鐘(可自行調(diào)整)露泊。
說到?TCP_TIMEWAIT_LEN 這個(gè)我就多啰嗦幾句,很多資深運(yùn)維小伙伴旅择,在早起為了加快 tcp timeout 的回收時(shí)間滤淳,經(jīng)常會(huì)修改這個(gè)內(nèi)核頭文件中定義的宏數(shù)據(jù),然后重編譯內(nèi)核砌左。 說實(shí)話確實(shí)有一些用處脖咐,至少早起阿里很多基礎(chǔ)平臺(tái)的運(yùn)維就是這么干的,至于其他大廠不得而知汇歹,這個(gè)仁者見仁吧屁擅。
客戶端 TCP連接 “揮手告別”,為什么客戶端不直接進(jìn)入CLOSED狀態(tài)产弹,而是要在TIME_WAIT等待那么久呢派歌,我猜主要是基于如下考慮:
1. 確保遠(yuǎn)程端(服務(wù)端)能夠正確處于關(guān)閉狀態(tài)
? ? 確保 TCP 連接在各種情況下,都能正常的關(guān)閉痰哨。我們的網(wǎng)絡(luò) IP 協(xié)議本身就是盡力而為的傳輸胶果,所有傳輸?shù)目煽啃远际强?TCP 協(xié)議棧來完成的。假如當(dāng) TCP 自身傳輸信令的過程中也出現(xiàn)了一些異常呢斤斧? 是不是我們 TCP 傳輸協(xié)議本身需要一定的容錯(cuò)機(jī)制早抠。
2.?防止上一次連接中的包,又重新收到撬讽,影響新連接
又回到了上面說到的 IP 網(wǎng)絡(luò)本身盡力而為的傳輸機(jī)制,并不保證數(shù)據(jù)包在底層傳輸?shù)臅r(shí)候游昼,接收方收到的數(shù)據(jù)包的數(shù)據(jù)順序不一定是按照發(fā)送方的順序甘苍,再加上數(shù)據(jù)傳輸延遲,就讓上圖的問題發(fā)生的情況成為了大概率事件烘豌。
說了這么多载庭,TCP TIMEWAIT 在一個(gè)服務(wù)器上大量堆積有什么危害嗎??
1.占用連接資源
TIME_WAIT占用的1分鐘時(shí)間內(nèi),相同四元組(源地址囚聚,源端口靖榕,目標(biāo)地址,目標(biāo)端口)的連接無法創(chuàng)建靡挥,通常一個(gè)ip可以開啟的端口為net.ipv4.ip_local_port_range指定的32768-61000序矩,如果TIME_WAIT狀態(tài)過多鸯绿,會(huì)導(dǎo)致無法創(chuàng)建新連接跋破。
2.占用內(nèi)存資源
這個(gè)占用資源并不是很多,可以不用擔(dān)心瓶蝴。 (現(xiàn)在服務(wù)器內(nèi)存真心多毒返,不怕。 如果你實(shí)用的虛擬機(jī)舷手,而且還是短鏈接巨多拧簸,內(nèi)存分配不那么充足的情況下,還要節(jié)省成本男窟, 那就要當(dāng)心咯)
那我們?nèi)绾谓鉀Q這樣的問題:
1.修改為長連接盆赤,代價(jià)較大,長連接對服務(wù)器性能有影響歉眷。
2.增加可用端口范圍(修改net.ipv4.ip_local_port_range); 增加服務(wù)端口牺六,比如采用80,81等多個(gè)端口提供服務(wù); 增加客戶端ip(適用于負(fù)載均衡汗捡,比如nginx淑际,采用多個(gè)ip連接后端服務(wù)器); 增加服務(wù)端ip; 這些方式治標(biāo)不治本,只能緩解問題扇住。
3.將net.ipv4.tcp_max_tw_buckets設(shè)置為很小的值(默認(rèn)是18000). 當(dāng)TIME_WAIT連接數(shù)量達(dá)到給定的值時(shí)春缕,所有的TIME_WAIT連接會(huì)被立刻清除,并打印警告信息艘蹋。但這種粗暴的清理掉所有的連接锄贼,意味著有些連接并沒有成功等待2MSL,就會(huì)造成通訊異常女阀。
4.修改TCP_TIMEWAIT_LEN值咱娶,減少等待時(shí)間,但這個(gè)需要修改內(nèi)核并重新編譯强品。(這個(gè)之前提過膘侮,有某個(gè)大廠的小伙伴之前這么做的,有效果的榛,但是有其他負(fù)面情況琼了,我沒有做完整的評估,自己斟酌實(shí)用)
5.打開tcp_tw_recycle和tcp_timestamps選項(xiàng)。
6.打開tcp_tw_reuse和tcp_timestamps選項(xiàng)雕薪。
注意昧诱,注意,注意所袁,重要的事情說三遍盏档。 5和6之間只能選擇一個(gè),不能同時(shí)打開燥爷。
個(gè)人的一點(diǎn)小建議:
tcp_tw_recycle 選項(xiàng)在4.10內(nèi)核之前還只是不適用于NAT/LB的情況(其他情況下蜈亩,我們也非常不推薦開啟該選項(xiàng)),但4.10內(nèi)核后徹底沒有了用武之地前翎,并且在4.12內(nèi)核中被移除.
tcp_tw_reuse 選項(xiàng)仍然可用稚配。在服務(wù)器上面,啟用該選項(xiàng)對于連入的TCP連接來說不起作用港华,但是對于客戶端(比如服務(wù)器上面某個(gè)服務(wù)以客戶端形式運(yùn)行道川,比如nginx反向代理)等是一個(gè)可以考慮的方案。
修改TCP_TIMEWAIT_LEN是非常不建議的行為立宜。