一、什么是pprof
pprof是Go官方提供的性能分析工具,可以分析程序的運行情況,并且提供可視化的功能。prof是profile(畫像)的縮寫,使用pprof可以分析以下幾種指標數(shù)據(jù):
-
allocs
:程序啟動之后內(nèi)存分配的情況 -
block
:導致阻塞操作的一些堆棧跟蹤信息 -
cmdline
:當前程序啟動的命令行 -
goroutine
:所有當前goroutine
的堆棧跟蹤信息 -
heap
:程序在當前堆上內(nèi)存分配的情況 -
mutex
:鎖資源的競爭的堆棧信息 -
profile
:CPU profile
文件??梢栽?debug/pprof?seconds=x秒
GET
參數(shù)中指定持續(xù)時間。獲取pprof
文件后,使用go tool pprof x.prof
命令分析pprof
文件。 -
threadcreate
:系統(tǒng)線程的使用情況 -
trace
:當前系統(tǒng)的代碼執(zhí)行的鏈路情況
使用pprof
工具主要分析以下幾種指標:
-
CPU Profiling
:CPU
分析,按照一定的頻率采集所監(jiān)聽的應(yīng)用程序CPU
(含寄存器)的使用情況,可確定應(yīng)用程序在主動消耗CPU
周期時花費時間的位置 -
Memory Profiling
:內(nèi)存分析,在應(yīng)用程序進行堆分配時記錄堆棧跟蹤,用于監(jiān)視當前和歷史內(nèi)存使用情況,以及檢查內(nèi)存泄漏 -
Block Profiling
:阻塞分析,記錄goroutine
阻塞等待同步(包括定時器通道)的位置 -
Mutex Profiling
:互斥鎖分析,報告互斥鎖的競爭情況。
當程序存在內(nèi)存或者CPU
飆升的情況時,我們可以通過pprof
工具來查詢問題出現(xiàn)的根源。
二、怎么使用pprof
pprof包含兩個相關(guān)的庫:
-
runtime/pprof
主要應(yīng)用于工具型應(yīng)用。包含腳本、定時任務(wù)等。
如:對于只跑一次的程序,例如每天只跑一次的離線預(yù)處理程序,調(diào)用 pprof 包提供的函數(shù),手動開啟性能數(shù)據(jù)采集 -
net/http/pprof
主要應(yīng)用于服務(wù)型應(yīng)用。包含HTTP服務(wù),GRPC服務(wù)等。
如:對于在線服務(wù),對于一個 HTTP Server,訪問 pprof 提供的 HTTP 接口,獲得性能數(shù)據(jù)。當然,實際上這里底層也是調(diào)用的runtime/pprof
提供的函數(shù),封裝成接口對外提供網(wǎng)絡(luò)訪問。
1. 工具型應(yīng)用
工具型應(yīng)用主要使用runtime/pprof
包實現(xiàn)性能分析。
func main() {
// --- cpu 分析示例 start---
// 創(chuàng)建cpu分析文件
fc, err := os.Create("./cpu.prof")
if err != nil {
fmt.Println("create cpu.prof err:", err.Error())
return
}
defer fc.Close()
// 開始分析cpu
err = pprof.StartCPUProfile(fc)
if err == nil {
defer pprof.StopCPUProfile()
}
// --- cpu 分析示例 end---
var count int
for i := 0; i < 10000; i++ {
count++
}
// --- 內(nèi)存 分析示例 start---
fm, err := os.Create("./memory.prof")
if err != nil {
fmt.Println("create memory.prof err:", err.Error())
return
}
defer fm.Close()
// 開始分析內(nèi)存
err = pprof.WriteHeapProfile(fm)
if err != nil {
fmt.Println("write heap prof err:", err.Error())
return
}
// --- 內(nèi)存 分析示例 end---
for i := 0; i < 10000; i++ {
count++
}
fmt.Println("do finish......count:", count)
}
執(zhí)行go run main.go
后,在代碼目錄下,可以看到生成了cpu.prof
和memory.prof
文件。
通過執(zhí)行go tool pprof ./memory.prof
或者go tool pprof -http=:8888 ./memory.prof
進入命令行模式或者web頁面進行性能分析。
執(zhí)行go tool pprof ./memory.prof
進入命令行:
執(zhí)行go tool -http=:8888 pprof ./memory.prof
可進入web
頁面,更方便查看:
頁面展示效果:
SAMPLE各個標簽的含義解釋:
2. 服務(wù)型應(yīng)用
對于服務(wù)類型的應(yīng)用,主要在服務(wù)內(nèi)部匿名引入net/http/pprof
包,然后通過HTTP
訪問pprof
頁面。
匿名引入方式為:import _ "net/http/pprof"
package main
import (
"fmt"
"net/http"
_ "net/http/pprof"
)
func main() {
http.HandleFunc("/", hello)
err := http.ListenAndServe(":8080", nil)
if err != nil {
fmt.Println("ListenAndServe Err:", err.Error())
return
}
}
func hello(resp http.ResponseWriter, req *http.Request) {
fmt.Fprintln(resp, "Hello World, Are You OK?")
}
執(zhí)行http://localhost:8080/debug/pprof/
可以看到畫像信息:
但是需要注意,如果HTTP服務(wù)不是通過http.ListenAndServe(":8080", nil)
啟動的,而是指定第二個參數(shù)啟動的話,需要自己注冊pprof
路由。
在net/http/pprof/pprof.go
的官方源碼注釋中也提到此種情況:
If you are not using DefaultServeMux, you will have to register handlers with the mux you are using.
如果您不使用DefaultServeMux,則必須向所使用的多路復(fù)用器注冊pprof處理程序
http.ListenAndServe函數(shù)可以傳遞handler,如果handler不為nil,則說明研發(fā)自定義了 ServeMux,否則用的是默認DefaultServeMux
net/http/pprof
包中,有init
函數(shù)
func init() {
http.HandleFunc("/debug/pprof/", Index)
http.HandleFunc("/debug/pprof/cmdline", Cmdline)
http.HandleFunc("/debug/pprof/profile", Profile)
http.HandleFunc("/debug/pprof/symbol", Symbol)
http.HandleFunc("/debug/pprof/trace", Trace)
}
所以如果使用默認ServeMux
,則不需要注冊,但是如果使用自定義的ServeMux
,則需要增加注冊后,才能獲取到pprof
。
// 自己注冊這幾個函數(shù)
r.HandleFunc("/debug/pprof/", pprof.Index)
r.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline)
r.HandleFunc("/debug/pprof/profile", pprof.Profile)
r.HandleFunc("/debug/pprof/symbol", pprof.Symbol)
r.HandleFunc("/debug/pprof/trace", pprof.Trace)
另外一種啟動pprof
的方式在生產(chǎn)環(huán)境中更加常用:通過協(xié)程另起一個HTTP
服務(wù),單獨用作pprof
分析:
func RegisterProf() {
go func() {
if err := http.ListenAndServe(":6060", nil); err != nil {
panic("pprof server start error: " + err.Error())
}
}()
}
三、pprof數(shù)據(jù)分析
GO
官方提供了go tool pprof
工具來幫助我們分析pprof
生成的數(shù)據(jù)文件。
使用go tool pprof
分析數(shù)據(jù),主要有兩種模式:
- 命令行交互模式
go tool pprof [file_pprof|url_pprof]
- web頁面模式
go tool pprof -http=:6666 [file_pprof|url_pprof]
其中,file_pprof
表示生成的prof
分析文件,如cpu.prof
;url_pprof
表示遠端服務(wù)開啟的pprof
訪問,如http://localhost:8080/debug/pprof/profile
進入命令行交互模式后,可以使用help
查看所有子命令,使用help <cmd|option>
查看子命令使用方法。如 help、help top
等
CPU Profiling
瀏覽器訪問/debug/pprof/profile
會自動進行 CPU profiling
,默認持續(xù) 30s,并生成一個文件供下載,可以通過帶參數(shù)?seconds=60
進行60
秒的數(shù)據(jù)采集。
為了模擬請求,使用ab進行壓測,ab -k -c 1 -t 180 -n 100000000 http://localhost:8080/hello
執(zhí)行go tool pprof http://localhost:8080/debug/pprof/profile
后,默認需要等30s才會顯示交互
top指令排序展示
每一行表示一個函數(shù)的信息,列信息字段解釋:
-
flat
:函數(shù)在 CPU 上運行的時間 -
flat%
:函數(shù)在CPU上運行時間的百分比 -
sum%
:是從第一行到當前行所有函數(shù)累加使用 CPU 的比例,如第二行sum=53.85=30.77+23.08 -
cum
:這個函數(shù)以及子函數(shù)運行所占用的時間,應(yīng)該大于等于flat -
cum%
:這個函數(shù)以及子函數(shù)運行所占用的比例,應(yīng)該大于等于flat% -
最后一列
:函數(shù)的名字
web指令生成圖示
在交互模式下輸入 web,會自動生成一個 svg 文件,并跳轉(zhuǎn)到瀏覽器打開。
改功能需要安裝graphviz后才能使用,安裝方法https://shidawuhen.github.io/2020/02/08/go-callvis/ 。
圖中每個方框?qū)?yīng)應(yīng)用程序運行的一個函數(shù),方框越大代表函數(shù)執(zhí)行的時間越久(函數(shù)執(zhí)行時間會包含它調(diào)用的子函數(shù)的執(zhí)行時間,但并不是正比的關(guān)系);方框之間的箭頭代表著調(diào)用關(guān)系,箭頭上的數(shù)字代表被調(diào)用函數(shù)的執(zhí)行時間。
具體細節(jié)可以參考:https://github.com/google/pprof/tree/master/doc#interpreting-the-callgraph
以runtime netpoll
為例:
箭頭上的230ms
表示該函數(shù)總共的執(zhí)行時間,包含自身和下游所有子節(jié)點;
方框中的10ms
表示自身的執(zhí)行時間;
方框中的2.70%
表示自身執(zhí)行時間在該函數(shù)總共執(zhí)行時間的占比在總時間中的占比:2.70 = (10/230)*62.16
方框中的62.16%
表示總時間占比,即整個程序耗時占比。
list指令分析函數(shù)
確定出哪個函數(shù)耗時之后,可以用pprof
分析函數(shù)中的哪一行導致的耗時,使用子命令:list 函數(shù)名。
堆內(nèi)存分析示例
內(nèi)存分配既可以發(fā)生在堆上也可以在棧上。堆上分配的內(nèi)存需要垃圾回收或者手動回收(對于沒有垃圾回收的語言,例如 C++),棧上的內(nèi)存則通常在函數(shù)退出后自動釋放。
Go 語言通過逃逸分析會將盡可能多的對象分配到棧上,以使程序可以運行地更快。
這里說明一下,有兩種內(nèi)存分析策略:一種是當前的(這一次采集)內(nèi)存或?qū)ο蟮姆峙?,稱為 inuse
;另一種是從程序運行到現(xiàn)在所有的內(nèi)存分配,不管是否已經(jīng)被 gc
過了,稱為 alloc
。
As mentioned above, there are two main memory analysis strategies with pprof. One is around looking at the current allocations (bytes or object count), called inuse. The other is looking at all the allocated bytes or object count throughout the run-time of the program, called alloc. This means regardless if it was gc-ed, a summation of everything sampled.
加上 -sample_index 參數(shù)后,可以切換內(nèi)存分析的類型:go tool pprof -sample_index=alloc_space http://localhost:8080/debug/pprof/heap
或者go tool pprof -alloc_space http://localhost:8080/debug/pprof/heap
四種標簽:文章來源:http://www.zghlxwxcb.cn/news/detail-625193.html
四、pprof數(shù)據(jù)分析類型匯總
其他數(shù)據(jù)的分析和CPU
的基本一致。下面列舉所有的分類:文章來源地址http://www.zghlxwxcb.cn/news/detail-625193.html
http://localhost:8080/debug/pprof/ :獲取概況信息,即本文第一張圖的信息
go tool pprof http://localhost:8080/debug/pprof/allocs : 分析內(nèi)存分配
go tool pprof http://localhost:8080/debug/pprof/block : 分析堆棧跟蹤導致阻塞的同步原語
go tool pprof http://localhost:8080/debug/pprof/cmdline : 分析命令行調(diào)用的程序,web下調(diào)用報錯
go tool pprof http://localhost:8080/debug/pprof/goroutine : 分析當前 goroutine 的堆棧信息
go tool pprof http://localhost:8080/debug/pprof/heap : 分析當前活動對象內(nèi)存分配
go tool pprof http://localhost:8080/debug/pprof/mutex : 分析堆棧跟蹤競爭狀態(tài)互斥鎖的持有者
go tool pprof http://localhost:8080/debug/pprof/profile : 分析一定持續(xù)時間內(nèi)CPU的使用情況
go tool pprof http://localhost:8080/debug/pprof/threadcreate : 分析堆棧跟蹤系統(tǒng)新線程的創(chuàng)建
go tool pprof http://localhost:8080/debug/pprof/trace : 分析追蹤當前程序的執(zhí)行狀況
參考連接
- 一文搞懂pprof
- 深度解密Go語言之 pprof
- go性能分析工具pprof
- Go語言:利用pprof工具排查內(nèi)存泄漏的示例
- Go語言:利用pprof工具查找goroutine(協(xié)程)泄漏的示例
- go 程序性能調(diào)優(yōu) pprof 的使用
到了這里,關(guān)于Go性能分析工具pprof詳解的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!