Go內建的net/http/pprof
套件可用來監控應用程式的資源利用狀況。
範例環境:
- macOS Ventura 13.4.1
- Go 1.19
使用
Go的pprof必須搭配HTTP應用程式使用,在程式中以副作用方式匯入(side-effect import)pprof,即import _ "net/http/pprof"
。
package main
import (
"net/http"
_ "net/http/pprof"
)
func main() {
http.ListenAndServe(":8080", nil)
}
啟動應用程式,pprof監控的資料可以在/debug/pprof
查看。
例如這邊在瀏覽器開啟http://localhost:8080/debug/pprof/
如下。
- allocs - 所有的記憶體配置。
- block - 追蹤goroutine的多執行緒阻塞(包括Timer channel)。
- cmdline - 目前程式調用的命令。
- goroutine - 追蹤目前的goroutine。
- heap - 仍存活物件的記憶體配置。用來監控目前即過去的記憶體使用狀況及找出可能的記憶體洩漏。
- mutex - 追蹤互斥鎖競爭。
- profile - CPU用量分析。
- threadcreate - 追蹤作業系統執行緒的建立。
- trace - 目前程式的執行追蹤檔。
從上可看到目前系統中的allocs有4個、goroutine有4個、heap有4個、threadcreate有7個。allocs和heap內容相同。
取得profile
點選goroutine進入的頁面內容如下,最上面的goroutine profile: total 3
顯示目前有3個goroutine在運作。下面可以看到每個goroutine的數量和stack trace。
goroutine profile: total 4
1 @ 0x102fff6 0x10647c5 0x125c415 0x125c22d 0x125918b 0x1268365 0x1268efe 0x1215fef 0x1217989 0x1218bac 0x1214d47 0x106a761
# 0x10647c4 runtime/pprof.runtime_goroutineProfileWithLabels+0x24 /usr/local/Cellar/go/1.19.3/libexec/src/runtime/mprof.go:846
# 0x125c414 runtime/pprof.writeRuntimeProfile+0xb4 /usr/local/Cellar/go/1.19.3/libexec/src/runtime/pprof/pprof.go:723
# 0x125c22c runtime/pprof.writeGoroutine+0x4c /usr/local/Cellar/go/1.19.3/libexec/src/runtime/pprof/pprof.go:683
# 0x125918a runtime/pprof.(*Profile).WriteTo+0x14a /usr/local/Cellar/go/1.19.3/libexec/src/runtime/pprof/pprof.go:330
# 0x1268364 net/http/pprof.handler.ServeHTTP+0x4a4 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/pprof/pprof.go:253
# 0x1268efd net/http/pprof.Index+0x13d /usr/local/Cellar/go/1.19.3/libexec/src/net/http/pprof/pprof.go:371
# 0x1215fee net/http.HandlerFunc.ServeHTTP+0x2e /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:2109
# 0x1217988 net/http.(*ServeMux).ServeHTTP+0x148 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:2487
# 0x1218bab net/http.serverHandler.ServeHTTP+0x30b /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:2947
# 0x1214d46 net/http.(*conn).serve+0x606 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:1991
1 @ 0x103a136 0x10335d7 0x1064bc9 0x10b8b12 0x10b96ba 0x10b96a8 0x1161029 0x116bce5 0x120eb5f 0x106a761
# 0x1064bc8 internal/poll.runtime_pollWait+0x88 /usr/local/Cellar/go/1.19.3/libexec/src/runtime/netpoll.go:305
# 0x10b8b11 internal/poll.(*pollDesc).wait+0x31 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_poll_runtime.go:84
# 0x10b96b9 internal/poll.(*pollDesc).waitRead+0x259 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_poll_runtime.go:89
# 0x10b96a7 internal/poll.(*FD).Read+0x247 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_unix.go:167
# 0x1161028 net.(*netFD).Read+0x28 /usr/local/Cellar/go/1.19.3/libexec/src/net/fd_posix.go:55
# 0x116bce4 net.(*conn).Read+0x44 /usr/local/Cellar/go/1.19.3/libexec/src/net/net.go:183
# 0x120eb5e net/http.(*connReader).backgroundRead+0x3e /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:678
1 @ 0x103a136 0x10335d7 0x1064bc9 0x10b8b12 0x10ba1b4 0x10ba1a1 0x1162195 0x11719c8 0x1170d3d 0x1219105 0x1218d3d 0x126a0a5 0x126a075 0x1039d72 0x106a761
# 0x1064bc8 internal/poll.runtime_pollWait+0x88 /usr/local/Cellar/go/1.19.3/libexec/src/runtime/netpoll.go:305
# 0x10b8b11 internal/poll.(*pollDesc).wait+0x31 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_poll_runtime.go:84
# 0x10ba1b3 internal/poll.(*pollDesc).waitRead+0x233 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_poll_runtime.go:89
# 0x10ba1a0 internal/poll.(*FD).Accept+0x220 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_unix.go:614
# 0x1162194 net.(*netFD).accept+0x34 /usr/local/Cellar/go/1.19.3/libexec/src/net/fd_unix.go:172
# 0x11719c7 net.(*TCPListener).accept+0x27 /usr/local/Cellar/go/1.19.3/libexec/src/net/tcpsock_posix.go:142
# 0x1170d3c net.(*TCPListener).Accept+0x3c /usr/local/Cellar/go/1.19.3/libexec/src/net/tcpsock.go:288
# 0x1219104 net/http.(*Server).Serve+0x384 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:3070
# 0x1218d3c net/http.(*Server).ListenAndServe+0x7c /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:2999
# 0x126a0a4 net/http.ListenAndServe+0x44 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:3255
# 0x126a074 main.main+0x14 /Users/<user>/Documents/projects/go-demo/main.go:9
# 0x1039d71 runtime.main+0x211 /usr/local/Cellar/go/1.19.3/libexec/src/runtime/proc.go:250
1 @ 0x1066f5f 0x10752c9 0x10b96e5 0x10b96cd 0x10b9485 0x1161029 0x116bce5 0x120f031 0x11c319f 0x11c3d2f 0x11c3f87 0x11c6439 0x120b9f9 0x120b9fa 0x12105ca 0x1214a85 0x106a761
# 0x1066f5e syscall.syscall+0x7e /usr/local/Cellar/go/1.19.3/libexec/src/runtime/sys_darwin.go:23
# 0x10752c8 syscall.read+0x48 /usr/local/Cellar/go/1.19.3/libexec/src/syscall/zsyscall_darwin_amd64.go:1189
# 0x10b96e4 syscall.Read+0x284 /usr/local/Cellar/go/1.19.3/libexec/src/syscall/syscall_unix.go:183
# 0x10b96cc internal/poll.ignoringEINTRIO+0x26c /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_unix.go:794
# 0x10b9484 internal/poll.(*FD).Read+0x24 /usr/local/Cellar/go/1.19.3/libexec/src/internal/poll/fd_unix.go:163
# 0x1161028 net.(*netFD).Read+0x28 /usr/local/Cellar/go/1.19.3/libexec/src/net/fd_posix.go:55
# 0x116bce4 net.(*conn).Read+0x44 /usr/local/Cellar/go/1.19.3/libexec/src/net/net.go:183
# 0x120f030 net/http.(*connReader).Read+0x170 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:786
# 0x11c319e bufio.(*Reader).fill+0xfe /usr/local/Cellar/go/1.19.3/libexec/src/bufio/bufio.go:106
# 0x11c3d2e bufio.(*Reader).ReadSlice+0x2e /usr/local/Cellar/go/1.19.3/libexec/src/bufio/bufio.go:372
# 0x11c3f86 bufio.(*Reader).ReadLine+0x26 /usr/local/Cellar/go/1.19.3/libexec/src/bufio/bufio.go:401
# 0x11c6438 net/textproto.(*Reader).readLineSlice+0x98 /usr/local/Cellar/go/1.19.3/libexec/src/net/textproto/reader.go:56
# 0x120b9f8 net/textproto.(*Reader).ReadLine+0x78 /usr/local/Cellar/go/1.19.3/libexec/src/net/textproto/reader.go:37
# 0x120b9f9 net/http.readRequest+0x79 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/request.go:1036
# 0x12105c9 net/http.(*conn).readRequest+0x249 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:994
# 0x1214a84 net/http.(*conn).serve+0x344 /usr/local/Cellar/go/1.19.3/libexec/src/net/http/server.go:1916
在命令列輸入go tool pprof <profile-path>
會下載為一份pprof的goroutine profile檔並進入pprof命令互動模式。<profile-path>
為profile的url路徑。例如這邊輸入go tool pprof http://localhost:8080/debug/pprof/goroutine
會下載一份pprof.goroutine.001.pb.gz
檔預設放在使用者目錄下的pprof
目錄,即/Users/<user>/pprof
。
~% go tool pprof http://localhost:8080/debug/pprof/goroutine
Fetching profile over HTTP from http://localhost:8080/debug/pprof/goroutine
Saved profile in /Users/<user>/pprof/pprof.goroutine.001.pb.gz
Type: goroutine
Time: Jun 30, 2023 at 10:24pm (CST)
Entering interactive mode (type "help" for commands, "o" for options)
(pprof)
轉為圖形檔
進入pprof命令互動模式後,可選擇將檔案轉為不同格式的圖形,例如這邊輸入png
則轉為profile001.png
檔在執行目錄下。
(pprof) png
Generating report in profile001.png
轉圖形檔需要graphviz工具,mac輸入brew install graphviz
安裝。
或是先離開pprof互動模式回到命令列,在命令列輸入go tool pprof -png <pprof-profile-path>
則是把profile檔轉為png。<pprof-profile-path>
為profile檔的目錄位置。
~% go tool pprof -png ~/pprof/pprof.goroutine.001.pb.gz
Generating report in profile001.png
pprof profile轉換成的圖形檔如下。
沒有留言:
張貼留言