golang 性能調優分析工具 pprof(上)篇, 這是下篇。html
go version go1.13.9git
把上面的程序例子稍微改動下,命名爲 demohttp.go:github
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 }
先運行上面的 demohttp.go 程序,執行命令:golang
go run demohttp.goweb
而後在瀏覽器輸入:http://localhost:8090/debug/pprof/,查看服務運行狀況,以下圖:瀏覽器
名稱 | 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 命令來分析這個文件 |
點擊上面的連接,就能夠查看具體的分析狀況。
不斷刷新網頁,能夠看到數據在不斷變化。app
在命令行上運行 demohttp.go 程序,執行命令:框架
go run demohttp.gosvg
A. 分析 cpu profile函數
在開啓另一個命令行終端,執行以下命令:
go tool pprof http://localhost:8090/debug/pprof/profile?seconds=70
參數 seconds = 70:進行 70s 的數據樣本採集,這個參數能夠根據實際狀況調整。
上面的命令執行後,會等待 70s , 而後纔會進入命令交互界面,如上圖
輸入 top
命令:
你們發現沒,其實與上面 runtime/pprof 在命令行交互時是同樣的操做,能夠參考上面的字段參數說明。
找出耗時代碼部分,也能夠用命令:list
。
在 top
命令執行後,發現什麼問題沒?這個 top 命令顯示的信息都是系統調用信息耗時,沒有用戶定義的函數。爲何?下面進行分析。
B. 分析 memory profile
執行命令:
go tool pprof http://localhost:8090/debug/pprof/heap
而後一樣輸入 top
命令查看函數使用狀況,以下圖:
其他的跟蹤分析命令相似,就不一一分析了。
把上面在終端命令行下交互分析的數據進行可視化分析。
在前面可視化分析中,咱們瞭解到可視化最重要有 2 步:1.採集數據 2.圖形化採集的數據。
在上面第三節 runtime/pprof 中,進入終端命令行交互操做,而後輸入 web 命令,就能夠生成一張 svg 格式的圖片,用瀏覽器能夠直接查看該圖片。咱們用一樣的方法來試一試。
go tool pprof http://localhost:8090/debug/pprof/profile?seconds=30
web
命令以下圖:
果真生成了一個 svg 文件,在瀏覽器查看該圖片文件,啥有用信息也沒有,以下圖:
爲何沒有有用信息?前面有講到過,沒有用戶訪問 http server ,須要的程序沒有運行,一直阻塞在那裏等待客戶端的訪問鏈接,因此 go tool pprof 只能採集部分代碼運行的信息,而這部分代碼又沒有消耗多少 cpu。
那怎麼辦?
一個方法就是用 http 測試工具模擬用戶訪問。這裏用 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 後,採集信息完成,以下圖:
輸入 top
命令查看統計信息:
能夠看到用戶定義的一個最耗時函數是:main.cyclenum
。若是要查看這個函數最耗時部分代碼,能夠用 list cyclenum
命令查看。
咱們這裏是要生成一張圖片,因此輸入 web
命令生成圖片:
在瀏覽器上查看 svg 圖片:
(圖片較大,只截取了部分)
這張圖完整的展現了 top
命令的信息。
執行命令:
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/,以下圖:
(截取部分圖片)
這樣就能夠在web瀏覽器上查看分析數據了。
用 http 測試框架 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 的火焰圖文件,以下:
(截取一部分圖展現)
點擊方塊能夠查看更詳細信息: