Go 標準庫想增加 metrics 指標,你支持嗎?
大家好,我是煎魚。
在 Go 的標準庫中,有一個神奇的標準庫 runtime/metrics,這個標準庫提供了一系列預定義好的 Go 自身的相關指標。
如果沒有編寫過基礎監控庫或者關注的比較少的朋友可能會沒接觸到這類指標,甚至不知道有這些值。但我相信你在監控圖標中肯定看到過。
本文分兩個部分,第一個部分是快速了解現有的 metrics 指標,第二個部分是了解現在社區希望追加到標準庫的 metrics 指標內容。
一起看看社區討論的方向和內容。
快速了解 runtime/metrics
以下是一個快速 Demo。代碼如下:
func main() {
descs := metrics.All()
samples := make([]metrics.Sample, len(descs))
for i := range samples {
samples[i].Name = descs[i].Name
}
metrics.Read(samples)
for _, sample := range samples {
name, value := sample.Name, sample.Value
switch value.Kind() {
case metrics.KindUint64:
fmt.Printf("%s: %d\n", name, value.Uint64())
case metrics.KindFloat64:
fmt.Printf("%s: %f\n", name, value.Float64())
case metrics.KindFloat64Histogram:
fmt.Printf("%s: %f\n", name, medianBucket(value.Float64Histogram()))
...
}
}
}
func medianBucket(h *metrics.Float64Histogram) float64 {
total := uint64(0)
for _, count := range h.Counts {
total += count
}
thresh := total / 2
total = 0
for i, count := range h.Counts {
total += count
if total >= thresh {
return h.Buckets[i]
}
}
panic("should not happen")
}
輸出結果:
/cgo/go-to-c-calls:calls: 0
/cpu/classes/gc/mark/assist:cpu-seconds: 0.000000
/cpu/classes/gc/mark/dedicated:cpu-seconds: 0.000000
...
/gc/cycles/automatic:gc-cycles: 0
/gc/cycles/forced:gc-cycles: 0
/gc/cycles/total:gc-cycles: 0
/gc/gogc:percent: 100
/gc/gomemlimit:bytes: 9223372036854775807
/gc/heap/allocs-by-size:bytes: 8193.000000
/gc/heap/allocs:bytes: 56832
/gc/heap/allocs:objects: 6
/gc/heap/frees-by-size:bytes: 1.000000
/gc/heap/frees:bytes: 0
/gc/heap/frees:objects: 0
/gc/heap/goal:bytes: 4194304
...
里面包含了相當多的 Go 系統指標。完整的代碼運行和輸出可以查看 https://go.dev/play/p/CKASbysqX9x
。
我梳理了一張對照清單。其中 10 個指標如下:
序號 | 指標 | 含義 |
1 | /cgo/go-to-c-calls:calls | 當前進程從 Go 調用到 C 的次數 |
2 | /cpu/classes/gc/mark/assist:cpu-seconds | 預計執行 GC 程序所花費的 CPU 總時長,以協助 GC 并防止其落后于應用程序 |
3 | /cpu/classes/gc/mark/dedicated:cpu-seconds | 在專門用于執行 GC 任務的 CPU 處理器(根據 GOMAXPROCS 的定義)上執行 GC 任務預計需要花費的 CPU 總時長 |
4 | /cpu/classes/gc/mark/idle:cpu-seconds | 在空閑 CPU 資源上執行 GC 任務所花費的 CPU 總時間 |
5 | /cpu/classes/gc/pause:cpu-seconds | GC 暫停應用程序預計所花費的 CPU 總時長 |
6 | /gc/cycles/automatic:gc-cycles | Go Runtime 程序已完成的 GC 循環次數。 |
7 | /gc/gogc:percent | 用戶配置的堆大小目標百分比 |
8 | /gc/heap/allocs:objects | 應用程序觸發的堆分配累計計數 |
9 | /memory/classes/heap/free:bytes | Go Runtime 對物理內存的可用空間大小的預估(完全空閑并可返回底層系統但尚未返回的內存) |
10 | /sched/gomaxprocs:threads | 當前 |
對于完整指標有興趣的可以查看:https://pkg.go.dev/runtime/metrics#hdr-Supported_metrics
。
更多的 metrics 指標
最近在 Go 社區中有同學發起了一項討論《metrics for the standard library[1]》,希望探討和在其他標準庫中添加更多的 metrics 指標,提供更多的可觀察性。
比較多同學期望的是網絡、延遲類的指標,針對性能、錯誤等。如下幾種場景:
- net/http 服務端:
- 處理延遲。
- 請求/響應體大小。
- 恐慌(panic)、恢復(recover)。
- 錯誤/警告(觸發
net/http.Server.ErrorLog
的所有內容) - 被拒絕的無效請求。
- net/http 客戶端:
調用延遲。
請求/響應體大小
連接池相關。
database/sql 客戶端:
查詢延遲。
響應大小。
連接池相關。
net 網絡包相關:
例如 TCP、UDP 等,對應的打開連接的數量、連接狀態(空閑、激活、關閉)、連接錯誤等。
例如 TLS,在握手階段相關的指標,握手持續時間、握手失敗計數等。
新提及的 metrics 指標有沒有滿足你的需求呢,或者有沒有更多的補充?
總結
整體上會發現大家對于 Go 標準庫的指標訴求,更多的趨向于底層包。因為無論你用的是什么開源倉庫,其絕大部分都是基于上述提到的包。
在現階段,如果自己的 Go 業務應用程序去記錄這些指標,就需要再封裝一層,每一個包,例如:ORM 就需要去實現一遍插件等。
而第三方庫實現不會把 metrics 這類非核心功能直接加入初始化實現中。因此官方標準庫對 metrics 的支持是非常有必要的。
至少這樣就不用每個團隊都搞一遍 net/http、database/sql 等的延遲調用指標的配置和設置了。