天天看點

Go使用 pprof 和 dump-goroutine-stacktraces

Gin架構下使用pprof檢視程式占cpu資源

代碼添加

import "github.com/DeanThompson/ginpprof"
...
router := gin.Default()
ginpprof.Wrap(router)
...
           

浏覽器通路

Go使用 pprof 和 dump-goroutine-stacktraces
  • 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
//自動打開浏覽器
           
Go使用 pprof 和 dump-goroutine-stacktraces

采樣時間

上圖展示了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