Gin架構下使用pprof檢視程式占cpu資源
代碼添加
import "github.com/DeanThompson/ginpprof"
...
router := gin.Default()
ginpprof.Wrap(router)
...
浏覽器通路
![](https://img.laitimes.com/img/__Qf2AjLwojIjJCLyojI0JCLicmbw5SMUNlUmZ1LcNTMvwlNw8CX5EDMy8CXt92YugXM4FmLyM3Lc9CX6MHc0RHaiojIsJye.png)
- allocs:對所有過去記憶體配置設定的抽樣
- block:導緻同步原語阻塞的堆棧跟蹤
- cmdline:目前程式的指令行調用
- goroutine:目前所有goroutine的堆棧跟蹤
- heap: 堆記憶體配置設定情況的記錄,預設每配置設定512K位元組時取樣一次。
- mutex:檢視争用互斥鎖的持有者。
- profile:CPU配置檔案
- threadcreate:建立新OS線程的堆棧跟蹤
- trace:目前程式的執行軌迹
可讀資訊太少,下面展示pprof web功能
指令行
//輸入
$ go tool pprof http://ip:port/debug/pprof/profile
//輸出
Saved profile in C:\Users\seeta\pprof\pprof.main.samples.cpu.008.pb.gz
File: main
Type: cpu
Time: Jun 13, 2019 at 12:04pm (CST)
Duration: 30s, Total samples = 0
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
//在(pprof)右邊輸入 web
(pprof) web
//自動打開浏覽器
采樣時間
上圖展示了30s 的 CPU 采樣資訊,可使用second指定采樣時間,例如指令行輸入:
$ go tool pprof http://ip:port/debug/pprof/profile?second=60
采樣狀态
檢視根據曆史(-alloc_space)或正在使用(-inuse_space)
$ go tool pprof -alloc_space http://ip:port/debug/pprof/profile?second=60
采樣篩選
運作 go tool pprof 指令時加上 –nodefration=0.05 參數,表示如果調用的子函數使用的 CPU、memory 不超過 5%,就忽略它,不要顯示在圖檔中。
火焰圖
要生成火焰圖,需要事先安裝 FlameGraph工具,這個工具的安裝很簡單,隻要把對應的可執行檔案放到
$PATH
目錄下就行,在window下不可用。
dump-goroutine-stacktraces
重點:
runtime.Stac
參考代碼:
func main(){
...
setupSigusr1Trap()
...
}
func setupSigusr1Trap() {
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGUSR1)//監聽SIGUSER1信号,僅限linux系統,win下編譯出錯
go func() {
for range c {
DumpStacks()
}
}()
}
func DumpStacks() {
buf := make([]byte, 16384)
buf = buf[:runtime.Stack(buf, true)]
fmt.Printf("=== BEGIN goroutine stack dump ===\n%s\n=== END goroutine stack dump ===", buf)
}
執行代碼,指令行輸入(linux系統):
$ lsof -i:port //port是程式監聽的端口,這樣可以擷取程式的pid
//COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME
// main 123 xxx ...
$ kill -n USR1 123
//這個指令并不會殺死程序,隻是發送了SIGUSER1信号
//控制台輸出如下類似的goroutin效資訊
=== BEGIN goroutine stack dump ===
goroutine 36 [running]:
main.DumpStacks()
/home/seeta/wjx/jiesi_data/main.go:61 +0x77
main.setupSigusr1Trap.func1(0xc0001a62a0)
/home/seeta/wjx/jiesi_data/main.go:54 +0x34
created by main.setupSigusr1Trap
/home/seeta/wjx/jiesi_data/main.go:52 +0xab
goroutine 1 [IO wait, 14 minutes]:
internal/poll.runtime_pollWait(0x7fb675e01f00, 0x72, 0x0)
/usr/local/go/src/runtime/netpoll.go:173 +0x66
internal/poll.(*pollDesc).wait(0xc0001be418, 0x72, 0xc00006a100, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:85 +0x9a
internal/poll.(*pollDesc).waitRead(0xc0001be418, 0xffffffffffffff00, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_poll_runtime.go:90 +0x3d
internal/poll.(*FD).Accept(0xc0001be400, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0)
/usr/local/go/src/internal/poll/fd_unix.go:384 +0x1a0
net.(*netFD).accept(0xc0001be400, 0x40d71f, 0xc0000a8140, 0xa0)
/usr/local/go/src/net/fd_unix.go:238 +0x42
net.(*TCPListener).accept(0xc0001ae2a0, 0xc0004bbd20, 0xe2fa0034, 0x40cb3d006f28230d)
/usr/local/go/src/net/tcpsock_posix.go:139 +0x2e
net.(*TCPListener).AcceptTCP(0xc0001ae2a0, 0xc0004bbd48, 0x4b51b6, 0x5d01c65c)
/usr/local/go/src/net/tcpsock.go:247 +0x47
net/http.tcpKeepAliveListener.Accept(0xc0001ae2a0, 0xc0004bbd98, 0x18, 0xc000000300, 0x6e9185)
/usr/local/go/src/net/http/server.go:3232 +0x2f
net/http.(*Server).Serve(0xc000208b60, 0xc94240, 0xc0001ae2a0, 0x0, 0x0)
/usr/local/go/src/net/http/server.go:2826 +0x22f
net/http.(*Server).ListenAndServe(0xc000208b60, 0xbdab48, 0xa)
/usr/local/go/src/net/http/server.go:2764 +0xb6
JSDataManager/manager/serverManager.StartToListen(0x0, 0xbb244c)
/home/seeta/wjx/jiesi_data/manager/serverManager/ServerMananger.go:63 +0x4e
main.main()
/home/seeta/wjx/jiesi_data/main.go:42 +0x257
...
=== END goroutine stack dump ===
參考資料:
https://stackoverflow.com/questions/19094099/how-to-dump-goroutine-stacktraces