Go語言之使用pprof工具查找goroutine(協(xié)程)泄漏
用pprof工具查找goroutine(協(xié)程)泄漏
goroutine泄漏指的是goroutine啟動之后沒有退出導致goroutine的數(shù)量持續(xù)上升,或者是在實際應用中g(shù)oroutine占用了很長時間才退出導致在一段時間內(nèi)goroutine的數(shù)量急劇上升。
通??梢圆捎肎o自帶的pprof工具來定位問題
如下面這個示例
這是一個簡單的HTTP服務,當接收到請求時另起一個goroutine來輸出日志,同時返回“Hello, World!\n”。
在記錄日志之前可能要處理一個耗時很長的業(yè)務邏輯,如通過公網(wǎng)請求第三方的API接口,這里為了簡化問題用time.Sleep來示意。
goroutineleak.go
package main import ( "io" "log" "net/http" _ "net/http/pprof" "time" ) func writeLog(msg string) { go func() { time.Sleep(1 * time.Second) log.Println(msg) }() } func handler(w http.ResponseWriter, r *http.Request) { writeLog(r.URL.RequestURI()) io.WriteString(w, "Hello, world!\n") } func main() { http.HandleFunc("/", handler) http.ListenAndServe(":8080", nil) }
利用Grinder來壓測,開8個進程,每個進程開3個線程,同時請求上述服務。
在請求過程中,通過瀏覽器查看http://pub.pengpengzhou.com:8080/debug/pprof/goroutine?debug=1, 域名是上述服務所在的地址。
從pprof的返回結(jié)果中,我們可以看到協(xié)程總數(shù)是5605,下面列出了5組產(chǎn)生協(xié)程的代碼stack trace,按產(chǎn)生的協(xié)程數(shù)量倒排序。
可以看到第一組產(chǎn)生了5597個協(xié)程,產(chǎn)生位置在goroutineleak.go的13行“time.Sleep(1 * time.Second)”對應的函數(shù)是main.writeLog。
問題很快得到定位,把這一行注釋掉,重新再壓測,可以得到如下結(jié)果, 協(xié)程總數(shù)一下就降到了8,泄漏的問題得到了解決。
當然,在實際應用中,耗時是不可避免的,通常是用設(shè)置超時的辦法來規(guī)避長時間等待。
總結(jié)
以上為個人經(jīng)驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關(guān)文章
Go?Gin框架優(yōu)雅重啟和停止實現(xiàn)方法示例
Web應用程序中,有時需要重啟或停止服務器,無論是因為更新代碼還是進行例行維護,這時需要保證應用程序的可用性和數(shù)據(jù)的一致性,就需要優(yōu)雅地關(guān)閉和重啟應用程序,即不丟失正在處理的請求和不拒絕新的請求,本文將詳解如何在Go語言中使用Gin這個框架實現(xiàn)優(yōu)雅的重啟停止2024-01-01Go語言函數(shù)的延遲調(diào)用(Deferred Code)詳解
本文將介紹Go語言函數(shù)和方法中的延遲調(diào)用,正如名稱一樣,這部分定義不會立即執(zhí)行,一般會在函數(shù)返回前再被調(diào)用,我們通過一些示例來了解一下延遲調(diào)用的使用場景2022-07-07golang 如何用反射reflect操作結(jié)構(gòu)體
這篇文章主要介紹了golang 用反射reflect操作結(jié)構(gòu)體的操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧2021-04-04Ruby序列化和持久化存儲(Marshal、Pstore)操作方法詳解
這篇文章主要介紹了Ruby序列化和持久化存儲(Marshal、Pstore)操作方法詳解,包括Ruby Marshal序列化,Ruby Pstore存儲,需要的朋友可以參考下2022-04-04