go 开了多少个goroutine 怎么看_线上 Go 程序偶尔出现异常怎么办?这个思路可解决你的烦恼...
Go 項目做的比較大(主要說代碼多,參與人多)之后,可能會遇到類似下面這樣的問題:
- 程序老是半夜崩,崩了以后就重啟了,我也醒不來,現場早就丟了,不知道怎么定位
- 這壓測開壓之后,隨機出問題,可能兩小時,也可能五小時以后才出問題,這我蹲點蹲出痔瘡都不一定能等到崩潰的那個時間點啊
- 有些級聯失敗,最后留下現場并不能幫助我們準確地判斷問題的根因,我們需要出問題時第一時間的現場
Go 內置的 pprof 雖然是問題定位的神器,但是沒有辦法讓你恰好在出問題的那個時間點,把相應的現場保存下來進行分析。特別是一些隨機出現的內存泄露、CPU 抖動,等你發現有泄露的時候,可能程序已經 OOM 被 kill 掉了。而 CPU 抖動,你可以蹲了一星期都不一定蹲得到。
這個問題最好的解決辦法是 continuous profiling,不過這個理念需要公司的監控系統配合,在沒有達到最終目標前,我們可以先向前邁一小步,看看怎么用比較低的成本來解決這個問題。
從現象上,可以將出問題的癥狀簡單分個類:
- cpu 抖動:有可能是模塊內有一些比較冷門的邏輯,觸發概率比較低,比如半夜的定時腳本,觸發了以后你還在睡覺,這時候要定位就比較鬧心了。
- 內存使用抖動:有很多種情況會導致內存使用抖動,比如突然涌入了大量請求,導致本身創建了過多的對象。也可能是 goroutine 泄露。也可能是突然有鎖沖突,也可能是突然有 IO 抖動。原因太多了,猜是沒法猜出根因的。
- goroutine 數暴漲,可能是死鎖,可能是數據生產完了 channel 沒關閉,也可能是 IO 抖了什么的。
CPU 使用,內存占用和 goroutine 數,都可以用數值表示,所以不管是“暴漲”還是抖動,都可以用簡單的規則來表示:
- xx 突然比正常情況下的平均值高出了 25%
- xx 超過了模塊正常情況下的最高水位線
這兩條規則可以描述大部分情況下的異常,規則一可以表示瞬時的,劇烈的抖動,之后可能迅速恢復了;規則二可以用來表示那些緩慢上升,但最終超出系統負荷的情況,例如 1s 泄露一兆內存,直至幾小時后 OOM。
而與均值的 diff,在沒有歷史數據的情況下,就只能在程序內自行收集了,比如 goroutine 的數據,我們可以每 x 秒運行一次采集,在內存中保留最近 N 個周期的 goroutine 計數,并持續與之前記錄的 goroutine 數據均值進行 diff:
time-Page-2
比如像圖里的情況,前十個周期收集到的 goroutine 數在 1300 左右波動,而最新周期收集到的數據為 2w+,這顯然是瞬時觸發導致的異常情況,那么我們就可以在這個點自動地去做一些事情,比如:
- 把當前的 goroutine 棧 dump 下來
- 把當前的 cpu profile dump 下來
- 把當前的 off-cpu profile dump 下來
- 不怕死的話,也可以 dump 幾秒的 trace
文件保存下來,模塊掛掉也就無所謂了。之后在喝茶的時候,發現線上曾經出現過崩潰,那再去線上機器把文件撈下來,一邊喝茶一邊分析,還是比較悠哉的。
這里面稍微麻煩一些的是 CPU 和內存使用量的采集,現在的應用可能跑在物理機上,也可能跑在 docker 中,因此在獲取用量時,需要我們自己去做一些定制。物理機中的數據采集,可以使用 gopsutil[1],docker 中的數據采集,可以參考少量 cgroups[2] 中的實現。
更具體的代碼會在之后的文章講,我們編寫的 lib 也會在不久后開源,當然,這篇文章其實已經把大部分實現思路講完了~
參考資料
[1]gopsutil: https://github.com/shirou/gopsutil
[2]cgroups: https://github.com/containerd/cgroups
推薦閱讀
線上問題排查實戰:容器中某Go服務GC停頓經常超過100ms
站長 polarisxu
自己的原創文章
不限于 Go 技術
職場和創業經驗
Go語言中文網
每天為你
分享 Go 知識
Go愛好者值得關注
總結
以上是生活随笔為你收集整理的go 开了多少个goroutine 怎么看_线上 Go 程序偶尔出现异常怎么办?这个思路可解决你的烦恼...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: antd 能自适应吗_自首要满足的条件有
- 下一篇: go http 处理w.write 错误