TCP服務端主動斷開連線問題
零、背景
多年前的時候,我曾提起過我名下掛了一個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/limit
和 lsof
都不能實錘問題。
四、解決問題
既然確定問題了,就好辦了。
而且發現這個限制是配置化的,現在配置的是 128
,那直接設定成無限大就行了。
但是又看了下框架程式碼,發現連線還真不能隨便設定的太大。
因為這個框架需要預先評估需要多少連線,然後啟動的時候就申請建立了所有的資源。
考慮到這個連線僅僅是轉發機與介面機之間的,也就是有多少轉發機就有多少個連線。
那就把轉發機配置成 256
吧。
預留一倍的 buffer 應該可以用到這個中轉退休了。
五、最後
回頭想想,起初是流量暴漲問題,然後發現業務架構不合理問題,接著發現流量不均衡問題,再接著發現連線被服務端主動斷開問題,最終發現是網路框架對連線數做了限制。
定位問題就是這樣一環扣一環。
不過連線被斷開這個現象真不好發現,只有部分介面機異常有錯誤日誌,登入很多幾次才發現問題的。
這一環節算是運氣環節了,有耐心一臺臺看日誌的話肯定可以發現。 , 如果當時只登入幾臺,恰好沒看到錯誤日誌,那就沒有下文了。
稍等,我怎麼記得遇到連線被斷開問題的時候,去轉發機和介面機分別執行了 netstat
命令,看到的資料怎麼不一致呢?
敬請期待下篇TCP話題文章:連線未釋放問題。
-EOF-
本文公眾號:天空的程式碼世界
個人微訊號:tiankonguse
QQ演算法群:165531769(不止演算法)
知識星球:不止演算法
- leetcode 第 312 場演算法比賽
- leetcode 第 311 場演算法比賽
- leetcode 第 310 場演算法比賽
- leetcode 第 286 場演算法比賽
- 請教下,go HTTP 服務如何同時支援 GET 與 POST
- 設計模式之迭代器模式
- 佇列卡住?方向錯了,使出十八般武藝也沒用
- 兩臺電腦如何複製資料,同事的方法我震驚了
- 影片的位元率、關鍵幀、FPS啥意思?
- Leetcode 第 171 場比賽回顧
- TCP服務端主動斷開連線問題
- Leetcode 第 179 場比賽回顧
- 觀看得到與B站的跨年晚會
- Leetcode 第 169 場比賽回顧
- Leetcode 第 168 場比賽回顧
- Leetcode 第 166 場比賽回顧
- Leetcode 第 165 場比賽回顧
- Leetcode 第 164 場比賽回顧
- 開始使用 vscode 了
- Leetcode 第 161 場比賽回顧