一次對server服務大量積壓異常TCP ESTABLISHED鏈接的排查筆記

背景

我們都知道昌阿,基于Kubernetes的微服務,大行其道恳邀,傳統(tǒng)部署模式一直都在跟著變化懦冰,但其實,在原有業(yè)務向服務化方向過度過程中谣沸,有些場景可能會變得復雜刷钢。

比如說:將Kubernetes的模式應用到開發(fā)環(huán)節(jié)上,這個環(huán)節(jié)需要頻繁的變更代碼乳附,微服務的方式闯捎,可能就需要不斷的:

改代碼->構建鏡像->鏡像推送->部署->拉去鏡像->生成容器

尤其是PHP的業(yè)務,不需要構建二進制许溅,僅需要發(fā)布代碼瓤鼻,因此,如果按照上面的部署方式贤重,就需要頻繁改代碼茬祷,走構建鏡像這個流程,最后再做發(fā)布并蝗,這在開發(fā)環(huán)節(jié)就顯得過于麻煩了祭犯,換而言之,有沒有辦法滚停,能讓開發(fā)直接將代碼上傳到容器中呢沃粗?

其實是有的,就是設計一個FTP中間件代理键畴,讓用戶本地改完代碼最盅,通過FTP客戶端(很多IDE是支持FTP的)直接上傳到容器內(nèi)部突雪,甚至于用戶保存一下代碼就上傳到容器內(nèi)。

因此涡贱,這就引出了今天的主角咏删,是我基于FTP協(xié)議+gRPC協(xié)議自研的FTP代理工具。

這個工具上線后问词,服務全公司所有研發(fā)督函,經(jīng)過一段時間運行和修補,相對穩(wěn)定激挪,也做了一些關于內(nèi)存方面的優(yōu)化辰狡,直到又一次,在維護這個FTP代理的時候垄分,發(fā)現(xiàn)一個奇怪的問題:

FTP代理進程搓译,監(jiān)聽的是 192.168.88.32 的 21 端口,所以锋喜,這個端口對應了多少連接些己,就表示有多少個客戶端存在,通過:

netstat -apn |grep "192.168.88.32:21"

發(fā)現(xiàn)嘿般,有將近1000個鏈接段标,且都是 ESTABLISHED,ESTABLISHED 狀態(tài)表示一個連接的狀態(tài)是“已連接”炉奴,但我們研發(fā)團隊逼庞,并沒有那么多人,直覺上看瞻赶,事出反常必有妖赛糟。

初步分析可能性

感覺可能有一種情況,就是每個人開了多個FTP客戶端砸逊,實際場景下璧南,研發(fā)同學組可能會使用3種類型的FTP客戶端

PHPStorm:這個客戶端(SFTP插件)自己會維護一個FTP長連接。
Sublime + VsCode师逸,這2個客戶端不會維護鏈接司倚,數(shù)據(jù)交互完成(比如傳輸任務),就主動發(fā)送 QUIT 指令到FTP代理端篓像,然后所有鏈接關閉动知。很干凈。

另外员辩,使用PHPStorm的話盒粮,也存在開多個IDE創(chuàng)建,就使用多個FTP客戶端連接的情況奠滑。
為了繼續(xù)排查丹皱,我把所有對 192.168.88.32:21 的鏈接妒穴,做了分組統(tǒng)計,看看哪個IP的連接數(shù)最多

# 注:61604 是 ftp代理的進程ID
netstat -apn|grep "61604/server"|grep '192.168.88.32:21'|awk -F ':' '{print$2}'|awk '{print$2}'|sort|uniq -c |sort

上面的統(tǒng)計种呐,是看哪個IP,對 192.168.88.32:21 連接數(shù)最多(18個)弃甥。

