Goroutine 泄漏,出事到跑路

生產環境這兩天頻繁上線代碼。訂單業務流量快速增長的同時,goroutine 數量暴漲。臨發現的時候,蹭蹭蹭已經衝到 5、6 百個 goroutine,並且幾乎沒有下降的趨勢。

嚴重的作妖現象,妖極必反,第一反應是暗暗心裏發苦:goroutine 泄漏!否則應該穩定最多一百多個 goroutine 左右。生產環境,pprof 關閉狀態。

先查了下 Kibana 的日誌流量,差不多一個小時一個小時地有併發的日誌量流量嚴重,日誌裏面搜了幾個關鍵詞:panic, runtine, stack, timeout, "invalid memory address"。沒有什麼訂單項目的相關的異常。

這就離譜,沒定位問題出處。

趕緊把 master 拉一個分支出來,發佈到測試環境的 k8s 集羣裏。拉起一個 api 的鏡像。暴露 pprof 出來一看,我勒個乖乖,復現了。也在一直增長,也是一樣沒有 gotoutine 回落的跡象。

但是初步明確是對外網絡連接的問題。既然測試環境能浮現,那我索性直接在本地 run 起來。

然後發了幾個請求,看着 goroutine 遞增的同時,看那些程序在佔用最多的 goroutine 消耗。

go tool pprof localhost:9091/pprof/goroutine?debug=1
top
tree 20

發現,訂單列表查詢和訂單統計的 orm 是最大百分比份額。查了一下代碼,gorm 好像查詢結果返回了一個切片,但是沒有進行初始化。於是改了一下,然後重新 debug 重複上面的調試步驟。

好開心:只有 40 個 goroutine 了。持續發起多個請求,我還是高興的太早了。一開始只是重啓,goroutine 數量因爲程序重啓暫時清零而已。過了一會兒,隨着測試的各個接口持續下來,又上去了。

排查了好久,中間這玩意兒一度飆到了 2000 以上。

這整的我血壓都上來了。趕緊上報直屬 leader 和 技術大牛,一起來研究。

嘗試把所有的對外 http 請求進行改造,我們基於 gin 進行了二次開發做的一個微服務架構。現在既然是網絡問題,那最可能出問題的地方應該就是對外部第三方 API 調用或者 kafka 消費。這兩大部分都是走的 http 。

隊友懷疑是所有的對外的接口沒有進行 context 上下文的 cancel,於是所有對外接口統一用 context.WithCancel 和 context.WithTimeout 試了一遍,然而並沒有起作用。

時間慢慢在消逝,斷來斷去,最後原因定位到落在創建訂單的邏輯上。然後一段一段註釋,打印 log。然後 google 搜索了不少,最後嘗試了一下在我們二次封裝的底層邏輯內增加參數。

我旁邊的美女程序媛,她率先成功了!她直接修改網絡連接客戶端的結構體。增加了一個參數值。我其實之前在 stackoverflow 也查到類似的辦法了。

t.DisableKeepAlives = true

底層的 golang 網絡包,可以在這個 /go/src/net/http 目錄找到 Transport 這個結構體。從註釋看,客戶端每個 http 請求都是用 Transport 做相應的機制處理的。而 DisableKeepAlives 這個參數如果沒有設置,就是默認的長鏈接。

➜  http pwd
/usr/local/go/src/net/http
 173
 174     // DisableKeepAlives, if true, disables HTTP keep-alives and
 175     // will only use the connection to the server for a single
 176     // HTTP request.
 177     //
 178     // This is unrelated to the similarly named TCP keep-alives.
 179     DisableKeepAlives bool

率先發布到測試環境,果然平復了 goroutine。改造之後,像 Timeout 一樣作爲 Client 對象工廠方法創建時的可選參數傳遞。

趕緊通過 CI/CD 推送新的 merge hotfix / 分支,20 多秒之後,新版本替代 pod Running 起來,替換了老版本的 pod。

刷新 Grafana ,啓動時是 60 多個 goroutine,最後穩定在 120 個上下。觀察了 10 多分鐘,基本穩定在 130 個以下,一塊悶石終於緩緩落地。

下午 6:50 去樓下胡亂吃了碗米飯。

7:30,下班,撤,回家寫篇公衆號壓壓驚。還好不用跑路,虛驚一場。

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/W0gSSS9Oie_gzbLoK1THsA