Go性能分析大殺器PPROF

這是什麼

想要進行性能優化,Go本身自帶的工具鏈就包含了性能分析工具,而且也非常棒,pprof就是Go性能分析的利器,它是Go語言自帶的包,有如下兩種:

  1. runtime/pprof:採集程式(非 Server)的運行數據進行分析
  2. 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的性能分析大家可以更深入的研究,一起交流。

Tags: