精品欧美一区二区三区在线观看 _久久久久国色av免费观看性色_国产精品久久在线观看_亚洲第一综合网站_91精品又粗又猛又爽_小泽玛利亚一区二区免费_91亚洲精品国偷拍自产在线观看 _久久精品视频在线播放_美女精品久久久_欧美日韩国产成人在线

Go 程序崩了?煎魚教你用 PProf 工具來救火!

開發(fā) 開發(fā)工具
在本文中我們詳細(xì)的介紹了 Go 語言中 pprof 的使用,針對一些常用的套件均進(jìn)行了說明。而 pprof 在我們平時的性能剖析,問題排查上都占據(jù)著非常重要的角色。

 [[396774]]

本文轉(zhuǎn)載自微信公眾號「腦子進(jìn)煎魚了」,作者陳煎魚。轉(zhuǎn)載本文請聯(lián)系腦子進(jìn)煎魚了公眾號。

前言

應(yīng)用程序在運(yùn)行時,總是會出現(xiàn)一些你所意料不到的問題,像是跑著跑著突然報警,監(jiān)控提示你進(jìn)程 CPU 使用率過高、內(nèi)存占用不斷增大(疑似泄露)、臨時內(nèi)存大量申請后長時間內(nèi)不滑,又或是 Goroutine 泄露、出現(xiàn) Goroutine 數(shù)量暴漲,并且持續(xù)保持,甚至是莫名其妙在某次迭代發(fā)布后的數(shù)小時內(nèi)出現(xiàn)了應(yīng)用程序無法提供服務(wù)的問題...

這發(fā)生起來的話,是多么的讓人感到擔(dān)憂,那么除了在我們平時要做好各類防護(hù)以外,在問題正在發(fā)生時,我們又有什么辦法排查呢,因此在這個章節(jié),我們將介紹排查辦法之一,也就是 Go 語言的性能剖析大殺器 PProf 工具鏈,它是 Go 語言中必知必會的技能點(diǎn)。

PProf 是什么

在 Go 語言中,PProf 是用于可視化和分析性能分析數(shù)據(jù)的工具,PProf 以 profile.proto 讀取分析樣本的集合,并生成報告以可視化并幫助分析數(shù)據(jù)(支持文本和圖形報告)。

而剛剛提到的 profile.proto 是一個 Protobuf v3 的描述文件,它描述了一組 callstack 和 symbolization 信息, 作用是統(tǒng)計分析的一組采樣的調(diào)用棧,是很常見的 stacktrace 配置文件格式。

有哪幾種采樣方式

  • runtime/pprof:采集程序(非 Server)的指定區(qū)塊的運(yùn)行數(shù)據(jù)進(jìn)行分析。
  • net/http/pprof:基于HTTP Server運(yùn)行,并且可以采集運(yùn)行時數(shù)據(jù)進(jìn)行分析。
  • go test:通過運(yùn)行測試用例,并指定所需標(biāo)識來進(jìn)行采集。

支持什么使用模式

  • Report generation:報告生成。
  • Interactive terminal use:交互式終端使用。
  • Web interface:Web 界面。

可以做什么

  • CPU Profiling:CPU 分析,按照一定的頻率采集所監(jiān)聽的應(yīng)用程序 CPU(含寄存器)的使用情況,可確定應(yīng)用程序在主動消耗 CPU 周期時花費(fèi)時間的位置。
  • Memory Profiling:內(nèi)存分析,在應(yīng)用程序進(jìn)行堆分配時記錄堆棧跟蹤,用于監(jiān)視當(dāng)前和歷史內(nèi)存使用情況,以及檢查內(nèi)存泄漏。
  • Block Profiling:阻塞分析,記錄Goroutine阻塞等待同步(包括定時器通道)的位置,默認(rèn)不開啟,需要調(diào)用runtime.SetBlockProfileRate進(jìn)行設(shè)置。
  • Mutex Profiling:互斥鎖分析,報告互斥鎖的競爭情況,默認(rèn)不開啟,需要調(diào)用runtime.SetMutexProfileFraction進(jìn)行設(shè)置。
  • Goroutine Profiling:Goroutine 分析,可以對當(dāng)前應(yīng)用程序正在運(yùn)行的 Goroutine 進(jìn)行堆棧跟蹤和分析。

其中像是 Goroutine Profiling 這項(xiàng)功能會在實(shí)際排查中會經(jīng)常用到。

因?yàn)楹芏鄦栴}出現(xiàn)時的表象就是 Goroutine 暴增,而這時候我們要做的事情之一就是查看應(yīng)用程序中的 Goroutine 正在做什么事情,因?yàn)槭裁醋枞耍缓笤龠M(jìn)行下一步。

介紹和使用

一個簡單的例子