統(tǒng)計發(fā)現(xiàn)爽室,很多IP,都存在多個鏈接的情況淆攻,難道每個人都用了多個IDE且可能還多IDE窗口使用嗎阔墩?于是,挑了一個最多的瓶珊,找到公司中使用這個IP的人啸箫,溝通發(fā)現(xiàn),他確實使用了IDE多窗口伞芹,但是遠遠沒有使用18個客戶端那么多忘苛,僅僅PHPStorm開了3個窗口而已。

初步排查結論:應該是FTP代理所在服務器的問題唱较,和用戶開多個客戶端沒有關系扎唾。

進一步排查

這次排查,是懷疑南缓,這將近1000個的 ESTABLISHED 客戶端鏈接中胸遇,有大量假的 ESTABLISHED 鏈接存在,之前的統(tǒng)計發(fā)現(xiàn)汉形,實際上纸镊,對 192.168.88.32:21 的客戶端鏈接進行篩選,得到的IP概疆,一共才200個客戶端IP而已逗威,平均下來,每個人都有5個FTP客戶端鏈接FTP代理岔冀,想象覺得不太可能庵楷。那么,如何排查 ESTABLISHED 假鏈接呢楣颠?

在 TCP 四次揮手過程中尽纽,首先需要有一端,發(fā)起 FIN 包童漩,接收方接受到 FIN 包之后弄贿,便開啟四次揮手的過程,這也是連接斷開的過程矫膨。

從之前的排查看差凹,有人的IP期奔,發(fā)起了多達18個FTP連接,那么危尿,要排查是不是在 FTP 代理服務器上呐萌,存在假的 ESTABLISHED 連接的話,就首先需要去 開發(fā)同學的機器上看谊娇,客戶端連接的端口肺孤,是不是仍在使用。比如:

tcp    ESTAB      0      0      192.168.88.32:21                 192.168.67.38:58038

這個表明济欢,有一個研發(fā)的同學 IP是 192.168.67.38赠堵,使用了端口 58038,連接 192.168.88.32 上的 FTP 代理服務的 21 端口法褥。所以茫叭,先要去看,到底研發(fā)同學的電腦上半等,這個端口存在不存在揍愁。

后來經(jīng)過與研發(fā)同學溝通確認,研發(fā)電腦上并沒有 58038 端口使用杀饵,這說明吗垮,對FTP代理服務的的客戶端鏈接中顯示的端口,也就是實際用戶的客戶端端口凹髓,存在大量不存在的情況烁登。

結論:FTP代理服務器上,存在的近1000個客戶端連接中(ESTABLISHED狀態(tài))蔚舀,有大量的假連接存在饵沧。也就是說,實際上這個連接早就斷開不存在了赌躺,但服務端卻還顯示存在狼牺。

排查假 ESTABLISHED 連接

首先,如果出現(xiàn)假的 ESTABLISHED 連接礼患,表示連接的客戶端已經(jīng)不存在了是钥,客戶端一方,要么發(fā)起了 TCP FIN 請求服務端沒有收到缅叠,比如因為網(wǎng)絡的各種原因(比如斷網(wǎng)了)之后悄泥,F(xiàn)TP客戶端無法發(fā)送FIN到服務端。要么服務端服務器接受到了 FIN肤粱,但是在后續(xù)過程中弹囚,丟包了等等。

為了驗證上面的問題领曼,我本機進行了一次模擬鸥鹉,連接FTP服務端后蛮穿,本機直接斷網(wǎng),斷網(wǎng)后毁渗,殺死FTP客戶端進程践磅,等待5分鐘(為什么等待5分鐘后面說)后,重新聯(lián)網(wǎng)灸异。然后再 FTP 服務端府适,查看服務器上與 FTP代理進行連接的所有IP,然后發(fā)現(xiàn)我本機的IP和端口依然在列绎狭,然后再我本機细溅,通過

lsof -i :端口號

卻沒有任何記錄褥傍,直接說明:服務端確實保持了假 ESTABLISHED 鏈接儡嘶,一直不釋放。

上面提到恍风,我等待5分鐘蹦狂,是因為,服務端的 keepalive朋贬,是這樣的配置:

