微服務效能分析工具 Pyroscope 初體驗

2023-07-29 06:00:58

Go 自帶介面效能分析工具 pprof,較為常用的有以下 4 種分析:

  • CPU Profiling: CPU 分析,按照一定的頻率採集所監聽的應用程式 CPU(含暫存器)的使用情況,可確定應用程式在主動消耗 CPU 週期時花費時間的位置;
  • Memory Profiling: 記憶體分析,在應用程式進行堆分配時記錄堆疊跟蹤,用於監視當前和歷史記憶體使用情況,以及檢查記憶體漏失;
  • Block Profiling: 阻塞分析,記錄 goroutine 阻塞等待同步(包括定時器通道)的位置;
  • Mutex Profiling: 互斥鎖分析,報告互斥鎖的競爭情況。

接入方式:

package main

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

func main() {
    http.ListenAndServe("0.0.0.0:6060", nil)
}

它使用預設的 http.DefaultServeMux 結構,註冊了 /debug/pprof/ 路由,在瀏覽器存取可以存取 CPU/Memory/Block/Mutex/Goroutine 等效能分析頁面。

對於線上服務來說,需要針對該路由做好限制,否則可能直接暴露到系統外部,造成資料安全問題。

如果是內部服務,自己電腦的瀏覽器看不到頁面,就很麻煩了。而 Pyroscope 這個專案就非常爽~

它有一個非常漂亮的 UI 介面,展示 Agent 採集的資料,能直觀地展示程式各個函數的呼叫耗時,從而找出效能瓶頸。

架構圖如下:

接入方式也非常簡單,本地搭建服務的話(macOS),輸入以下命令:

brew install pyroscope-io/brew/pyroscope
pyroscope server

對應的服務需要加入以下程式碼:

package main

import (
    "github.com/pyroscope-io/client/pyroscope"
)

func initPyroScope() {
    runtime.SetMutexProfileFraction(5)
    runtime.SetBlockProfileRate(5)
    _, _ = pyroscope.Start(pyroscope.Config{
        ApplicationName: app.ServerName,                 // 應用名稱
        ServerAddress:   "http://pyroscope.test.com.cn", // 上報地址
        Logger:          pyroscope.StandardLogger,
        Tags:            map[string]string{"hostname": os.Getenv("HOSTNAME")},
        ProfileTypes: []pyroscope.ProfileType{
            pyroscope.ProfileCPU,
            pyroscope.ProfileAllocObjects,
            pyroscope.ProfileAllocSpace,
            pyroscope.ProfileInuseObjects,
            pyroscope.ProfileInuseSpace,
            pyroscope.ProfileGoroutines,
            pyroscope.ProfileMutexCount,
            pyroscope.ProfileMutexDuration,
            pyroscope.ProfileBlockCount,
            pyroscope.ProfileBlockDuration,
        },
    })
}

func main() {
    initPyroScope()
    // ...
}

其中,ApplicationNameServerAddress 需要自行替換。

如果是本地,ServerAddress 請改成 "http://127.0.0.1:4040",接著執行 benchmark 壓測:

ab -c 100 -n 10000 'http://127.0.0.1:8099/api/xxx-service/v1/yyy/get_test?gid=23333'

可以得到火焰圖(好漂亮啊):

此時可以看到最耗時的是 HTTP 服務的呼叫,還有 JSON 的序列化:

說明我們的程式介面,在某個輸入引數的情況下,沒有出現邏輯上的瓶頸。

我們可以多變換輸入引數,根據業務邏輯找到最複雜最消耗效能的模組,有針對性進行效能優化。


文章來源於本人部落格,釋出於 2022-06-12,原文連結:https://imlht.com/archives/391/