我們新建一個 main.go 文件,用于后續(xù)的應(yīng)用程序分析和示例展示,寫入如下代碼:

  1. var datas []string 
  2.  
  3. func main() { 
  4.  go func() { 
  5.   for { 
  6.    log.Printf("len: %d"Add("go-programming-tour-book")) 
  7.    time.Sleep(time.Millisecond * 10) 
  8.   } 
  9.  }() 
  10.  
  11.  _ = http.ListenAndServe("0.0.0.0:6060", nil) 
  12.  
  13. func Add(str string) int { 
  14.  data := []byte(str) 
  15.  datas = append(datas, string(data)) 
  16.  return len(datas) 

接下來最重要的一步,就是在 import 中添加 _ "net/http/pprof" 的引用,如下:

  1. import ( 
  2.  _ "net/http/pprof" 
  3.  ... 

接下來我們運(yùn)行這個程序,訪問 http://127.0.0.1:6060/debug/pprof/ 地址,檢查是否正常響應(yīng)。

通過瀏覽器訪問

第一種方式,我們可以直接通過瀏覽器,進(jìn)行查看,那么在第一步我們可以先查看總覽頁面,也就是訪問 http://127.0.0.1:6060/debug/pprof/,如下:

  1. /debug/pprof/ 
  2.  
  3. Types of profiles available: 
  4. Count Profile 
  5. 3 allocs 
  6. 0 block 
  7. 0 cmdline 
  8. 8 goroutine 
  9. 3 heap 
  10. 0 mutex 
  11. 0 profile 
  12. 11 threadcreate 
  13. 0 trace 
  14. full goroutine stack dump 
  • allocs:查看過去所有內(nèi)存分配的樣本,訪問路徑為$HOST/debug/pprof/allocs。
  • block:查看導(dǎo)致阻塞同步的堆棧跟蹤,訪問路徑為$HOST/debug/pprof/block。
  • cmdline:當(dāng)前程序的命令行的完整調(diào)用路徑。
  • goroutine:查看當(dāng)前所有運(yùn)行的 goroutines 堆棧跟蹤,訪問路徑為$HOST/debug/pprof/goroutine。
  • heap:查看活動對象的內(nèi)存分配情況, 訪問路徑為$HOST/debug/pprof/heap。
  • mutex:查看導(dǎo)致互斥鎖的競爭持有者的堆棧跟蹤,訪問路徑為$HOST/debug/pprof/mutex。
  • profile:默認(rèn)進(jìn)行 30s 的 CPU Profiling,得到一個分析用的 profile 文件,訪問路徑為$HOST/debug/pprof/profile。
  • threadcreate:查看創(chuàng)建新OS線程的堆棧跟蹤,訪問路徑為$HOST/debug/pprof/threadcreate。

如果你在對應(yīng)的訪問路徑上新增 ?debug=1 的話,就可以直接在瀏覽器訪問,如下:

debug 模式

若不新增 debug 參數(shù),那么將會直接下載對應(yīng)的profile文件。

再展開來講,在部署環(huán)境中,我們?yōu)榱司W(wǎng)絡(luò)安全,通常不會直接對外網(wǎng)暴露 pprof 的相關(guān)端口,因此會通過 curl、wget 等方式進(jìn)行 profile 文件的間接拉取。

另外還有一點(diǎn)需要注意,debug 的訪問方式是具有時效性的,在實(shí)際場景中,我們常常需要及時將當(dāng)前狀態(tài)下的 profile 文件給存儲下來,便于二次分析。

通過交互式終端使用

第二種方式,我們可以直接通過命令行,來完成對正在運(yùn)行的應(yīng)用程序 pprof 的抓取和分析。

CPU Profiling

  1. $ go tool pprof http://localhost:6060/debug/pprof/profile\?seconds\=60 
  2. Fetching profile over HTTP from http://localhost:6060/debug/pprof/profile?seconds=60 
  3. Saved profile in /Users/eddycjy/pprof/pprof.samples.cpu.002.pb.gz 
  4. Type: cpu 
  5. Duration: 1mins, Total samples = 37.25s (61.97%) 
  6. Entering interactive mode (type "help" for commands, "o" for options) 
  7. (pprof) 

執(zhí)行該命令后,需等待 60 秒(可調(diào)整 seconds 的值),pprof 會進(jìn)行 CPU Profiling,結(jié)束后將默認(rèn)進(jìn)入 pprof 的命令行交互式模式,可以對分析的結(jié)果進(jìn)行查看或?qū)С觥A硗馊绻闼鶈拥?HTTP Server 是 TLS 的方式,那么在調(diào)用 go tool pprof 時,需要將調(diào)用路徑改為:go tool pprof https+insecure://localhost:6060/debug/pprof/profile\?seconds\=60。

接下來我們輸入查詢命令 top10 ,以此查看對應(yīng)資源開銷(例如:CPU 就是執(zhí)行耗時/開銷、Memory 就是內(nèi)存占用大小)排名前十的函數(shù),如下:

  1. (pprof) top10 
  2. Showing nodes accounting for 36.23s, 97.26% of 37.25s total 
  3. Dropped 80 nodes (cum <= 0.19s) 
  4. Showing top 10 nodes out of 34 
  5.       flat  flat%   sum%        cum   cum%  Name 
  6.     32.63s 87.60% 87.60%     32.70s 87.79%  syscall.syscall 
  7.      0.87s  2.34% 89.93%      0.88s  2.36%  runtime.stringtoslicebyte 
  8.      0.69s  1.85% 91.79%      0.69s  1.85%  runtime.memmove 
  9.      0.52s  1.40% 93.18%      0.52s  1.40%  runtime.nanotime 
  10.      ... 
  11. (pprof)  
  • flat:函數(shù)自身的運(yùn)行耗時。
  • flat%:函數(shù)自身在 CPU 運(yùn)行耗時總比例。
  • sum%:函數(shù)自身累積使用 CPU 總比例。
  • cum:函數(shù)自身及其調(diào)用函數(shù)的運(yùn)行總耗時。
  • cum%:函數(shù)自身及其調(diào)用函數(shù)的運(yùn)行耗時總比例。
  • Name:函數(shù)名。

在大多數(shù)的情況下,我們可以通過這五列得出一個應(yīng)用程序的運(yùn)行情況,知道當(dāng)前是什么函數(shù),正在做什么事情,占用了多少資源,誰又是占用資源的大頭,以此來得到一個初步的分析方向。

另外在交互命令行中,pprof 還支持了大量的其它命令,具體可執(zhí)行 pprof help 查看幫助說明。

Heap Profiling

  1. $ go tool pprof http://localhost:6060/debug/pprof/heap 
  2. Fetching profile over HTTP from http://localhost:6060/debug/pprof/heap 
  3. Saved profile in /Users/eddycjy/pprof/pprof.alloc_objects.alloc_space.inuse_objects.inuse_space.011.pb.gz 
  4. Type: inuse_space 
  5. Entering interactive mode (type "help" for commands, "o" for options) 
  6. (pprof) 

執(zhí)行該命令后,能夠很快的拉取到其結(jié)果,因?yàn)樗恍枰?CPU Profiling 做采樣等待,這里需要注意的一點(diǎn)是 Type 這一個選項(xiàng),你可以看到它默認(rèn)顯示的是 inuse_space,實(shí)際上可以針對多種內(nèi)存概況進(jìn)行分析,常用的類別如下:

  • inuse_space:分析應(yīng)用程序的常駐內(nèi)存占用情況。
  1. $ go tool pprof -inuse_space http://localhost:6060/debug/pprof/heap 
  2. (pprof) top 
  3. Showing nodes accounting for 4.01GB, 100% of 4.01GB total 
  4.       flat  flat%   sum%        cum   cum% 
  5.     4.01GB   100%   100%     4.01GB   100%  main.Add 
  6.          0     0%   100%     4.01GB   100%  main.main.func1 
  • alloc_objects:分析應(yīng)用程序的內(nèi)存臨時分配情況。
  1. $ go tool pprof -alloc_objects http://localhost:6060/debug/pprof/heap 
  2. (pprof) top 
  3. Showing nodes accounting for 215552550, 100% of 215560746 total 
  4. Dropped 14 nodes (cum <= 1077803) 
  5.       flat  flat%   sum%        cum   cum% 
  6.   86510197 40.13% 40.13%   86510197 40.13%  main.Add 
  7.   85984544 39.89% 80.02%   85984544 39.89%  fmt.Sprintf 
  8.   43057809 19.97%   100%  215552550   100%  main.main.func1 
  9.          0     0%   100%   85984544 39.89%  log.Printf 

