TCP服務端主動斷開連線問題

語言: CN / TW / HK

零、背景

多年前的時候,我曾提起過我名下掛了一個2013年的中轉服務,這個服務多年來一直在線上裸奔,沒人動過。

當時在《 歷史悠久的微博中轉 》這篇文章裡分享了這個中轉服務的架構設計。

後來還在《 記一次微博中轉異常 》文章裡分享了遇到的一個問題。

這不,最近又遇到問題了。

一、流量不均衡

元旦晚會前幾天,大家都在準備服務擴容的事情。

運維問我中轉還能擴容嗎?

我回答國慶的時候已經盡最大可能擴容了,之後再擴整個服務就起不來了,應該到達系統架構上限了。

我也曾在內心自問:具體架構的哪裡到達上限呢?

自己回答:還沒細看程式碼,不是很清楚。

然後又進行合理推理:巨集觀上看架構是可以無限擴容的,應該是微觀上某個地方遇到類似於千年蟲的問題了。

而元旦前夕,突然收到最大值告警。

一看流量,訪問量翻了好幾倍,部分機器網絡卡跑的很高。

看下機型配置,都是8核、16G記憶體、1G流量。

竟然有單機 qps 高達 18~20W/s,流量幾乎跑滿。

注:週四流量還低,不過監控系統只能看到最近的若干天,我記得暴漲之前大概只有不到 40M,與高峰期比翻了 3倍。

為啥有這麼大的流量呢?

這應該歸屬是業務架構設計不合理,沒有正確使用中轉這個原因。

1、使用多臺機器重複生產相同的資料。

2、每臺機器死迴圈的方式生產相同資料。

3、生產的每條資料是歷史上全量變更訊息。

4、80+個消費者分別訂閱一份全量資料。

這樣,相同的資料被放大了無數倍,就出現了上圖的峰值每秒 200萬的qps。

沒業務反饋有啥問題,暫時沒人敢動了。

不過我發現一個地方不對勁:服務有20臺機器,總量200萬的話,單機應該 10萬才對。

為啥會有單機 20萬的量呢?

二、發現問題

先看下中轉的架構吧。

架構比較簡單,分為五個模組:配置中心、生成者、介面機、轉發機、消費者。

上一小節提到的單機 qps 20 萬指的是轉發機成功向消費者傳送的包量。

我的第一反應是去那個轉發機看看錯誤日誌,結果發現這臺機器沒任何問題。

接著我就分析監控檢視,發現在介面機到轉發機發資料時,就已經不均勻了。

本來介面機會把訊息平均的發給所有轉發機。

現在遇到這種情況說明部分介面機或轉發機有問題,只能多登陸幾臺機器,看看能不能發現什麼錯誤日誌。

看了五六臺機器的日誌後,還真發現一個問題:部分介面機在不斷的建立連向轉發機的連線。

那就解釋通了:介面機與某些轉發機連線不通,流量就被髮給其他機器了,從而流量不均勻。

三、分析問題

那為什麼在不斷的建立連線呢?

使用 tcpdump 抓包一看,發現連上轉發機後,轉發機作為服務端馬上主動把連線斷開了。

所以問題還是出在轉發機上,不過是流量低的那些轉發機上(連線連不上,流量過不來)。

去有問題的轉發機,沒發現什麼錯誤日誌,看了看中轉業務程式碼,也沒發現什麼問題。

那隻能祭出終極方法了:檢視網路框架的程式碼。

大概看了框架程式碼,也沒發現問題。

一想,這個網路框架與中轉業務都跑了六七年了,邏輯應該沒有大問題,需要注意那些邊界情況。

於是再回頭細看網路框架的各種邊界,還真發現有種情況會導致連接出問題。

框架對TCP的連線數做了最大限制。

看到這,就是驗證猜想了。

使用 lsof 檢視 fd 數量,確實挺多的。

再使用 gcore 生成服務的記憶體映象,然後 gdb 進去輸出相關變數。

還真是進入了連線最大限制這段程式碼。

注:這裡是網路框架邏輯上的限制,而不是系統級別的限制,所以檢視 /proc/limitlsof 都不能實錘問題。

四、解決問題

既然確定問題了,就好辦了。

而且發現這個限制是配置化的,現在配置的是 128 ,那直接設定成無限大就行了。

但是又看了下框架程式碼,發現連線還真不能隨便設定的太大。

因為這個框架需要預先評估需要多少連線,然後啟動的時候就申請建立了所有的資源。

考慮到這個連線僅僅是轉發機與介面機之間的,也就是有多少轉發機就有多少個連線。

那就把轉發機配置成 256 吧。

預留一倍的 buffer 應該可以用到這個中轉退休了。

五、最後

回頭想想,起初是流量暴漲問題,然後發現業務架構不合理問題,接著發現流量不均衡問題,再接著發現連線被服務端主動斷開問題,最終發現是網路框架對連線數做了限制。

定位問題就是這樣一環扣一環。

不過連線被斷開這個現象真不好發現,只有部分介面機異常有錯誤日誌,登入很多幾次才發現問題的。

這一環節算是運氣環節了,有耐心一臺臺看日誌的話肯定可以發現。 , 如果當時只登入幾臺,恰好沒看到錯誤日誌,那就沒有下文了。

稍等,我怎麼記得遇到連線被斷開問題的時候,去轉發機和介面機分別執行了 netstat 命令,看到的資料怎麼不一致呢?

敬請期待下篇TCP話題文章:連線未釋放問題。

-EOF-

本文公眾號:天空的程式碼世界

個人微訊號:tiankonguse

QQ演算法群:165531769(不止演算法)

知識星球:不止演算法