Go Wiki: CustomPprofProfiles

最初發佈於 https://rakyll.org/custom-profiles/


Go 開箱即用地提供了幾個 pprof profile,用於從 Go 程式收集分析資料。

runtime/pprof 包提供的內建 profile

  • profile:CPU profile 確定程式在積極消耗 CPU 週期時(而非睡眠或等待 I/O 時)將時間花在了哪裡。
  • heap:Heap profile 報告當前活動的分配;用於監控當前記憶體使用情況或檢查記憶體洩漏。
  • threadcreate:Thread creation profile 報告導致建立新 OS 執行緒的程式部分。
  • goroutine:Goroutine profile 報告所有當前 goroutine 的堆疊跟蹤。
  • block:Block profile 顯示 goroutine 在等待同步原語(包括定時器通道)時被阻塞的位置。Block profile 預設未啟用;使用 runtime.SetBlockProfileRate 來啟用它。
  • mutex:Mutex profile 報告鎖的爭用。當您認為 CPU 未被充分利用是由於互斥鎖爭用時,請使用此 profile。Mutex profile 預設未啟用,請參閱 runtime.SetMutexProfileFraction 來啟用。

除了內建 profile,runtime/pprof 包還允許您匯出自定義 profile,並對程式碼進行儀器化以記錄對該 profile 有貢獻的執行堆疊。

想象一下我們有一個 blob 伺服器,我們正在為其編寫一個 Go 客戶端。我們的使用者希望能夠對客戶端上的已開啟 blob 進行分析。我們可以建立一個 profile 並記錄開啟和關閉 blob 的事件,這樣使用者就可以隨時知道有多少 blob 已開啟。

這是一個允許您開啟一些 blob 的 blobstore 包。我們將建立一個新的自定義 profile 並開始記錄導致 blob 開啟的執行堆疊。

package blobstore

import "runtime/pprof"

var openBlobProfile = pprof.NewProfile("blobstore.Open")

// Open opens a blob, all opened blobs need
// to be closed when no longer in use.
func Open(name string) (*Blob, error) {
    blob := &Blob{name: name}
    // TODO: Initialize the blob...

    openBlobProfile.Add(blob, 2) // add the current execution stack to the profile
    return blob, nil
}

當用戶想要關閉 blob 時,我們需要從 profile 中移除與當前 blob 關聯的執行堆疊。

// Close closes the blob and frees the
// underlying resources.
func (b *Blob) Close() error {
    // TODO: Free other resources.
    openBlobProfile.Remove(b)
    return nil
}

現在,從使用此包的程式中,我們應該能夠檢索 blobstore.Open profile 資料,並使用我們日常的 pprof 工具來檢查和視覺化它們。

讓我們編寫一個開啟一些 blob 的小型 main 程式。

package main

import (
    "fmt"
    "math/rand"
    "net/http"
    _ "net/http/pprof" // as a side effect, registers the pprof endpoints.
    "time"

    "myproject.org/blobstore"
)

func main() {
    for i := 0; i < 1000; i++ {
        name := fmt.Sprintf("task-blob-%d", i)
        go func() {
            b, err := blobstore.Open(name)
            if err != nil {
                // TODO: Handle error.
            }
            defer b.Close()

            // TODO: Perform some work, write to the blob.
        }()
    }
    http.ListenAndServe("localhost:8888", nil)
}

啟動伺服器,然後使用 go tool 讀取和視覺化 profile 資料。

$ go tool pprof https://:8888/debug/pprof/blobstore.Open
(pprof) top
Showing nodes accounting for 800, 100% of 800 total
      flat  flat%   sum%        cum   cum%
       800   100%   100%        800   100%  main.main.func1 /Users/jbd/src/hello/main.go

您會看到有 800 個開啟的 blob,並且所有開啟操作都來自 main.main.func1。在這個小例子中,沒有更多可看的了,但在複雜的伺服器中,您可以檢查與開啟的 blob 互動最熱點的地方,並找出瓶頸或洩漏。


此內容是 Go Wiki 的一部分。