另外還有 inuse_objects 和 alloc_space 類別,分別對應(yīng)查看每個函數(shù)所分別的對象數(shù)量和查看分配的內(nèi)存空間大小,具體可根據(jù)情況選用。

Goroutine Profiling

  1. $ go tool pprof http://localhost:6060/debug/pprof/goroutine 
  2. Fetching profile over HTTP from http://localhost:6060/debug/pprof/goroutine 
  3. Saved profile in /Users/eddycjy/pprof/pprof.goroutine.003.pb.gz 
  4. Type: goroutine 
  5. Entering interactive mode (type "help" for commands, "o" for options) 
  6. (pprof)  

在查看 goroutine 時,我們可以使用traces命令,這個命令會打印出對應(yīng)的所有調(diào)用棧,以及指標(biāo)信息,可以讓我們很便捷的查看到整個調(diào)用鏈路有什么,分別在哪里使用了多少個 goroutine,并且能夠通過分析查看到誰才是真正的調(diào)用方,輸出結(jié)果如下:

  1. (pprof) traces 
  2. Type: goroutine 
  3. -----------+------------------------------------------------------- 
  4.          2   runtime.gopark 
  5.              runtime.netpollblock 
  6.              internal/poll.runtime_pollWait 
  7.              ... 
  8. -----------+------------------------------------------------------- 
  9.          1   runtime.gopark 
  10.              runtime.netpollblock 
  11.              ... 
  12.              net/http.ListenAndServe 
  13.              main.main 
  14.              runtime.main 

在調(diào)用棧上來講,其展示順序是自下而上的,也就是 runtime.main 方法調(diào)用了 main.main 方法,main.main 方法又調(diào)用了 net/http.ListenAndServe 方法,這里對應(yīng)的也就是我們所使用的示例代碼了,排查起來會非常方便。

每個調(diào)用堆棧信息用 ----------- 分割,函數(shù)方法前的就是指標(biāo)數(shù)據(jù),像 Goroutine Profiling 展示是就是該方法占用的 goroutine 的數(shù)量。而 Heap Profiling 展示的就是占用的內(nèi)存大小,如下:

  1. $ go tool pprof http://localhost:6060/debug/pprof/heap 
  2. ... 
  3. Type: inuse_space 
  4. Entering interactive mode (type "help" for commands, "o" for options) 
  5. (pprof) traces 
  6. Type: inuse_space 
  7. -----------+------------------------------------------------------- 
  8.      bytes:  13.55MB 
  9.    13.55MB   main.Add 
  10.              main.main.func1 
  11. -----------+------------------------------------------------------- 

實(shí)際上 pprof 中的所有功能都會根據(jù)不同的 Profile 類型展示不同的對應(yīng)結(jié)果。

Mutex Profiling

怎么樣的情況下會造成阻塞呢,一般有如下方式:調(diào)用 chan(通道)、調(diào)用 sync.Mutex (同步鎖)、調(diào)用 time.Sleep() 等等。那么為了驗(yàn)證互斥鎖的競爭持有者的堆棧跟蹤,我們可以根據(jù)以上的 sync.Mutex 方式,來調(diào)整先前的示例代碼,代碼如下:

  1. func init() { 
  2.  runtime.SetMutexProfileFraction(1) 
  3.  
  4. func main() { 
  5.  var m sync.Mutex 
  6.  var datas = make(map[int]struct{}) 
  7.  for i := 0; i < 999; i++ { 
  8.   go func(i int) { 
  9.    m.Lock() 
  10.    defer m.Unlock() 
  11.    datas[i] = struct{}{} 
  12.   }(i) 
  13.  } 
  14.  
  15.  _ = http.ListenAndServe(":6061", nil) 

需要特別注意的是 runtime.SetMutexProfileFraction 語句,如果未來希望進(jìn)行互斥鎖的采集,那么需要通過調(diào)用該方法來設(shè)置采集頻率,若不設(shè)置或沒有設(shè)置大于 0 的數(shù)值,默認(rèn)是不進(jìn)行采集的。

接下來我們進(jìn)行調(diào)用 go tool pprof 進(jìn)行分析,如下:

  1. $ go tool pprof http://localhost:6061/debug/pprof/mutex 
  2. Fetching profile over HTTP from http://localhost:6061/debug/pprof/mutex 
  3. Saved profile in /Users/eddycjy/pprof/pprof.contentions.delay.010.pb.gz 
  4. Type: delay 
  5. Entering interactive mode (type "help" for commands, "o" for options) 

我們查看調(diào)用 top 命令,查看互斥量的排名:

  1. (pprof) top 
  2. Showing nodes accounting for 653.79us, 100% of 653.79us total 
  3.       flat  flat%   sum%        cum   cum% 
  4.   653.79us   100%   100%   653.79us   100%  sync.(*Mutex).Unlock 
  5.          0     0%   100%   653.79us   100%  main.main.func1 

接下來我們可以調(diào)用 list 命令,看到指定函數(shù)的代碼情況(包含特定的指標(biāo)信息,例如:耗時),若函數(shù)名不明確,默認(rèn)會對函數(shù)名進(jìn)行模糊匹配,如下:

  1. (pprof) list main 
  2. Total: 653.79us 
  3. ROUTINE ======================== main.main.func1 in /eddycjy/main.go 
  4.          0   653.79us (flat, cum)   100% of Total 
  5.          .          .     40:  go func(i int) { 
  6.          .          .     41:   m.Lock() 
  7.          .          .     42:   defer m.Unlock() 
  8.          .          .     43: 
  9.          .          .     44:   datas[i] = struct{}{} 
  10.          .   653.79us     45:  }(i) 
  11.          .          .     46: } 
  12.          .          .     47: 
  13.          .          .     48: err := http.ListenAndServe(":6061", nil) 
  14.          .          .     49: if err != nil { 
  15.          .          .     50:  log.Fatalf("http.ListenAndServe err: %v", err) 
  16. (pprof)  

我們可以在輸出的分析中比較準(zhǔn)確的看到引起互斥鎖的函數(shù)在哪里,鎖開銷在哪里,在本例中是第 45 行。

Block Profiling

與 Mutex 的 runtime.SetMutexProfileFraction 相似,Block 也需要調(diào)用 runtime.SetBlockProfileRate() 進(jìn)行采集量的設(shè)置,否則默認(rèn)關(guān)閉,若設(shè)置的值小于等于 0 也會認(rèn)為是關(guān)閉。

與上小節(jié) Mutex 相比,主體代碼不變,僅是新增 runtime.SetBlockProfileRate() 的調(diào)用,如下:

  1. func init() { 
  2.  runtime.SetBlockProfileRate(1) 
  3.  ... 

我們查看調(diào)用 top 命令,查看阻塞情況的排名:

  1. $ go tool pprof http://localhost:6061/debug/pprof/block 
  2. Fetching profile over HTTP from http://localhost:6061/debug/pprof/block 
  3. Saved profile in /Users/eddycjy/pprof/pprof.contentions.delay.017.pb.gz 
  4. Type: delay 
  5. Entering interactive mode (type "help" for commands, "o" for options) 
  6. (pprof) top 
  7. Showing nodes accounting for 74.54ms, 100% of 74.54ms total 
  8.       flat  flat%   sum%        cum   cum% 
  9.    74.54ms   100%   100%    74.54ms   100%  sync.(*Mutex).Lock 
  10.          0     0%   100%    74.54ms   100%  main.main.func1 

同樣的,我們也可以調(diào)用 list 命令查看具體的阻塞情況,執(zhí)行方式和排查模式與先前概述的一致。

查看可視化界面

接下來我們繼續(xù)使用前面的示例程序,將其重新運(yùn)行起來,然后在其它窗口執(zhí)行下述命令:

  1. $ wget http://127.0.0.1:6060/debug/pprof/profile    

默認(rèn)需要等待 30 秒,執(zhí)行完畢后可在當(dāng)前目錄下發(fā)現(xiàn)采集的文件 profile,針對可視化界面我們有兩種方式可進(jìn)行下一步分析:

方法一(推薦):該命令將在所指定的端口號運(yùn)行一個 PProf 的分析用的站點(diǎn)。

  1. $ go tool pprof -http=:6001 profile  

方法二:通過 web 命令將以 svg 的文件格式寫入圖形,然后在 Web 瀏覽器中將其打開。

  1. $ go tool pprof profile 
  2. Type: cpu 
  3. Time: Feb 1, 2020 at 12:09pm (CST) 
  4. Duration: 30s, Total samples = 60ms (  0.2%) 
  5. Entering interactive mode (type "help" for commands, "o" for options) 
  6. (pprof) web 

如果出現(xiàn)錯誤提示 Could not execute dot; may need to install graphviz.,那么意味著你需要安裝 graphviz組件。

另外方法一所運(yùn)行的站點(diǎn),實(shí)際上包含了方法二的內(nèi)容(svg圖片),并且更靈活,因此非特殊情況,我們會直接使用方法一的方式運(yùn)行站點(diǎn)來做觀察和分析。

剖析內(nèi)容

通過 PProf 所提供的可視化界面,我們能夠更方便、更直觀的看到 Go 應(yīng)用程序的調(diào)用鏈、使用情況等。另外在 View 菜單欄中,PProf 還支持多種分析方式的切換,如下:

view 菜單欄

接下來我們將基于 CPU Profiling 所抓取的 Profile 進(jìn)行一一介紹,而其它 Profile 類型的分析模式也是互通的,只要我們了解了一種,其余的也就會了。

Top

top 欄目

該視圖與前面所講解的 top 子命令的作用和含義是一樣的,因此不再贅述。

Graph

graph 欄目

該視圖展示的為整體的函數(shù)調(diào)用流程,框越大、線越粗、框顏色越鮮艷(紅色)就代表它占用的時間越久,開銷越大。相反若框顏色越淡,越小則代表在整體的函數(shù)調(diào)用流程中,它的開銷是相對較小的。

因此我們可以用此視圖去分析誰才是開銷大頭,它又是因?yàn)槭裁凑{(diào)用流程而被調(diào)用的。

Peek

peek 欄目

此視圖相較于 Top 視圖,增加了所屬的上下文信息的展示,也就是函數(shù)的輸出調(diào)用者/被調(diào)用者。

Source

source 欄目

該視圖主要是增加了面向源代碼的追蹤和分析,可以看到其開銷主要消耗在哪里。

Flame Graph

flame graph 概覽

Flame Graph(火焰圖)它是可動態(tài)的,調(diào)用順序由上到下(A -> B -> C -> D),每一塊代表一個函數(shù)、顏色越鮮艷(紅)、區(qū)塊越大代表占用 CPU 的時間更長。同時它也支持點(diǎn)擊塊深入進(jìn)行分析。

我們選擇頁面上的 main.main.func1 區(qū)塊,將會進(jìn)入到其屬下的下一層級,如下:

進(jìn)一步查看 flame graph

這樣子我們就可以根據(jù)不同函數(shù)的多維度層級進(jìn)行分析,能夠更好的觀察其流轉(zhuǎn)并發(fā)現(xiàn)問題。

通過測試用例做剖析

在上述章節(jié)中,我們是通過在應(yīng)用程序中埋入方法進(jìn)行采集的,那么還有一種方式,能夠更精準(zhǔn)的剖析到你所想要分析的流程或函數(shù)。

首先我們將先前所編寫的 Add 方法挪到獨(dú)立的 package 中,命名為 add.go 文件,然后新建 add_test.go 文件,寫入如下測試用例代碼:

  1. func TestAdd(t *testing.T) { 
  2.  _ = Add("go-programming-tour-book"
  3.  
  4. func BenchmarkAdd(b *testing.B) { 
  5.  for i := 0; i < b.N; i++ { 
  6.   Add("go-programming-tour-book"
  7.  } 

在完成代碼編寫后,我們回到命令行窗口執(zhí)行如下采集命令:

  1. $ go test -bench=. -cpuprofile=cpu.profile 

執(zhí)行完畢后會在當(dāng)前命令生成 cpu.profile 文件,然后只需執(zhí)行 go tool pprof 命令就可以進(jìn)行查看了,如下圖:

cpu profile

另外除了對 CPU 進(jìn)行剖析以外,我們還可以調(diào)整選項(xiàng),對內(nèi)存情況進(jìn)行分析,如下采集命令:

  1. $ go test -bench=. -memprofile=mem.profile 

接下來和上面一樣,執(zhí)行 go tool pprof 命令進(jìn)行查看,如下圖:

進(jìn)一步查看

通過 Lookup 寫入文件做剖析

除了注入 http handler 和 go test 以外,我們還可以在程序中通過 pprof 所提供的 Lookup 方法來進(jìn)行相關(guān)內(nèi)容的采集和調(diào)用。

其一共支持六種類型,分別是:

  • goroutine。
  • threadcreate。
  • heap。
  • block。
  • mutex。

具體代碼如下:

  1. type LookupType int8 
  2.  
  3. const ( 
  4.  LookupGoroutine LookupType = iota 
  5.  LookupThreadcreate 
  6.  LookupHeap 
  7.  LookupAllocs 
  8.  LookupBlock 
  9.  LookupMutex 
  10.  
  11. func pprofLookup(lookupType LookupType, w io.Writer) error { 
  12.  var err error 
  13.  switch lookupType { 
  14.  case LookupGoroutine: 
  15.   p := pprof.Lookup("goroutine"
  16.   err = p.WriteTo(w, 2) 
  17.  case LookupThreadcreate: 
  18.   p := pprof.Lookup("threadcreate"
  19.   err = p.WriteTo(w, 2) 
  20.  case LookupHeap: 
  21.   p := pprof.Lookup("heap"
  22.   err = p.WriteTo(w, 2) 
  23.  case LookupAllocs: 
  24.   p := pprof.Lookup("allocs"
  25.   err = p.WriteTo(w, 2) 
  26.  case LookupBlock: 
  27.   p := pprof.Lookup("block"
  28.   err = p.WriteTo(w, 2) 
  29.  case LookupMutex: 
  30.   p := pprof.Lookup("mutex"
  31.   err = p.WriteTo(w, 2) 
  32.  } 
  33.  
  34.  return err 

接下來我們只需要對該方法進(jìn)行調(diào)用就好了,其提供了 io.Writer 接口,也就是只要實(shí)現(xiàn)了對應(yīng)的 Write 方法,我們可以將其寫到任何支持地方去,如下:

  1. ... 
  2. func init() { 
  3.  runtime.SetMutexProfileFraction(1) 
  4.  runtime.SetBlockProfileRate(1) 
  5.  
  6. func main() { 
  7.  http.HandleFunc("/lookup/heap", func(w http.ResponseWriter, r *http.Request) { 
  8.   _ = pprofLookup(LookupHeap, os.Stdout) 
  9.  }) 
  10.  http.HandleFunc("/lookup/threadcreate", func(w http.ResponseWriter, r *http.Request) { 
  11.   _ = pprofLookup(LookupThreadcreate, os.Stdout) 
  12.  }) 
  13.  http.HandleFunc("/lookup/block", func(w http.ResponseWriter, r *http.Request) { 
  14.   _ = pprofLookup(LookupBlock, os.Stdout) 
  15.  }) 
  16.  http.HandleFunc("/lookup/goroutine", func(w http.ResponseWriter, r *http.Request) { 
  17.   _ = pprofLookup(LookupGoroutine, os.Stdout) 
  18.  }) 
  19.  _ = http.ListenAndServe("0.0.0.0:6060", nil) 

在上述代碼中,我們將采集結(jié)果寫入到了控制臺上,我們可以進(jìn)行一下驗(yàn)證,調(diào)用 http://127.0.0.1:6060/lookup/heap,控制臺輸出結(jié)果如下:

  1. $ go run main.go 
  2. heap profile: 0: 0 [0: 0] @ heap/1048576 
  3.  
  4. # runtime.MemStats 
  5. # Alloc = 180632 
  6. # TotalAlloc = 180632 
  7. # Sys = 69928960 
  8. # Lookups = 0 
  9. ... 

為什么要初始化net/http/pprof

在我們的例子中,你會發(fā)現(xiàn)我們在引用上對 net/http/pprof 包進(jìn)行了默認(rèn)的初始化(也就是 _),如果你曾經(jīng)漏了,或者沒加,你會發(fā)現(xiàn)壓根調(diào)用不了 pprof 的相關(guān)接口,這是為什么呢,我們一起看看下面該包的初始化方法,如下:

  1. func init() { 
  2.  http.HandleFunc("/debug/pprof/"Index
  3.  http.HandleFunc("/debug/pprof/cmdline", Cmdline) 
  4.  http.HandleFunc("/debug/pprof/profile", Profile) 
  5.  http.HandleFunc("/debug/pprof/symbol", Symbol) 
  6.  http.HandleFunc("/debug/pprof/trace", Trace) 

實(shí)際上 net/http/pprof 會在初始化函數(shù)中對標(biāo)準(zhǔn)庫中 net/http 所默認(rèn)提供的 DefaultServeMux 進(jìn)行路由注冊,源碼如下:

  1. var DefaultServeMux = &defaultServeMux 
  2. var defaultServeMux ServeMux 
  3.  
  4. func HandleFunc(pattern string, handler func(ResponseWriter, *Request)) { 
  5.  DefaultServeMux.HandleFunc(pattern, handler) 

而我們在例子中使用的 HTTP Server,也是使用的標(biāo)準(zhǔn)庫中默認(rèn)提供的,因此便完美的結(jié)合在了一起,這也恰好也是最小示例的模式。

這時候你可能會注意到另外一個問題,那就是我們的實(shí)際項(xiàng)目中,都是有相對獨(dú)立的 ServeMux 的,這時候我們只要仿照著將 pprof 對應(yīng)的路由注冊進(jìn)去就好了,如下:

  1. mux := http.NewServeMux() 
  2. mux.HandleFunc("/debug/pprof/", pprof.Index
  3. mux.HandleFunc("/debug/pprof/cmdline", pprof.Cmdline) 
  4. mux.HandleFunc("/debug/pprof/profile", pprof.Profile) 
  5. mux.HandleFunc("/debug/pprof/symbol", pprof.Symbol) 
  6. mux.HandleFunc("/debug/pprof/trace", pprof.Trace) 

總結(jié)

在本文中我們詳細(xì)的介紹了 Go 語言中 pprof 的使用,針對一些常用的套件均進(jìn)行了說明。而 pprof 在我們平時的性能剖析,問題排查上都占據(jù)著非常重要的角色。

在日常只需要根據(jù)合理的排查思路,相信你一定能夠根據(jù)在 pprof 中的蛛絲馬跡,解決那些或大或小的問題,實(shí)現(xiàn)準(zhǔn)點(diǎn)下班!

 

責(zé)任編輯:武曉燕 來源: 腦子進(jìn)煎魚了
相關(guān)推薦

2022-02-07 08:55:57

Go程序代碼

2022-06-27 11:20:13

工具內(nèi)存GO

2021-05-18 14:42:55

PythonMySQL

2019-01-24 09:00:00

PythonAutoML機(jī)器學(xué)習(xí)

2018-01-02 16:48:58

Python 微信安卓

2015-03-23 12:33:28

2015-04-22 11:29:45

PythonPython創(chuàng)建瀑布圖

2014-07-22 10:19:19

NeoBundle

2023-10-27 11:38:09

PythonWord

2019-09-05 10:07:23

ZAODeepfakes換臉

2023-08-03 08:51:07

2014-07-21 09:51:10

AndroidResflux修改應(yīng)用

2020-04-09 09:52:42

Python數(shù)據(jù)技術(shù)

2020-03-25 14:40:45

語言編程語言Hello

2021-08-09 13:31:25

PythonExcel代碼

2022-10-19 14:30:59

2021-12-26 18:32:26

Python Heic 文件

2021-02-04 09:00:57

SQLDjango原生

2011-03-28 16:14:38

jQuery

2021-02-06 14:55:05

大數(shù)據(jù)pandas數(shù)據(jù)分析
點(diǎn)贊
收藏

51CTO技術(shù)棧公眾號

天堂va欧美va亚洲va老司机| 日韩av电影免费播放| 麻豆天美蜜桃91| 精品一区二区三区亚洲| 玉足女爽爽91| 国产一区福利视频| 成人午夜视频在线播放| 欧美三级情趣内衣| 久久亚洲精品人成综合网| 国产美女av一区二区三区| 精品少妇一区二区30p| av电影在线播放| 黄视频网站在线看| 丁香天五香天堂综合| 欧美有码在线视频| 亚洲精品国产精品国自| 欧美一区一区| 欧美性极品少妇精品网站| 亚洲高清乱码| 六月婷婷综合网| 亚洲三级电影在线观看| 亚洲二区在线播放视频| 在线免费观看av的网站| 性欧美video高清bbw| 久久午夜色播影院免费高清| 国产精品视频公开费视频| 玖玖爱免费视频| 国产麻豆精品久久| 日韩一级片在线播放| 日本www在线视频| 国产毛片av在线| 粉嫩久久99精品久久久久久夜| 国产成人综合一区二区三区| 激情小说中文字幕| 精品国产乱码久久久| 精品久久国产97色综合| 免费涩涩18网站入口| h片精品在线观看| 国产精品久久久久久妇女6080| 国产欧美日韩亚洲| 国产乱码久久久久| 视频一区二区欧美| 午夜精品久久久久久久男人的天堂| 中文字幕无码日韩专区免费| 国产一区二区三区四区五区传媒| 亚洲精品一区二区三区在线观看| 欧美成年人视频在线观看| 蜜桃麻豆影像在线观看| 亚洲欧美日韩国产成人精品影院 | 麻豆91在线观看| 91sa在线看| 91精品国产高清一区二区三蜜臀| 大胆日韩av| 亚洲视频在线观看视频| 欧产日产国产精品98| 久久伊人久久| 91精品国产综合久久婷婷香蕉 | 国产美女永久免费无遮挡| 国产成人aa在线观看网站站| 4438成人网| 国产九九在线视频| 欧美电影网站| 色综合天天狠狠| www.爱色av.com| 高端美女服务在线视频播放| 亚洲一区二区三区四区在线免费观看| 中文字幕一区二区中文字幕| 秋霞影院午夜丰满少妇在线视频| 国产人伦精品一区二区| 欧美一区2区三区4区公司二百| 天天射天天色天天干| 成人国产电影网| 国产91精品入口17c| 国产xxxxxx| 国产成a人亚洲精品| 99免费在线观看视频| 91精品国产乱码久久| 日韩国产欧美三级| 国产精品久久999| 久久国产香蕉视频| 久久国产精品区| 91精品免费看| www.日韩高清| av不卡在线观看| 欧美极品一区二区| 国产一区二区三区不卡在线| 久久精品亚洲精品国产欧美kt∨| 午夜精品亚洲一区二区三区嫩草| 免费在线毛片网站| 亚洲免费av网站| 少妇人妻大乳在线视频| 亚洲性受xxx喷奶水| 91久久精品一区二区三| 69久久久久久| 视频在线观看免费影院欧美meiju| 精品捆绑美女sm三区 | 91jq激情在线观看| 欧美午夜宅男影院在线观看| 密臀av一区二区三区| 日本电影久久久| 日韩精品自拍偷拍| 国产高清自拍视频| 久久亚洲成人| 欧美极品少妇xxxxx| 91蜜桃视频在线观看| 免费久久精品视频| 91亚洲精品一区| 亚洲 欧美 精品| 国产精品美女久久久久久2018| 成人手机在线播放| 伊人久久国产| 欧美一区二区三区播放老司机| xfplay5566色资源网站| 精品国产乱码久久久久久1区2匹| 欧美精品在线免费播放| 国产一级片毛片| 久久99日本精品| 久久国产精品久久精品国产| 日本不卡在线| 亚洲一区av在线| 尤蜜粉嫩av国产一区二区三区| 国内自拍亚洲| 亚洲精品美女在线观看| 91制片厂在线| 欧美亚洲视频| 91视频在线免费观看| 国产区高清在线| 亚洲国产视频直播| 污视频网址在线观看| 欧美黑人做爰爽爽爽| 久久精品精品电影网| 久热这里只有精品6| 国产精品一二一区| 亚洲国产精品久久久久久女王| av3级在线| 91精品国产综合久久久久久漫画| 亚洲久久久久久| 中文字幕免费精品| 国产精品久久久久7777婷婷| 亚洲 精品 综合 精品 自拍| 亚洲国产一区在线观看| 污免费在线观看| 日韩精品一区二区久久| 4438全国成人免费| 亚洲精品国产手机| 1区2区3区国产精品| 999在线免费视频| 全球av集中精品导航福利| 欧美大胆a视频| 国产精品伦一区二区三区| 久久久精品天堂| www.av中文字幕| 国产精品一区三区在线观看| 在线观看国产欧美| 99re国产在线| 久久色在线观看| 99在线精品免费视频| 蜜桃在线一区| 久久亚洲一区二区三区四区五区高| 成人免费一级片| 国产亚洲精品久| 欧美一区二区激情| 97久久超碰| 欧美黄色性视频| 亚洲第一第二区| 一区二区三区**美女毛片| www.日本久久| 999精品在线| 国产日本欧美一区二区三区在线| 国产福利在线| 欧美三级视频在线播放| 精品伦精品一区二区三区视频密桃| 老司机精品福利视频| 国产日韩精品一区观看| av在线最新| 日韩av一区在线| 好吊色在线视频| 国产亚洲欧美激情| 玖玖爱视频在线| 一区二区三区四区电影| 国产精品最新在线观看| 午夜在线免费观看视频| 666欧美在线视频| 国产一级特黄a高潮片| 99精品欧美一区二区三区小说| 久色视频在线播放| 国产剧情在线观看一区| 国产精品女主播视频| av男人的天堂在线| 欧美一区在线视频| 国产亚洲精品久久久久久无几年桃| 99久久久久免费精品国产| 久久久久狠狠高潮亚洲精品| 精品午夜久久| 91精品视频播放| 在线观看免费视频你懂的| 精品成人一区二区三区四区| 日本高清不卡码| 国产精品成人免费| 99热这里只有精品2| 国产精品theporn| 欧美日韩大片一区二区三区| 久久91超碰青草在哪里看| 操91在线视频| 亚洲色图另类小说| 欧美日韩一区二区在线观看视频 | 国产人伦精品一区二区| 日韩高清在线一区二区| 午夜亚洲伦理| 手机福利在线视频| 日本亚洲不卡| 成人免费看黄网站| www555久久| 亚洲一区www| 亚洲第一视频在线| 欧美日韩在线播放| 全部毛片永久免费看| 亚洲视频一二三| 国产高潮视频在线观看| 美女国产一区二区三区| 妞干网在线观看视频| 国产精品二区不卡| 欧美二区三区在线| 日本亚洲欧洲无免费码在线| 97视频在线观看免费| 女女色综合影院| 国产一区二区三区久久精品| 国产黄a三级三级看三级| 日韩欧美一区二区三区| 欧美日韩三级在线观看| 欧美经典三级视频一区二区三区| 制服丝袜av在线| 国产一区在线不卡| 91视频免费版污| 激情亚洲网站| 日本免费在线视频观看| 国产不卡一二三区| 国产伦精品一区二区三区视频黑人 | 精品高清视频| 一本一道久久a久久| 国产精品久久久久久久久久久新郎| 国模雨婷捆绑高清在线| 精品国产一区二区三区久久| 久久久久久女乱国产| 精品久久久久香蕉网| 国产欧美久久久| 欧美视频在线观看一区| 人人爽人人爽人人片av| 欧美日韩性视频| 五月天婷婷丁香| 亚洲高清中文字幕| 国产一二三av| 中文字幕第一页久久| 久久丫精品国产亚洲av不卡| 豆国产96在线|亚洲| 欧美性猛交xx| 国产福利91精品| 国产人妻精品久久久久野外| 激情欧美一区二区三区在线观看| 18岁视频在线观看| 国产精品一二| 日本精品一区二区三区四区| aⅴ色国产欧美| 欧美日韩国产精品激情在线播放| 亚洲精品极品| 久久国产精品视频在线观看| 亚洲经典视频在线观看| 欧美亚洲日本一区二区三区| 亚洲小说区图片区| 欧美大片在线播放| 亚洲在线观看| 黄色片一级视频| 一区二区高清| 精品免费国产一区二区| 美女爽到呻吟久久久久| 激情内射人妻1区2区3区| 亚洲专区在线| 中文字幕欧美人妻精品一区| 麻豆久久一区二区| 在线免费黄色小视频| 国产一区二区毛片| 国产乱淫av麻豆国产免费| www.久久久久久久久| 中文人妻一区二区三区| 久久久久久久性| 美国黄色特级片| 亚洲精品成a人| 久久夜色精品亚洲| 在线一区二区三区四区五区 | 国产婷婷色一区二区在线观看| 欧美色另类天堂2015| 在线视频免费观看一区| 精品蜜桃在线看| av天在线观看| 国语自产精品视频在线看| 精品亚洲美女网站| 2014亚洲精品| 国产一区二区三区四区五区| 久久综合亚洲精品| 天堂va蜜桃一区二区三区漫画版 | 337p粉嫩大胆色噜噜噜噜亚洲| 伊人影院综合网| 亚洲大片免费看| 中文字幕一区二区三区人妻四季| 精品捆绑美女sm三区| 欧洲美女少妇精品| 97热在线精品视频在线观看| 亚洲色图图片| 日本成人看片网址| 99亚洲一区二区| 免费看三级黄色片| 亚洲欧洲av色图| 69亚洲精品久久久蜜桃小说 | 日韩欧美中文在线| www香蕉视频| 少妇精69xxtheporn| 天堂av中文在线观看| 99久久伊人精品影院| 婷婷精品进入| 蜜臀av免费观看| 26uuu国产一区二区三区| 免费在线观看日韩| 91精品国产欧美日韩| jyzzz在线观看视频| 国产91精品不卡视频| 91亚洲无吗| 日韩最新中文字幕| 久久精品国产免费| youjizz亚洲女人| 在线看日韩精品电影| 欧美在线一卡| 欧美亚洲成人网| 美国一区二区| 无码人妻丰满熟妇区96| 懂色av一区二区在线播放| 我要看黄色一级片| 欧美精品一卡两卡| 幼a在线观看| 成人女保姆的销魂服务| 日韩视频在线观看| www.久久91| 国产精品国产三级国产aⅴ原创| 日韩久久久久久久久久| 一区二区三区黄色| 青青热久免费精品视频在线18| 日本一区视频在线观看免费| 久久蜜桃资源一区二区老牛| 国产伦精品一区二区三区妓女 | 一区二区三区视频网| 国产精品国产精品国产专区不蜜| 亚洲视屏在线观看| 色偷偷噜噜噜亚洲男人| 久久精品黄色| 午夜啪啪免费视频| 国产精品一区二区在线观看网站| 精品自拍偷拍视频| 337p日本欧洲亚洲大胆精品 | av大片在线播放| 国产乱人伦真实精品视频| 欧美激情777| 极品人妻一区二区| 亚洲成av人片一区二区梦乃| 深夜福利在线视频| 国产精品久久二区| 亚洲欧美偷拍自拍| 中文字幕在线永久| 91久久精品日日躁夜夜躁欧美| 最近高清中文在线字幕在线观看| 成人在线免费观看视视频| 欧美精品三区| 日本一区二区三区网站| 欧美性色欧美a在线播放| 久久久久久国产精品免费无遮挡| 亚洲一区二区在线播放| 日韩亚洲国产欧美| 日本二区在线观看| 3751色影院一区二区三区| 暧暧视频在线免费观看| 蜜桃av噜噜一区二区三| 日本91福利区| 久久久国产精品黄毛片| 国产丝袜视频一区| 欧美一区=区三区| 欧美视频在线观看视频| 国产免费久久精品| www黄色在线观看| 国产成人午夜视频网址| 欧美永久精品| 久久只有这里有精品| 日韩一卡二卡三卡四卡| 美脚恋feet久草欧美| 欧美 国产 精品| 91麻豆国产精品久久| 国产麻豆一精品一男同| 69久久夜色精品国产7777| 国产精品伦理久久久久久| 欧美一级片黄色| 91精品国产91久久久久久最新毛片| 天堂电影一区| 久久综合久久久久|