Go 標(biāo)準(zhǔn)庫(kù)想增加 metrics 指標(biāo),你支持嗎?
大家好,我是煎魚。
在 Go 的標(biāo)準(zhǔn)庫(kù)中,有一個(gè)神奇的標(biāo)準(zhǔn)庫(kù) runtime/metrics,這個(gè)標(biāo)準(zhǔn)庫(kù)提供了一系列預(yù)定義好的 Go 自身的相關(guān)指標(biāo)。
如果沒(méi)有編寫過(guò)基礎(chǔ)監(jiān)控庫(kù)或者關(guān)注的比較少的朋友可能會(huì)沒(méi)接觸到這類指標(biāo),甚至不知道有這些值。但我相信你在監(jiān)控圖標(biāo)中肯定看到過(guò)。
本文分兩個(gè)部分,第一個(gè)部分是快速了解現(xiàn)有的 metrics 指標(biāo),第二個(gè)部分是了解現(xiàn)在社區(qū)希望追加到標(biāo)準(zhǔn)庫(kù)的 metrics 指標(biāo)內(nèi)容。
一起看看社區(qū)討論的方向和內(nèi)容。
快速了解 runtime/metrics
以下是一個(gè)快速 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")
}
輸出結(jié)果:
/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
...
里面包含了相當(dāng)多的 Go 系統(tǒng)指標(biāo)。完整的代碼運(yùn)行和輸出可以查看 https://go.dev/play/p/CKASbysqX9x
。
我梳理了一張對(duì)照清單。其中 10 個(gè)指標(biāo)如下:
序號(hào) | 指標(biāo) | 含義 |
1 | /cgo/go-to-c-calls:calls | 當(dāng)前進(jìn)程從 Go 調(diào)用到 C 的次數(shù) |
2 | /cpu/classes/gc/mark/assist:cpu-seconds | 預(yù)計(jì)執(zhí)行 GC 程序所花費(fèi)的 CPU 總時(shí)長(zhǎng),以協(xié)助 GC 并防止其落后于應(yīng)用程序 |
3 | /cpu/classes/gc/mark/dedicated:cpu-seconds | 在專門用于執(zhí)行 GC 任務(wù)的 CPU 處理器(根據(jù) GOMAXPROCS 的定義)上執(zhí)行 GC 任務(wù)預(yù)計(jì)需要花費(fèi)的 CPU 總時(shí)長(zhǎng) |
4 | /cpu/classes/gc/mark/idle:cpu-seconds | 在空閑 CPU 資源上執(zhí)行 GC 任務(wù)所花費(fèi)的 CPU 總時(shí)間 |
5 | /cpu/classes/gc/pause:cpu-seconds | GC 暫停應(yīng)用程序預(yù)計(jì)所花費(fèi)的 CPU 總時(shí)長(zhǎng) |
6 | /gc/cycles/automatic:gc-cycles | Go Runtime 程序已完成的 GC 循環(huán)次數(shù)。 |
7 | /gc/gogc:percent | 用戶配置的堆大小目標(biāo)百分比 |
8 | /gc/heap/allocs:objects | 應(yīng)用程序觸發(fā)的堆分配累計(jì)計(jì)數(shù) |
9 | /memory/classes/heap/free:bytes | Go Runtime 對(duì)物理內(nèi)存的可用空間大小的預(yù)估(完全空閑并可返回底層系統(tǒng)但尚未返回的內(nèi)存) |
10 | /sched/gomaxprocs:threads | 當(dāng)前 |
對(duì)于完整指標(biāo)有興趣的可以查看:https://pkg.go.dev/runtime/metrics#hdr-Supported_metrics
。
更多的 metrics 指標(biāo)
最近在 Go 社區(qū)中有同學(xué)發(fā)起了一項(xiàng)討論《metrics for the standard library[1]》,希望探討和在其他標(biāo)準(zhǔn)庫(kù)中添加更多的 metrics 指標(biāo),提供更多的可觀察性。
比較多同學(xué)期望的是網(wǎng)絡(luò)、延遲類的指標(biāo),針對(duì)性能、錯(cuò)誤等。如下幾種場(chǎng)景:
- net/http 服務(wù)端:
- 處理延遲。
- 請(qǐng)求/響應(yīng)體大小。
- 恐慌(panic)、恢復(fù)(recover)。
- 錯(cuò)誤/警告(觸發(fā)
net/http.Server.ErrorLog
的所有內(nèi)容) - 被拒絕的無(wú)效請(qǐng)求。
- net/http 客戶端:
調(diào)用延遲。
請(qǐng)求/響應(yīng)體大小
連接池相關(guān)。
database/sql 客戶端:
查詢延遲。
響應(yīng)大小。
連接池相關(guān)。
net 網(wǎng)絡(luò)包相關(guān):
例如 TCP、UDP 等,對(duì)應(yīng)的打開(kāi)連接的數(shù)量、連接狀態(tài)(空閑、激活、關(guān)閉)、連接錯(cuò)誤等。
例如 TLS,在握手階段相關(guān)的指標(biāo),握手持續(xù)時(shí)間、握手失敗計(jì)數(shù)等。
新提及的 metrics 指標(biāo)有沒(méi)有滿足你的需求呢,或者有沒(méi)有更多的補(bǔ)充?
總結(jié)
整體上會(huì)發(fā)現(xiàn)大家對(duì)于 Go 標(biāo)準(zhǔn)庫(kù)的指標(biāo)訴求,更多的趨向于底層包。因?yàn)闊o(wú)論你用的是什么開(kāi)源倉(cāng)庫(kù),其絕大部分都是基于上述提到的包。
在現(xiàn)階段,如果自己的 Go 業(yè)務(wù)應(yīng)用程序去記錄這些指標(biāo),就需要再封裝一層,每一個(gè)包,例如:ORM 就需要去實(shí)現(xiàn)一遍插件等。
而第三方庫(kù)實(shí)現(xiàn)不會(huì)把 metrics 這類非核心功能直接加入初始化實(shí)現(xiàn)中。因此官方標(biāo)準(zhǔn)庫(kù)對(duì) metrics 的支持是非常有必要的。
至少這樣就不用每個(gè)團(tuán)隊(duì)都搞一遍 net/http、database/sql 等的延遲調(diào)用指標(biāo)的配置和設(shè)置了。