[root@xx xx]# sysctl -a |grep keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 300

服務器默認設置的 tcp keepalive 檢測是300秒后進行檢測凯楔,也就是5分鐘,當檢測失敗后锦募,一共進行9次重試摆屯,每次時間間隔是75秒。
那么糠亩,問題就來了虐骑,服務器設置了 keepalive,如果 300 + 9*75 秒后赎线,依然連接不上廷没,就應該主動關閉假 ESTABLISHED 連接才對。為何還會積壓呢垂寥?

猜想1:大量的積壓的 ESTABLISHED 連接颠黎,實際上都還沒有到釋放時間

為了驗證這個問題,我們就需要具體的看某個連接滞项,什么時候創(chuàng)建的狭归。所以,我找到其中一個我確定是假的 ESTABLISHED的鏈接(那個IP的用戶文判,把所有FTP客戶端都關了唉铜,進程也殺死了),看此連接的創(chuàng)建時間律杠,過程如下:

先確定 FTP 代理進程的ID潭流,為 61604

然后竞惋,看看這個進程的所有連接,找到某個端口的(55360灰嫉,就是一個客戶端所使用的端口)

[root@xxx xxx]# lsof -p 61604|grep 55360
server  61604 root    6u     IPv4 336087732      0t0        TCP node088032:ftp->192.168.70.16:55360 (ESTABLISHED)

我們看到一個 “6u”拆宛,這個就是進程使用的這個連接的socket文件,Linux中讼撒,一切皆文件浑厚。我們看看這個文件的創(chuàng)建時間,就是這個連接的創(chuàng)建時間了

ll /proc/61604/fd/6
//輸出:
lrwx------. 1 root root 64 Nov  1 14:03 /proc/61604/fd/6 -> socket:[336087732]

這個連接是11月1號創(chuàng)建的根盒,現(xiàn)在已經(jīng)11月8號钳幅,這個時間,早已經(jīng)超出了 keepalive 探測 TCP連接是否存活的時間炎滞。這說明2個點:

1敢艰、可能 Linux 的 KeepAlive 壓根沒生效。
2册赛、可能我的 FTP 代理進程钠导,壓根沒有使用 TCP KeepAlive

猜想2: FTP 代理進程,壓根沒有使用 TCP KeepAlive

要驗證這個結論森瘪,就得先知道牡属,怎么看一個連接,到底具不具備 KeepAlive 功效扼睬?

netstat 命令不好使(也可能我沒找到方法)逮栅,我們使用 ss 命令,查看 FTP進程下所有連接21端口的鏈接

ss -aoen|grep 192.168.12.32:21|grep ESTAB

從眾多結果中窗宇,隨便篩選2個結果:

tcp    ESTAB      0      0      192.168.12.32:21                 192.168.20.63:63677   ino:336879672 sk:65bb <->
tcp    ESTAB      0      0      192.168.12.32:21                 192.168.49.21:51896    ino:336960511 sk:67f7 <->

我們再對比一下措伐,所有連接服務器sshd進程的

tcp    ESTAB      0      0      192.168.12.32:333                192.168.53.207:63269               timer:(keepalive,59sec,0) ino:336462258 sk:6435 <->
tcp    ESTAB      0      0      192.168.12.32:333                192.168.55.185:64892               timer:(keepalive,3min59sec,0) ino:336461969 sk:62d1 <->
tcp    ESTAB      0      0      192.168.12.32:333                192.168.53.207:63220               timer:(keepalive,28sec,0) ino:336486442 sk:6329 <->
tcp    ESTAB      0      0      192.168.12.32:333                192.168.53.207:63771               timer:(keepalive,12sec,0) ino:336896561 sk:65de <->

對比很容易發(fā)現(xiàn),連接 21端口的所有連接担映,多沒有 timer 項废士。這說明,F(xiàn)TP代理 進程監(jiān)聽 21 端口時蝇完,所有進來的鏈接官硝,全都沒有使用keepalive。

