golang 性能剖析pprof


作為一個golang coder,使用golang編寫代碼是基本的要求。
能夠寫出代碼,並能夠熟悉程序執行過程中各方面的性能指標,則是更上一層樓。

如果在程序出現性能問題的時候,可以快速定位和解決問題,那么寫起代碼來,會更加自信。

本文介紹的pprof,是golang 自帶性能剖析工具,可以幫助定位程序中可能存在的問題。

1.profile文件的收集

pprof使用profile文件進行性能分析,profile文件是應用程序執行狀態的數據。

收集profile文件有兩種方式,對應go 語言提供的 runtime/pprof 和 net/http/pprof 兩個庫。

1.1 runtime/pprof

一般用於應用程序執行一段時間后,就會結束的情況。
例如,進行CPU profiling:

f, err := os.Create(*cpuprofile)
...
pprof.StartCPUProfile(f)
defer pprof.StopCPUProfile()

應用程序啟動時開始收集,應用程序結束后,就生成一個文件。

再例如,進行Mem profiling:

f, err := os.Create(*memprofile)
pprof.WriteHeapProfile(f)
f.Close()

生成一個mem profile文件。

1.2 net/http/pprof

這種方式主要用於程序一直在跑的場景。

如果使用了默認的 http.DefaultServeMux(通常是代碼直接使用 http.ListenAndServe("0.0.0.0:8000", nil)),只需要添加一行:

import _ "net/http/pprof"

如果你使用自定義的 Mux,則需要手動注冊一些路由規則:

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)

不管哪種方式,你的 HTTP 服務都會多出 /debug/pprof endpoint,訪問它會得到類似下面的內容:

/debug/pprof/

profiles:
0    block
62    goroutine
444    heap
30    threadcreate

full goroutine stack dump

下面的演示中,使用的例子代碼如下:

/*simple.go*/

package main

import (
        "log"
        _ "net/http/pprof"
        "net/http"
        "time"
)

func main() {

        go func() {
                log.Println(http.ListenAndServe("localhost:6060", nil))
        }()

        go worker()

        select{}
}

// simple worker
func worker(){

        strSlice := []string{}
        for {
                str := "hello world "
                strSlice = append(strSlice, str)

                time.Sleep(time.Second)
        }

}

代碼開始引入net/http/pprof,在端口6060啟動http服務。

啟動應用程序

go build simple.go

./simpe

2.pprof分析profiling數據

pprof分析profiling數據主要有兩種方式:

  • 交互式終端
  • 頁面顯示

2.1 交互式終端

2.1.1 查看內存使用情況

使用heap profile查看內存使用情況。

go tool pprof http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/lanyang/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Type: inuse_space
Time: Sep 21, 2019 at 1:56pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
(pprof) top10
Showing nodes accounting for 514kB, 100% of 514kB total
      flat  flat%   sum%        cum   cum%
     514kB   100%   100%      514kB   100%  unicode.init
         0     0%   100%      514kB   100%  runtime.doInit
         0     0%   100%      514kB   100%  runtime.main
(pprof)

默認的Type是inuse_space,即常駐內存.
與之對應的是alloc_objects,表示臨時分配的內存。

列出top10的內存占用。

2.1.2 查看CPU使用情況

使用cpu profile查看cpu使用情況。

例如查看過去30s的cpu profile

go tool pprof http://localhost:6060/debug/pprof/profile?seconds=30
Fetching profile over HTTP from http://localhost:6060/debug/pprof/profile?seconds=30
Saved profile in /Users/lanyang/pprof/pprof.samples.cpu.001.pb.gz
Type: cpu
Time: Sep 21, 2019 at 2:19pm (CST)
Duration: 30s, Total samples = 0
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

2.1.3 保存profile文件

從pprof使用上看,是首先保存profile文件,再進行分析的。

在一些場景,例如在線上環境,最好先保存profile,然后拿到線下做分析。

將profile文件保存下來:

wget  http://localhost:6060/debug/pprof/heap
--2019-09-21 15:20:17--  http://localhost:6060/debug/pprof/heap
正在解析主機 localhost (localhost)... ::1, 127.0.0.1
正在連接 localhost (localhost)|::1|:6060... 失敗:Connection refused。
正在連接 localhost (localhost)|127.0.0.1|:6060... 已連接。
已發出 HTTP 請求,正在等待回應... 200 OK
長度:1162 (1.1K) [application/octet-stream]
正在保存至: “heap”

heap                                         100%[============================================================================================>]   1.13K  --.-KB/s  用時 0s

2019-09-21 15:20:17 (111 MB/s) - 已保存 “heap” [1162/1162])

ll
-rw-r--r--  1 lanyang  staff   1.1K  9 21 15:20 heap

然后使用pprof進行分析,其中,./simple是可執行文件,用於解析各種符號,./heap是剛才獲取到的profile文件。

go tool pprof ./simple ./heap
Type: inuse_space
Time: Sep 21, 2019 at 3:20pm (CST)
No samples were found with the default sample value type.
Try "sample_index" command to analyze different sample values.
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)

2.2 頁面顯示

2.2.1 瀏覽器打開pprof頁面

瀏覽器中打開http://localhost:6060/debug/pprof/
如圖所示,列出了很多監控項,
在這里插入圖片描述

 Profile Descriptions:

allocs:
A sampling of all past memory allocations

block:
Stack traces that led to blocking on synchronization primitives

cmdline:
The command line invocation of the current program

goroutine:
Stack traces of all current goroutines

heap:
A sampling of memory allocations of live objects. You can specify the gc GET parameter to run GC before taking the heap sample.

mutex:
Stack traces of holders of contended mutexes

profile:
CPU profile. You can specify the duration in the seconds GET parameter. After you get the profile file, use the go tool pprof command to investigate the profile.

threadcreate:
Stack traces that led to the creation of new OS threads

trace:
A trace of execution of the current program. You can specify the duration in the seconds GET parameter. After you get the trace file, use the go tool trace command to investigate the trace.

可以通過鏈接跳轉到對應界面。

2.2.2. 更詳細的頁面顯示

go 從1.11開始的pprof提供了更豐富性能數據展示方式,包括火焰圖,直接使用如下命令:

$ go tool pprof -http=":8081" [binary] [profile]

會打開瀏覽器頁面。
端口可以自己選擇,這里使用了8081。
binary是應用程序的可執行文件,讀取符號信息。
profile 是profile文件,可以是本地文件,或者http地址。

例如,使用本地保存的profile文件:

$ go tool pprof -http=":8081" ./simple ./heap

或者,通過http 的profile:

go tool pprof -http=":8081" ./simple  http://localhost:6060/debug/pprof/heap
Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap
Saved profile in /Users/zhangyunyang/pprof/pprof.simple.alloc_objects.alloc_space.inuse_objects.inuse_space.001.pb.gz
Serving web UI on http://localhost:8081

火焰圖如圖所示,示例代碼比較簡單,所以火焰圖不是很明顯。
在這里插入圖片描述

如果不能使用go1.11,則可以使用最新的pprof工具:

# Get the pprof tool directly
$ go get -u github.com/google/pprof

$ pprof -http=":8081" [binary] [profile]

3.參考

Package pprof

使用 pprof 和火焰圖調試 golang 應用

Profiling Go Programs

go-torch


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM