Go性能分析大殺器PPROF
- 2020 年 3 月 9 日
- 筆記
這是什麼
想要進行性能優化,Go本身自帶的工具鏈就包含了性能分析工具,而且也非常棒,pprof就是Go性能分析的利器,它是Go語言自帶的包,有如下兩種:
- runtime/pprof:採集程式(非 Server)的運行數據進行分析
- net/http/pprof:採集 HTTP Server 的運行時數據進行分析,這個其實在上面的功能中包了一層提供了http介面。
pprof用於可視化和性能分析的工具,pprof 以 profile.proto 讀取分析樣本的集合,並生成報告以可視化並幫助分析數據(支援文本和圖形報告)
這個文件是一個ProtocolBuffer v3的描述文件,它描述了一組callstack和 symbolization資訊,作用是表示統計分析的一組取樣的調用棧,是很常見的 stacktrace 配置文件格式
使用方式
Report generation:報告生成,直接生成一個文件,解析這個文件得到結果
Interactive terminal use:互動式終端使用,實時回饋,監控,需要開發人員輸入指令,根據輸入的指令返回想要的資訊。
Web interface:Web 介面,實時回饋,監控,對開發人員友好。很方便,直觀的獲取和統計需要的數據。
能做什麼
CPU Profiling: CPU分析,按照一定的頻率採集所監聽的應用程式的CPU使用情況,可確定應用程式在主動消耗 CPU 周期時花費時間的位置。
Memory Profiling:記憶體分析,在應用程式堆棧分配時記錄跟蹤,用於監視當前和歷史記憶體使用情況,檢查記憶體泄漏情況。
Block Profiling:阻塞分析,記錄goroutine阻塞等待同步的位置
Mutex Profiling:互斥鎖分析,報告互斥鎖的競爭情況
一個小Demo來解釋
import ( "net/http" _ "net/http/pprof" ) func PprofWeb() { err := http.ListenAndServe(":9909", nil) if err != nil { panic(err) } } web介面使用
啟動這段程式碼後,訪問 http://localhost:9909/debug/pprof/ ,就可以看到監控頁面了,截圖資訊如下,我們對這些進行一下解釋。

allocs:所有過去記憶體分配的取樣
block:導致同步原語阻塞的堆棧跟蹤
cmdline:當前程式的命令行調用
goroutine:所有當前goroutine的堆棧跟蹤
heap:活動對象的記憶體分配的取樣。在獲取堆樣本之前,可以指定gc GET參數來運行gc。
metux:爭用互斥鎖持有者的堆棧跟蹤
profile:CPU配置文件。您可以在seconds GET參數中指定持續時間。獲取配置文件後,使用go tool pprof命令調查配置文件
threadcreate:導致創建新作業系統執行緒的堆棧跟蹤
trace:當前程式的執行軌跡。您可以在seconds GET參數中指定持續時間。獲取跟蹤文件後,使用go tool trace命令調查跟蹤
互動式終端使用
控制台輸入如下命令,這個命令的作用是追蹤上面程式碼60秒內CPU的消耗情況,執行該命令後,需要等待60秒(這個時間可自己調整),60秒到達後默認進入pprof互動式命令行中,可輸入help命令查看pprof的使用幫助
go tool pprof http://localhost:9909/debug/pprof/profile?seconds=60 我們看下面圖片,命令執行後,過了10秒鐘進入互動式控制台,我輸入了top10,代表意思是顯示前10個消耗CPU較多的方法,圖中的flat,sum,cum是什麼含義呢,接下來解釋一下。
flat:給定函數上的運行耗時
flat% :給定函數上的CPU運行耗時佔比
sum% :給定函數累積使用CPU總比例
cum :當前函數加上它之前的調用運行總耗時
cum% :當前函數加上他之前的調用CPU運行耗時佔比

