Go效能分析大殺器PPROF
阿新 • • 發佈:2020-03-09
#### 這是什麼
想要進行效能優化,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來解釋
```go
import (
"net/http"
_ "net/http/pprof"
)
func PprofWeb() {
err := http.ListenAndServe(":9909", nil)
if err != nil {
panic(err)
}
}
```
##### web介面使用
啟動這段程式碼後,訪問 http://localhost:9909/debug/pprof/ ,就可以看到監控頁面了,截圖資訊如下,我們對這些進行一下解釋。
![](https://img2020.cnblogs.com/blog/706455/202003/706455-20200309180635416-602112268.png)
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執行耗時佔比
![](https://img2020.cnblogs.com/blog/706455/202003/706455-20200309180648960-575488134.png)
還有其它很多的命令比如 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的百分比。
![](https://img2020.cnblogs.com/blog/706455/202003/706455-20200309180706323-1530333533.png)
#### 火焰圖
使用火焰圖需要手動安裝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),就表示該函式可能存在效能問題
![](https://img2020.cnblogs.com/blog/706455/202003/706455-20200309180724812-1871863865.png)
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的使用情況
```go
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 這個命令用瀏覽器來檢視記憶體的使用情況
```go
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的效能分析大家可以更深入的研究,一起交流。
![](https://img2018.cnblogs.com/blog/706455/201909/706455-20190911210708072-261554801.jpg)
<