1. 程式人生 > >golang 效能調優分析工具 pprof(下)

golang 效能調優分析工具 pprof(下)

[golang 效能調優分析工具 pprof(上)篇](https://www.cnblogs.com/jiujuan/p/14588185.html), 這是下篇。 ## 四、net/http/pprof ### 4.1 程式碼例子 1 > go version go1.13.9 把上面的程式例子稍微改動下,命名為 demohttp.go: ```go package main import ( "bytes" "fmt" "io/ioutil" "log" "math/rand" "net/http" _ "net/http/pprof" "sync" ) func main() { http.HandleFunc("/pprof-test", handler) fmt.Println("http server start") err := http.ListenAndServe(":8090", nil) if err != nil { log.Fatal(err) } } func handler(resp http.ResponseWriter, req *http.Request) { var wg sync.WaitGroup wg.Add(200) for i := 0; i < 200; i++ { go cyclenum(30000, &wg) } wg.Wait() wb := writeBytes() b, err := ioutil.ReadAll(wb) if err != nil { resp.Write([]byte(err.Error())) return } resp.Write(b) } func cyclenum(num int, wg *sync.WaitGroup) { slice := make([]int, 0) for i := 0; i < num; i++ { for j := 0; j < num; j++ { j = i + j slice = append(slice, j) } } wg.Done() } func writeBytes() *bytes.Buffer { var buff bytes.Buffer for i := 0; i < 30000; i++ { buff.Write([]byte{'a' + byte(rand.Intn(10))}) } return &buff } ``` ### 4.2 開始分析 #### 4.2.1 在 web 介面上分析 先執行上面的 demohttp.go 程式,執行命令: >go run demohttp.go 然後在瀏覽器輸入:[http://localhost:8090/debug/pprof/](http://localhost:8090/debug/pprof/),檢視服務執行情況,如下圖: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181541666-1171115210.png) | 名稱 | url | 說明 | | --- | --- | --- | | allocs | $host/debug/pprof/allocs?debug=1 | 過去所有記憶體抽樣情況 | | block | $host/debug/pprof/block?debug=1 | 同步阻塞時程式棧跟蹤的一些情況 | | heap | $host/debug/pprof/heap?debug=1 | 活動物件的記憶體分配情況 | | mutex | $host/debug/pprof/mutex?debug=1 | 互斥鎖持有者的棧幀情況 | | profile | $host/debug/pprof/profile | cpu profile,點選時會得到一個檔案,然後可以用 go tool pprof 命令進行分析 | | threadcreate | $host/debug/pprof/threadcreate?debug=1 | 建立新 OS 執行緒的堆疊跟蹤情況| | trace | $host/debug/pprof/trace | 當前程式執行的追蹤情況,點選時會得到一個檔案,可以用 go tool trace 命令來分析這個檔案 | 點選上面的連結,就可以檢視具體的分析情況。 不斷重新整理網頁,可以看到資料在不斷變化。 #### 4.2.2 命令列互動分析 在命令列上執行 demohttp.go 程式,執行命令: >go run demohttp.go **A. 分析 cpu profile** 在開啟另外一個命令列終端,執行如下命令: > go tool pprof http://localhost:8090/debug/pprof/profile?seconds=70 ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181600702-127232672.png) 引數 seconds = 70:進行 70s 的資料樣本採集,這個引數可以根據實際情況調整。 上面的命令執行後,會等待 70s , 然後才會進入命令互動介面,如上圖 輸入 `top` 命令: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181615969-2144123551.png) 大家發現沒,其實與上面 runtime/pprof 在命令列互動時是一樣的操作,可以參考上面的欄位引數說明。 找出耗時程式碼部分,也可以用命令:`list`。 在 `top` 命令執行後,發現什麼問題沒?這個 top 命令顯示的資訊都是系統呼叫資訊耗時,沒有使用者定義的函式。為什麼?下面進行分析。 **B. 分析 memory profile** 執行命令: > go tool pprof http://localhost:8090/debug/pprof/heap 然後同樣輸入 `top` 命令檢視函式使用情況,如下圖: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181636344-736191248.png) 其餘的跟蹤分析命令類似,就不一一分析了。 把上面在終端命令列下互動分析的資料進行視覺化分析。 #### 4.2.3 圖形視覺化分析 ##### A. pprof 圖形視覺化 在前面視覺化分析中,我們瞭解到視覺化最重要有 2 步:1.採集資料 2.圖形化採集的資料。 在上面第三節 runtime/pprof 中,進入終端命令列互動操作,然後輸入 web 命令,就可以生成一張 svg 格式的圖片,用瀏覽器可以直接檢視該圖片。我們用同樣的方法來試一試。 1. 輸入命令: >go tool pprof http://localhost:8090/debug/pprof/profile?seconds=30 2. 等待 30s 後輸入 `web` 命令 如下圖: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181654769-298765602.png) 果然生成了一個 svg 檔案,在瀏覽器檢視該圖片檔案,啥有用資訊也沒有,如下圖: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181713771-1008781385.png) 為什麼沒有有用資訊?前面有講到過,沒有使用者訪問 http server ,需要的程式沒有執行,一直阻塞在那裡等待客戶端的訪問連線,所以 go tool pprof 只能採集部分程式碼執行的資訊,而這部分程式碼又沒有消耗多少 cpu。 那怎麼辦? 一個方法就是用 http 測試工具模擬使用者訪問。這裡用 [https://github.com/rakyll/hey](https://github.com/rakyll/hey) 這個工具。 安裝 hey: >go get -u github.com/rakyll/hey 安裝完成後,進行 http 測試: >hey -n 1000 http://localhost:8090/pprof-test 同時開啟另一終端執行命令: >go tool pprof http://localhost:8090/debug/pprof/profile?seconds=120 等待 120s 後,採集資訊完成,如下圖: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181737404-825994524.png) 輸入 `top` 命令檢視統計資訊: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181750407-678718185.png) 可以看到使用者定義的一個最耗時函式是:`main.cyclenum`。如果要檢視這個函式最耗時部分程式碼,可以用 `list cyclenum` 命令檢視。 我們這裡是要生成一張圖片,所以輸入 `web` 命令生成圖片: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181803508-766169522.png) 在瀏覽器上檢視 svg 圖片: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330182343933-1263805848.png) (圖片較大,只截取了部分) 這張圖完整的展示了 `top` 命令的資訊。 ##### B. web 視覺化 執行命令: > go tool pprof -http=":8080" http://localhost:8090/debug/pprof/profile 同時開啟另一終端執行測試命令: > hey -n 200 -q 5 http://localhost:8090/pprof-test 上面 `go tool pprof` 執行完成後,會自動在瀏覽器開啟一個 http 地址,[http://localhost:8080/ui/](http://localhost:8080/ui/),如下圖: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330181955303-144225281.png) (擷取部分圖片) 這樣就可以在web瀏覽器上檢視分析資料了。 ##### C. 火焰圖 用 http 測試框架 [hey](http://github.com/rakyll/hey) 訪問,命令為: > hey -n 200 -q 5 http://localhost:8090/pprof-test 在壓測的同時開啟另一終端執行命令: > go-torch -u http://localhost:8090 來生成火焰圖。 執行命令時在終端輸出了資訊 : >Run pprof command: go tool pprof -raw -seconds 30 http://localhost:8090/debug/pprof/profile 可以看到 `go-torch` 的原始命令也是用到了 `go tool pprof` 上面這個命令預設生成了 torch.svg 的火焰圖檔案,如下: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330182015328-1804123499.png) (擷取一部分圖展示) 點選方塊可以檢視更詳細資訊: ![](https://img2020.cnblogs.com/blog/650581/202103/650581-20210330182028695-762559956.png) ## 參考 - [pprof](https://github.com/google/pprof) - [README](https://github.com/google/pprof/blob/master/doc/README.md) - [Profiling Go Programs](https://blog.golang.org/pprof) - [runtime/pprof](https://golang.org/pkg/runtime/pprof/) - [net/http/pprof](https://golang.org/pkg/net/http/pprof/) - [go-torch](https://github.com/uber-archive/go-torch) - [Flame Graph](https://github.com/brendangregg/FlameGraph) - [http 壓測工具 hey](http://github.com/rak