還有其它很多的命令比如 list,使用 list 函數名 命令查看具體的函數分析,同樣的,下面的命令行可以查看堆記憶體,阻塞,鎖的使用情況
go tool pprof http://localhost:9099/debug/pprof/heap go tool pprof http://localhost:9099/debug/pprof/block go tool pprof http://localhost:9099/debug/pprof/mutex 可視化介面使用
在上面的web介面中我們可以看到一行profile文字,點擊這個文字可以下載一個profile文件,下載完成之後。我們在這個文件所在目錄運行如下命令,有兩種方式
go tool pprof profile文件名, 此時會進入一個互動式控制台,輸入命令 web會產生一個svg文件,程式回啟動瀏覽器自動打開這個文件,即可進入可視化介面。我們也可以在上面CPU分析中的控制台中以同樣的方式進入可視化介面。
go tool pprof -http=:8080 profile文件名 ,此時瀏覽器會默認打開localhost:8080訪問 ,建議使用這種方式,獲取更好體驗。
如果出現下面錯誤,你需要安裝一個軟體Graphviz,安裝地址如下,這是一個圖形可視化軟體,安裝完成之後配置環境變數
https://graphviz.gitlab.io/_pages/Download/Download_windows.html Failed to execute dot. Is Graphviz installed? Error: exec: "dot": executable file not found in %PATH%
如下圖,展示CPU的在各個方法上的運行時間,關於圖形的說明: 每個框代表一個函數,理論上框的越大表示佔用的CPU資源越多。 方框之間的線條代表函數之間的調用關係。 線條上的數字表示cpu執行時間。 方框中的第一行數字表示當前函數佔用CPU的百分比,第二行數字表示當前函數累計佔用CPU的百分比。

火焰圖
使用火焰圖需要手動安裝Pprof原生工具,這是google提供的一個工具,記住google和Go官方不是一個概念。
go get -u github.com/google/pprof 啟動火焰圖可視化工具
pprof -http=:8080 profile文件名 訪問web地址 localhost:8080,如果上面的命令不加-http=:8080,則默認進入互動式控制台,輸入web命令,生成一個文件自動啟動瀏覽器自動打開,火焰圖明顯比上面Go官方的可視化介面要精緻許多。
如何觀察下面的火焰圖呢?Y軸表示調用棧,每一層都是一個函數,調用棧越深火焰就越高,最底部是正在執行的函數,上面是它的父函數,X軸表示這個函數的抽樣數,如果一個函數在X軸占的越寬,代表抽樣數越高,執行CPU的時間越長,注意,X軸不代表時間,而是所有的調用棧合併後,按字母順序排列的.
火焰圖就是看頂層的哪個函數佔據的寬度最大。只要有"平頂"(plateaus),就表示該函數可能存在性能問題

uber 也開源了一個火焰圖工具,github地址如下,教程很多,大家可以了解了解。
github.com/uber/go-torch,
對非web程式的性能分析
截至目前,上面我們都是對一個web應用程式進行性能檢測分析,用到的都是http介面形式訪問,那麼一個非web程式應該監測性能呢?如果你仔細觀察你會發現性能分析的本質就是對profile文件進行分析,所以我們需要在一個非web應用程式中生成一個profile文件出來,這樣就可以通過go tool pprof工具分析這個文件了
在runtime/pprof 提供了很多方法用來統計程式運行過程中CPU和記憶體的消耗情況,下面我們一起實踐一下。
下面這段程式碼獲取CPU的profile文件,會在當前目錄下生成一個cpu.prof文件,之後我們可以通過go tool prof -http=:8080 cpu.prof 這個命令用瀏覽器來查看cpu的使用情況
func PProfCPUApplication() { f, _ := os.Create("./cpu.prof") pprof.StartCPUProfile(f) for i := 1; i < 3000; i++ { time.Sleep(3 * time.Millisecond) RandomInt(10, 50) } pprof.StopCPUProfile() f.Close() } 下面這段程式碼獲取記憶體的profile文件,會在當前目錄下生成一個mem.prof文件,之後我們可以通過go tool prof -http=:8080 mem.prof 這個命令用瀏覽器來查看記憶體的使用情況
func PProfMemApplication() { f, _ := os.Create("./mem.prof") for i := 1; i < 3000; i++ { time.Sleep(3 * time.Millisecond) RandomInt(10, 50) } pprof.WriteHeapProfile(f) f.Close() } 在如何用好Go的測試黑科技一文中也說到可以用go test在測試時使用指定參數生成CPU和記憶體的profile文件。
go test -bench . -cpuprofile= cpu.prof go test -bench . -memprofile= mem.prof 對Pprof的簡單介紹就到這裡了,有關更多PProf的性能分析大家可以更深入的研究,一起交流。