找了一些文章短蜕,大多只是說氢架,怎么配置Linux 的 Keep Alive,以及不配置的朋魔,會造成 ESTABLISHED 不釋放問題岖研,沒有說進程需要額外設置啊?難道 Linux KeepAlive 配置孙援,不是對所有連接直接就生效的害淤?

所以,我們有必要驗證 Linux keepalive拓售,必須要進程自己額外開啟才能生效

驗證 Linux keepalive窥摄,必須要進程自己額外開啟才能生效

在開始這個驗證之前,先摘取一段FTP中間件代理關于監(jiān)聽 21 端口的部分代碼:

func (ftpServer *FTPServer) ListenAndServe() error {
    laddr, err := net.ResolveTCPAddr("tcp4", ftpServer.listenTo)
    if err != nil {
        return err
    }
    listener, err := net.ListenTCP("tcp4", laddr)
    if err != nil {
        return err
    }
    for {
        clientConn, err := listener.AcceptTCP()
        if err != nil || clientConn == nil {
            ftpServer.logger.Print("listening error")
            break
        }
        //以閉包的方式整理處理driver和ftpBridge础淤,協(xié)程結束整體由GC做資源釋放
        go func(c *net.TCPConn) {
            driver, err := ftpServer.driverFactory.NewDriver(ftpServer.FTPDriverType)
            if err != nil {
                ftpServer.logger.Print("Error creating driver, aborting client connection:" + err.Error())
            } else {
                ftpBridge := NewftpBridge(c, driver)
                ftpBridge.Serve()
            }
            c = nil
        }(clientConn)
    }
    return nil
}

足夠明顯崭放,整個函數(shù),net.ListenTCP 附近都沒有任何設置KeepAlive的相關操作鸽凶。我們查看 相關函數(shù)币砂,找到了設置 KeepAlive的地方,進行一下設置:

if err != nil || clientConn == nil {
    ftpServer.logger.Print("listening error")
    break
}
// 此處玻侥,設置 keepalive
clientConn.SetKeepAlive(true)

重新構建部署之后决摧,可以看到,所有對21端口的連接使碾,全部都帶了 timer

ss -aoen|grep 192.168.12.32:21|grep ESTAB

輸出如下:

tcp    ESTAB      0      0      192.168.12.32:21                 192.168.70.76:54888               timer:(keepalive,1min19sec,0) ino:397279721 sk:6b49 <->
tcp    ESTAB      0      0      192.168.12.32:21                 192.168.37.125:49648              timer:(keepalive,1min11sec,0) ino:398533882 sk:6b4a <->
tcp    ESTAB      0      0      192.168.12.32:21                 192.168.33.196:64471              timer:(keepalive,7.957ms,0) ino:397757143 sk:6b4c <->
tcp    ESTAB      0      0      192.168.12.32:21                 192.168.21.159:56630              timer:(keepalive,36sec,0) ino:396741646 sk:6b4d <->

可以很明顯看到蜜徽,所有的連接祝懂,全部具備了 timer 功效票摇,說明:想要使用 Linux 的 KeepAlive,需要程序單獨做設置進行開啟才行砚蓬。

最后:ss 命令結果中 keepalive 的說明

首先矢门,看一下 Linux 中的配置,我的機器如下:

[root@xx xx]# sysctl -a |grep keepalive
net.ipv4.tcp_keepalive_intvl = 75
net.ipv4.tcp_keepalive_probes = 9
net.ipv4.tcp_keepalive_time = 300

tcp_keepalive_time:表示多長時間后灰蛙,開始檢測TCP鏈接是否有效祟剔。
tcp_keepalive_probes:表示如果檢測失敗,會一直探測 9 次摩梧。
tcp_keepalive_intvl:承上物延,探測9次的時間間隔為 75 秒。

然后仅父,我們看一下 ss 命令的結果:

