你有沒有考慮過,你的goroutines是如何被go的runtime系統調度的?是否嘗試理解過為什么在程序中增加了並發,但並沒有給它帶來更好的性能?go執行跟蹤程序可以幫助回答這些疑問,還有其他和其有關性能的問題,例如延遲、競爭和較低的並行效率。
該工具是Go 1.5版本加入的,通過度量go語言特定事件的運行時,例如:
-
創建,啟動和終止goroutines
-
阻塞/非阻塞goroutines(syscalls, channels, locks)
-
網絡 I/O
-
Syscalls
-
垃圾回收
Go 開箱就提供了一系列的性能監控 API 以及用於分析的工具, 可以快捷而有效地觀察應用各個細節的 CPU 與內存使用概況, 包括生成一些可視化的數據(需要額外安裝 Graphviz).
例子 gist 來自之前的 Trie 的實現, Ruby vs Go.
main
函數加上了下面幾行:
|
|
這里 os.Create("cpu_profile")
指定生成的數據文件, 然后 pprof.StartCPUProfile
看名字就知道是開始對 CPU 的使用進行監控. 有開始就有結束, 一般直接跟着 defer pprof.StopCPUProfile()
省的后面忘了. 編譯執行一次以后會在目錄下生成監控數據並記錄到 cpu_profile. 接着就可以使用 pprof 來解讀分析這些監控生成的數據.
When CPU profiling is enabled, the Go program stops about 100 times per second and records a sample consisting of the program counters on the currently executing goroutine’s stack.
CPU Profiling
|
|
因為是在多核環境, 所以, 取樣時間(Total samples) 占比大於 100% 也屬於正常的. 交互操作模式提供了一大票的命令, 執行一下 help
就有相應的文檔了. 比如輸出報告到各種格式(pdf, png, gif), 方塊越大個表示消耗越大.
又或者列出 CPU 占比最高的一些(默認十個)運行結點的 top
命令, 也可以加上需要的結點數比如 top15
|
|
- flat: 是指該函數執行耗時, 程序總耗時 570ms,
main.NewNode
的 200ms 占了 35.09% - sum: 當前函數與排在它上面的其他函數的 flat 占比總和, 比如
35.09% + 12.28% = 47.37%
- cum: 是指該函數加上在該函數調用之前累計的總耗時, 這個看圖片格式的話會更清晰一些.
可以看到, 這里最耗 CPU 時間的是 main.NewNode
這個操作.
除此外還有 list
命令可以根據匹配的參數列出指定的函數相關數據, 比如:
Memory Profiling
|
|
類似 CPU 的監控, 要監控內存的分配回收使用情況, 只要調用 pprof.WriteHeapProfile(memProfile)
然后是跟上面一樣的生成圖片:
Type: inuse_space 是監控內存的默認選項, 還可以選 -alloc_space, -inuse_objects, -alloc_objects
inuse_space 是正在使用的內存大小, alloc_space是從頭到尾一共分配了的內存大小(包括已經回收了的), 后綴為 _objects
的是相應的對象數
net/http/pprof
對於 http 服務的監控有一些些的不同, 不過 Go 已經對 pprof 做了一些封裝在 net/http/pprof
例子 gist 來自從 net/http 入門到 Gin 源碼梳理
引入多一行 _ "net/http/pprof"
, 啟用服務以后就可以在路徑 /debug/pprof/
看到相應的監控數據. 類似下面(已經很貼心的把各自的描述信息寫在下邊了):
用 wrk (brew install wrk) 模擬測試
wrk -c 200 -t 4 -d 3m http://localhost:8080/hello
還是沒有前面的那些可視化圖形 UI 直觀, 不過可以通過 http://localhost:8080/debug/pprof/profile (其他幾個指標也差不多, heap, alloc…)生成一個類似前面的 CPU profile 文件監控 30s 內的數據. 然后就可以用 go tool pprof
來解讀了.
|
|