ss -aoen|grep 192.168.12.32:21|grep ESTAB
tcp ESTAB  0  0  192.168.12.32:21 192.168.70.76:54888 timer:(keepalive,1min19sec,0) ino:397279721 sk:6b49 <->

摘取這部分:timer:(keepalive,1min19sec,0) 叛薯,其中:

keepalive:表示此鏈接具備 keepalive 功效。
1min19sec:表示剩余探測時間笙纤,這個時間每次看都會邊耗溜,是一個遞減的值,第一次探測省容,需要 net.ipv4.tcp_keepalive_time 這個時間倒計時抖拴,如果探測失敗繼續(xù)探測,后邊會按照 net.ipv4.tcp_keepalive_intvl 這個時間值進行探測腥椒。直到探測成功阿宅。
0:這個值是探測時候衍,檢測到這是一個無效的TCP鏈接的話已經(jīng)進行了的探測次數(shù)。


歡迎關注“海角之南”公眾號獲取更新動態(tài)

haijiaozhinan.png
?著作權歸作者所有,轉載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末洒放,一起剝皮案震驚了整個濱河市脱柱,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌拉馋,老刑警劉巖榨为,帶你破解...
    沈念sama閱讀 207,248評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異煌茴,居然都是意外死亡随闺,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評論 2 381
  • 文/潘曉璐 我一進店門蔓腐,熙熙樓的掌柜王于貴愁眉苦臉地迎上來矩乐,“玉大人,你說我怎么就攤上這事回论∩⒑保” “怎么了?”我有些...
    開封第一講書人閱讀 153,443評論 0 344
  • 文/不壞的土叔 我叫張陵傀蓉,是天一觀的道長欧漱。 經(jīng)常有香客問我,道長葬燎,這世上最難降的妖魔是什么误甚? 我笑而不...
    開封第一講書人閱讀 55,475評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮谱净,結果婚禮上窑邦,老公的妹妹穿的比我還像新娘。我一直安慰自己壕探,他們只是感情好冈钦,可當我...
    茶點故事閱讀 64,458評論 5 374
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著李请,像睡著了一般瞧筛。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上捻艳,一...
    開封第一講書人閱讀 49,185評論 1 284
  • 那天驾窟,我揣著相機與錄音,去河邊找鬼认轨。 笑死绅络,一個胖子當著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播恩急,決...
    沈念sama閱讀 38,451評論 3 401
  • 文/蒼蘭香墨 我猛地睜開眼杉畜,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了衷恭?” 一聲冷哼從身側響起此叠,我...
    開封第一講書人閱讀 37,112評論 0 261
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎随珠,沒想到半個月后灭袁,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,609評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡窗看,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 36,083評論 2 325
  • 正文 我和宋清朗相戀三年茸歧,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片显沈。...
    茶點故事閱讀 38,163評論 1 334
  • 序言:一個原本活蹦亂跳的男人離奇死亡耳峦,死狀恐怖裆泳,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情粪小,我是刑警寧澤风科,帶...
    沈念sama閱讀 33,803評論 4 323
  • 正文 年R本政府宣布裕菠,位于F島的核電站丙笋,受9級特大地震影響鱼蝉,放射性物質發(fā)生泄漏。R本人自食惡果不足惜盖彭,卻給世界環(huán)境...
    茶點故事閱讀 39,357評論 3 307
  • 文/蒙蒙 一纹烹、第九天 我趴在偏房一處隱蔽的房頂上張望页滚。 院中可真熱鬧召边,春花似錦、人聲如沸裹驰。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,357評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽幻林。三九已至贞盯,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間沪饺,已是汗流浹背躏敢。 一陣腳步聲響...
    開封第一講書人閱讀 31,590評論 1 261
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留整葡,地道東北人件余。 一個月前我還...
    沈念sama閱讀 45,636評論 2 355
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親啼器。 傳聞我的和親對象是個殘疾皇子旬渠,可洞房花燭夜當晚...
    茶點故事閱讀 42,925評論 2 344

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