使用go-metrics在Go應(yīng)用中增加度量

Go語(yǔ)言內(nèi)置expvar,基于expvar提供的對(duì)基礎(chǔ)度量的支持能力,我們可以自定義各種度量(metrics)。但是expvar僅僅是提供了最底層的度量定義支持,對(duì)于一些復(fù)雜的度量場(chǎng)景,第三方或自實(shí)現(xiàn)的metrics包必不可少。
go-metrics包是Go領(lǐng)域使用較多的metrics包,該包是對(duì)Java社區(qū)依舊十分活躍的Coda Hale's Metrics library[2]的不完全Go移植(不得不感慨一下:Java的生態(tài)還真是強(qiáng)大)。因此該包在概念上與Coda Hale's Metrics library是基本保持一致的。go-metrics包在文檔方面做的還不夠,要理解很多概念性的東西,我們還得回到Coda Hale's Metrics library的項(xiàng)目文檔[3]去挖掘。
go-metrics這樣的包是純工具類的包,沒有太多“燒腦”的地方,只需要會(huì)用即可,這篇文章我們就來簡(jiǎn)單地看看如何使用go-metrics在Go應(yīng)用中增加度量。
1. go-metrics的結(jié)構(gòu)
go-metrics在度量指標(biāo)組織上采用了與Coda Hale's Metrics library相同的結(jié)構(gòu),即使用Metrics Registry(Metrics注冊(cè)表)。Metrics注冊(cè)表是一個(gè)度量指標(biāo)的集合:
?????????????????????????????┌─────────────┐
?????????????????????????????│?????????????│
??????????????????????┌──────┤????metric1??│
??????????????????????│??????│?????????????│
??????????????????????│??????└─────────────┘
??????????????????????│
??????????????????????│
┌─────────────────┐???│??????┌─────────────┐
│?????????????????├───┘??????│?????????????│
│?????????????????│??????????│????metric2??│
│?????Registry????├──────────┤?????????????│
│?????????????????│??????????└─────────────┘
│?????????????????├───────┐
│?????????????????│???????│
└──────────────┬──┘???????│??┌─────────────┐
???????????????│??????????│??│?????????????│
???????????????│??????????└──┤????metric3??│
???????????????│?????????????│?????????????│
???????????????│?????????????└─────────────┘
???????????????│???????????????????...?...
???????????????│?????????????┌─────────────┐
???????????????│?????????????│?????????????│
???????????????└─────────────┤????metricN??│
?????????????????????????????│?????????????│
?????????????????????????????└─────────────┘????????????
go-metrics包將Metrics注冊(cè)表的行為定義為了一個(gè)接口類型:
//?https://github.com/rcrowley/go-metrics/blob/master/registry.go
type?Registry?interface?{
????//?Call?the?given?function?for?each?registered?metric.
????Each(func(string,?interface{}))
????//?Get?the?metric?by?the?given?name?or?nil?if?none?is?registered.
????Get(string)?interface{}
????//?GetAll?metrics?in?the?Registry.
????GetAll()?map[string]map[string]interface{}
????//?Gets?an?existing?metric?or?registers?the?given?one.
????//?The?interface?can?be?the?metric?to?register?if?not?found?in?registry,
????//?or?a?function?returning?the?metric?for?lazy?instantiation.
????GetOrRegister(string,?interface{})?interface{}
????//?Register?the?given?metric?under?the?given?name.
????Register(string,?interface{})?error
????//?Run?all?registered?healthchecks.
????RunHealthchecks()
????//?Unregister?the?metric?with?the?given?name.
????Unregister(string)
????//?Unregister?all?metrics.??(Mostly?for?testing.)
????UnregisterAll()
}
并提供了一個(gè)Registry的標(biāo)準(zhǔn)實(shí)現(xiàn)類型StandardRegistry:
//?https://github.com/rcrowley/go-metrics/blob/master/registry.go
type?StandardRegistry?struct?{
????metrics?map[string]interface{}
????mutex???sync.RWMutex
}
我們看到StandardRegistry使用map結(jié)構(gòu)來組織metrics。我們可以通過NewRegistry函數(shù)創(chuàng)建了一個(gè)基于StandardRegistry的Registry實(shí)例:
//?https://github.com/rcrowley/go-metrics/blob/master/registry.go
func?NewRegistry()?Registry?{
????return?&StandardRegistry{metrics:?make(map[string]interface{})}
}
和標(biāo)準(zhǔn)庫(kù)的flag或log包的設(shè)計(jì)方式類似,go-metrics包也在包層面上提供了默認(rèn)的StandardRegistry實(shí)例:DefaultRegistry,這樣大多數(shù)情況直接使用DefaultRegistry實(shí)例即可滿足你的需求:
//?https://github.com/rcrowley/go-metrics/blob/master/registry.go
var?DefaultRegistry?Registry?=?NewRegistry()
一旦有了默認(rèn)Registry實(shí)例,我們通常使用下面goroutine并發(fā)安全的包級(jí)函數(shù)GetOrRegister來注冊(cè)或獲取某個(gè)度量指標(biāo):
//?https://github.com/rcrowley/go-metrics/blob/master/registry.go
func?GetOrRegister(name?string,?i?interface{})?interface{}?{
????return?DefaultRegistry.GetOrRegister(name,?i)
}
2. go-metrics的度量類型
go-metrics繼承了其前身Coda Hale's Metrics library所支持的幾種基本的度量類型,它們是Gauges、Counters、Histograms、Meters和Timers。下面我們就針對(duì)這幾種基本度量類型逐一說明一下其含義和使用方法。
1) Gauge
Gauge是對(duì)一個(gè)數(shù)值的即時(shí)測(cè)量值,其反映一個(gè)值的瞬時(shí)快照,比如我們要度量當(dāng)前隊(duì)列中待發(fā)送消息數(shù)量、當(dāng)前應(yīng)用程序啟動(dòng)的goroutine數(shù)量,都可以用Gauge這種度量類型實(shí)現(xiàn)。
下面的例子使用一個(gè)Gauge度量類型度量程序當(dāng)前啟動(dòng)的goroutine數(shù)量:
//?gauge.go
package?main
import?(
?"fmt"
?"net/http"
?"runtime"
?"time"
?"github.com/rcrowley/go-metrics"
)
func?main()?{
?g?:=?metrics.NewGauge()
?metrics.GetOrRegister("goroutines.now",?g)
?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
?})
?go?func()?{
??t?:=?time.NewTicker(time.Second)
??for?{
???select?{
???case?<-t.C:
????c?:=?runtime.NumGoroutine()
????g.Update(int64(c))
????fmt.Println("goroutines?now?=",?g.Value())
???}
??}
?}()
?http.ListenAndServe(":8080",?nil)
}
啟動(dòng)該程序,并用hey工具[4]發(fā)起http請(qǐng)求,我們看到如下輸出:
$hey?-c?5?-n?1000000?-m?GET?http://127.0.0.1:8080
$go?run?gauge.go
goroutines?now?=?9
goroutines?now?=?10
goroutines?now?=?7
goroutines?now?=?8
goroutines?now?=?7
goroutines?now?=?7
...?...
go-metrics包提供了將Registry中的度量指標(biāo)格式化輸出的接口,我們可以使用該接口將指標(biāo)情況輸出出來,而無需自行輸出log,比如上面例子可以改造為下面這樣:
//?gauge1.go
package?main
import?(
?"log"
?"net/http"
?"runtime"
?"time"
?"github.com/rcrowley/go-metrics"
)
func?main()?{
?g?:=?metrics.NewGauge()
?metrics.GetOrRegister("goroutines.now",?g)
?go?metrics.Log(metrics.DefaultRegistry,?time.Second,?log.Default())
?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
?})
?go?func()?{
??t?:=?time.NewTicker(time.Second)
??for?{
???select?{
???case?<-t.C:
????c?:=?runtime.NumGoroutine()
????g.Update(int64(c))
???}
??}
?}()
?http.ListenAndServe(":8080",?nil)
}
同樣方式運(yùn)行上面gauge1.log:
$go?run?gauge1.go
2021/07/04?09:42:58?gauge?goroutines.now
2021/07/04?09:42:58???value:??????????????10
2021/07/04?09:42:59?gauge?goroutines.now
2021/07/04?09:42:59???value:???????????????9
2021/07/04?09:43:00?gauge?goroutines.now
2021/07/04?09:43:00???value:???????????????9
2021/07/04?09:43:01?gauge?goroutines.now
2021/07/04?09:43:01???value:??????????????10
...?...
go-metrics包的Log函數(shù)必須放在一個(gè)單獨(dú)的goroutine中執(zhí)行,否則它將阻塞調(diào)用它的goroutine的繼續(xù)執(zhí)行。但Log函數(shù)也是goroutine安全的,其每次輸出度量值時(shí)其實(shí)輸出的都是Registry中各個(gè)度量值的“快照副本”:
//?https://github.com/rcrowley/go-metrics/blob/master/registry.go
func?(r?*StandardRegistry)?Each(f?func(string,?interface{}))?{
????metrics?:=?r.registered()
????for?i?:=?range?metrics?{
????????kv?:=?&metrics[i]
????????f(kv.name,?kv.value)
????}
}
func?(r?*StandardRegistry)?registered()?[]metricKV?{
????r.mutex.RLock()
????defer?r.mutex.RUnlock()
????metrics?:=?make([]metricKV,?0,?len(r.metrics))
????for?name,?i?:=?range?r.metrics?{
????????metrics?=?append(metrics,?metricKV{
????????????name:??name,
????????????value:?i,
????????})
????}
????return?metrics
}
對(duì)于Gauge這類的季世志度量,就像上面代碼那樣,我們都是通過Update直接設(shè)置其值的。
2) Counter
Counter顧名思義計(jì)數(shù)器!和Gauge相比,其提供了指標(biāo)增減方法Inc和Dec,如下面代碼:
//?https://github.com/rcrowley/go-metrics/blob/master/counter.go
type?Counter?interface?{
????Clear()
????Count()?int64
????Dec(int64)
????Inc(int64)
????Snapshot()?Counter
}
計(jì)數(shù)是日常使用較多的度量場(chǎng)景,比如一個(gè)服務(wù)處理的請(qǐng)求次數(shù)就十分適合用計(jì)數(shù)這個(gè)度量指標(biāo),下面這段代碼演示的就是這一場(chǎng)景:
//?counter.go
package?main
import?(
?"log"
?"net/http"
?"time"
?"github.com/rcrowley/go-metrics"
)
func?main()?{
?c?:=?metrics.NewCounter()
?metrics.GetOrRegister("total.requests",?c)
?go?metrics.Log(metrics.DefaultRegistry,?time.Second,?log.Default())
?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
??c.Inc(1)
?})
?http.ListenAndServe(":8080",?nil)
}
在這段代碼中,我們每收到一個(gè)http request就在其對(duì)應(yīng)的處理函數(shù)中利用Counter的Inc方法增加計(jì)數(shù),運(yùn)行上述代碼:
$go?run?counter.go
2021/07/04?10:29:03?counter?total.requests
...?...
2021/07/04?10:29:06?counter?total.requests
2021/07/04?10:29:06???count:???????????????0
2021/07/04?10:29:07?counter?total.requests
2021/07/04?10:29:07???count:???????????33890
2021/07/04?10:29:08?counter?total.requests
2021/07/04?10:29:08???count:???????????80160
2021/07/04?10:29:09?counter?total.requests
2021/07/04?10:29:09???count:??????????124855
2021/07/04?10:29:10?counter?total.requests
2021/07/04?10:29:10???count:??????????172077
2021/07/04?10:29:11?counter?total.requests
2021/07/04?10:29:11???count:??????????218466
2021/07/04?10:29:12?counter?total.requests
2021/07/04?10:29:12???count:??????????265476
2021/07/04?10:29:13?counter?total.requests
2021/07/04?10:29:13???count:??????????309153
...?...
3) Meter
Meter這個(gè)類型用于測(cè)量一組事件發(fā)生的速度,比如:web服務(wù)的平均處理性能(條/秒),除了平均值,go-metrics的Meter默認(rèn)還提供1分鐘、5分鐘和15分鐘時(shí)間段的平均速度,和top命令中的load average輸出的一分鐘、五分鐘、以及十五分鐘的系統(tǒng)平均負(fù)載類似。
下面就是一個(gè)用Meter來測(cè)量web服務(wù)處理性能的例子:
//?meter.go?
package?main
import?(
?"log"
?"net/http"
?"time"
?"github.com/rcrowley/go-metrics"
)
func?main()?{
?m?:=?metrics.NewMeter()
?metrics.GetOrRegister("rate.requests",?m)
?go?metrics.Log(metrics.DefaultRegistry,?time.Second,?log.Default())
?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
??m.Mark(1)
?})
?http.ListenAndServe(":8080",?nil)
}
我們用hey給該web server“施壓”并查看Meter度量指標(biāo)的輸出結(jié)果:
$hey?-c?5?-n?1000000?-m?GET?http://127.0.0.1:8080
$go?run?meter.go
2021/07/04?10:55:59?meter?rate.requests
2021/07/04?10:55:59???count:???????????????0
2021/07/04?10:55:59???1-min?rate:??????????0.00
2021/07/04?10:55:59???5-min?rate:??????????0.00
2021/07/04?10:55:59???15-min?rate:?????????0.00
2021/07/04?10:55:59???mean?rate:???????????0.00
2021/07/04?10:56:00?meter?rate.requests
2021/07/04?10:56:00???count:???????????????0
2021/07/04?10:56:00???1-min?rate:??????????0.00
2021/07/04?10:56:00???5-min?rate:??????????0.00
2021/07/04?10:56:00???15-min?rate:?????????0.00
2021/07/04?10:56:00???mean?rate:???????????0.00
2021/07/04?10:56:01?meter?rate.requests
2021/07/04?10:56:01???count:????????????8155
2021/07/04?10:56:01???1-min?rate:??????????0.00
2021/07/04?10:56:01???5-min?rate:??????????0.00
2021/07/04?10:56:01???15-min?rate:?????????0.00
2021/07/04?10:56:01???mean?rate:????????2718.27
2021/07/04?10:56:02?meter?rate.requests
2021/07/04?10:56:02???count:???????????50937
2021/07/04?10:56:02???1-min?rate:??????????0.00
2021/07/04?10:56:02???5-min?rate:??????????0.00
2021/07/04?10:56:02???15-min?rate:?????????0.00
2021/07/04?10:56:02???mean?rate:???????12734.04
2021/07/04?10:56:03?meter?rate.requests
2021/07/04?10:56:03???count:???????????96129
2021/07/04?10:56:03???1-min?rate:??????19225.00
2021/07/04?10:56:03???5-min?rate:??????19225.00
2021/07/04?10:56:03???15-min?rate:?????19225.00
2021/07/04?10:56:03???mean?rate:???????19225.54
2021/07/04?10:56:04?meter?rate.requests
2021/07/04?10:56:04???count:??????????141076
2021/07/04?10:56:04???1-min?rate:??????19225.00
2021/07/04?10:56:04???5-min?rate:??????19225.00
2021/07/04?10:56:04???15-min?rate:?????19225.00
2021/07/04?10:56:04???mean?rate:???????23512.40
2021/07/04?10:56:05?meter?rate.requests
2021/07/04?10:56:05???count:??????????187733
2021/07/04?10:56:05???1-min?rate:??????19225.00
2021/07/04?10:56:05???5-min?rate:??????19225.00
2021/07/04?10:56:05???15-min?rate:?????19225.00
2021/07/04?10:56:05???mean?rate:???????26818.71
2021/07/04?10:56:06?meter?rate.requests
2021/07/04?10:56:06???count:??????????234874
2021/07/04?10:56:06???1-min?rate:??????19225.00
2021/07/04?10:56:06???5-min?rate:??????19225.00
2021/07/04?10:56:06???15-min?rate:?????19225.00
2021/07/04?10:56:06???mean?rate:???????29358.98
2021/07/04?10:56:07?meter?rate.requests
2021/07/04?10:56:07???count:??????????279201
2021/07/04?10:56:07???1-min?rate:??????19225.00
2021/07/04?10:56:07???5-min?rate:??????19225.00
2021/07/04?10:56:07???15-min?rate:?????19225.00
2021/07/04?10:56:07???mean?rate:???????31022.05
2021/07/04?10:56:08?meter?rate.requests
2021/07/04?10:56:08???count:??????????321704
2021/07/04?10:56:08???1-min?rate:??????21295.03
2021/07/04?10:56:08???5-min?rate:??????19652.92
2021/07/04?10:56:08???15-min?rate:?????19368.43
2021/07/04?10:56:08???mean?rate:???????32170.20
2021/07/04?10:56:09?meter?rate.requests
2021/07/04?10:56:09???count:??????????362403
2021/07/04?10:56:09???1-min?rate:??????21295.03
2021/07/04?10:56:09???5-min?rate:??????19652.92
2021/07/04?10:56:09???15-min?rate:?????19368.43
2021/07/04?10:56:09???mean?rate:???????32945.48
2021/07/04?10:56:10?meter?rate.requests
2021/07/04?10:56:10???count:??????????401442
2021/07/04?10:56:10???1-min?rate:??????21295.03
2021/07/04?10:56:10???5-min?rate:??????19652.92
2021/07/04?10:56:10???15-min?rate:?????19368.43
2021/07/04?10:56:10???mean?rate:???????33453.34
2021/07/04?10:56:11?meter?rate.requests
2021/07/04?10:56:11???count:??????????440905
2021/07/04?10:56:11???1-min?rate:??????21295.03
2021/07/04?10:56:11???5-min?rate:??????19652.92
2021/07/04?10:56:11???15-min?rate:?????19368.43
2021/07/04?10:56:11???mean?rate:???????33915.67
2021/07/04?10:56:12?meter?rate.requests
2021/07/04?10:56:12???count:??????????479301
2021/07/04?10:56:12???1-min?rate:??????21295.03
2021/07/04?10:56:12???5-min?rate:??????19652.92
2021/07/04?10:56:12???15-min?rate:?????19368.43
2021/07/04?10:56:12???mean?rate:???????34235.60
2021/07/04?10:56:13?meter?rate.requests
2021/07/04?10:56:13???count:??????????518843
2021/07/04?10:56:13???1-min?rate:??????22744.85
2021/07/04?10:56:13???5-min?rate:??????19979.77
2021/07/04?10:56:13???15-min?rate:?????19479.57
2021/07/04?10:56:13???mean?rate:???????34589.43
2021/07/04?10:56:14?meter?rate.requests
2021/07/04?10:56:14???count:??????????560260
2021/07/04?10:56:14???1-min?rate:??????22744.85
2021/07/04?10:56:14???5-min?rate:??????19979.77
2021/07/04?10:56:14???15-min?rate:?????19479.57
2021/07/04?10:56:14???mean?rate:???????35016.17
如果使用Meter度量服務(wù)的最佳性能值,那么需要有持續(xù)穩(wěn)定的“施壓”,待1、5、15分鐘速率穩(wěn)定后,這時(shí)的值才有意義。Meter的最后一項(xiàng)mean rate是平均值,即服務(wù)啟動(dòng)后處理請(qǐng)求的總量與程序運(yùn)行時(shí)間的比值。
4) Histogram
Histogram是直方圖,與概率統(tǒng)計(jì)學(xué)上直方圖的概念類似,go-metrics中的Histogram也是用來統(tǒng)計(jì)一組數(shù)據(jù)的統(tǒng)計(jì)學(xué)分布情況的。除了最小值(min)、最大值(max)、平均值(mean)等,它還測(cè)量中位數(shù)(median)、第75、90、95、98、99和99.9百分位數(shù)。
直方圖可以用來度量事件發(fā)生的數(shù)據(jù)分布情況,比如:服務(wù)器處理請(qǐng)求時(shí)長(zhǎng)的數(shù)據(jù)分布情況,下面就是這樣一個(gè)例子:
//?histogram.go?
package?main
import?(
?"log"
?"math/rand"
?"net/http"
?"time"
?"github.com/rcrowley/go-metrics"
)
func?main()?{
?s?:=?metrics.NewExpDecaySample(1028,?0.015)
?h?:=?metrics.NewHistogram(s)
?metrics.GetOrRegister("latency.response",?h)
?go?metrics.Log(metrics.DefaultRegistry,?time.Second,?log.Default())
?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
??i?:=?rand.Intn(10)
??h.Update(int64(time.Microsecond?*?time.Duration(i)))
?})
?http.ListenAndServe(":8080",?nil)
}
在上面這個(gè)例子中,我們使用一個(gè)隨機(jī)值來模擬服務(wù)處理http請(qǐng)求的時(shí)間。Histogram需要一個(gè)采樣算法,go-metrics內(nèi)置了ExpDecaySample采樣。運(yùn)行上述示例,并使用hey模擬客戶端請(qǐng)求,我們得到如下輸出:
$go?run?histogram.go
2021/07/04?11:31:54?histogram?latency.response
2021/07/04?11:31:54???count:???????????????0
2021/07/04?11:31:54???min:?????????????????0
2021/07/04?11:31:54???max:?????????????????0
2021/07/04?11:31:54???mean:????????????????0.00
2021/07/04?11:31:54???stddev:??????????????0.00
2021/07/04?11:31:54???median:??????????????0.00
2021/07/04?11:31:54???75%:?????????????????0.00
2021/07/04?11:31:54???95%:?????????????????0.00
2021/07/04?11:31:54???99%:?????????????????0.00
2021/07/04?11:31:54???99.9%:???????????????0.00
2021/07/04?11:31:55???99.9%:???????????????0.00
...?...
2021/07/04?11:31:59?histogram?latency.response
2021/07/04?11:31:59???count:???????????33244
2021/07/04?11:31:59???min:?????????????????0
2021/07/04?11:31:59???max:??????????????9000
2021/07/04?11:31:59???mean:?????????????4457.20
2021/07/04?11:31:59???stddev:???????????2793.67
2021/07/04?11:31:59???median:???????????4000.00
2021/07/04?11:31:59???75%:??????????????7000.00
2021/07/04?11:31:59???95%:??????????????9000.00
2021/07/04?11:31:59???99%:??????????????9000.00
2021/07/04?11:31:59???99.9%:????????????9000.00
2021/07/04?11:32:00?histogram?latency.response
2021/07/04?11:32:00???count:???????????78970
2021/07/04?11:32:00???min:?????????????????0
2021/07/04?11:32:00???max:??????????????9000
2021/07/04?11:32:00???mean:?????????????4465.95
2021/07/04?11:32:00???stddev:???????????2842.12
2021/07/04?11:32:00???median:???????????4000.00
2021/07/04?11:32:00???75%:??????????????7000.00
2021/07/04?11:32:00???95%:??????????????9000.00
2021/07/04?11:32:00???99%:??????????????9000.00
2021/07/04?11:32:00???99.9%:????????????9000.00
2021/07/04?11:32:01?histogram?latency.response
2021/07/04?11:32:01???count:??????????124573
2021/07/04?11:32:01???min:?????????????????0
2021/07/04?11:32:01???max:??????????????9000
2021/07/04?11:32:01???mean:?????????????4459.14
2021/07/04?11:32:01???stddev:???????????2820.38
2021/07/04?11:32:01???median:???????????4000.00
2021/07/04?11:32:01???75%:??????????????7000.00
2021/07/04?11:32:01???95%:??????????????9000.00
2021/07/04?11:32:01???99%:??????????????9000.00
2021/07/04?11:32:01???99.9%:????????????9000.00
...?...
Histogram度量輸出的值包括min、max、mean(平均數(shù))、median(中位數(shù))、75、95、99、99.9百分位數(shù)上的度量結(jié)果。
5) Timer
最后我們來介紹Timer這個(gè)度量類型。大家千萬(wàn)別被這度量類型的名稱所誤導(dǎo),這并不是一個(gè)定時(shí)器。
Timer是go-metrics定義的一個(gè)抽象度量類型,它可以理解為Histogram和Meter的“合體”,即既度量一段代碼的執(zhí)行頻率(rate),又給出這段代碼執(zhí)行時(shí)間的數(shù)據(jù)分布。這一點(diǎn)從Timer的實(shí)現(xiàn)亦可以看出來:
//?https://github.com/rcrowley/go-metrics/blob/master/timer.go
func?NewTimer()?Timer?{
????if?UseNilMetrics?{
????????return?NilTimer{}
????}
????return?&StandardTimer{
????????histogram:?NewHistogram(NewExpDecaySample(1028,?0.015)),
????????meter:?????NewMeter(),
????}
}
我們看到一個(gè)StandardTimer是由histogram和meter組成的。我們還是以上面的http server服務(wù)為例,我們這次用Timer來度量:
//?timer.go
package?main
import?(
?"log"
?"math/rand"
?"net/http"
?"time"
?"github.com/rcrowley/go-metrics"
)
func?main()?{
?m?:=?metrics.NewTimer()
?metrics.GetOrRegister("timer.requests",?m)
?go?metrics.Log(metrics.DefaultRegistry,?time.Second,?log.Default())
?http.HandleFunc("/",?func(w?http.ResponseWriter,?r?*http.Request)?{
??i?:=?rand.Intn(10)
??m.Update(time.Microsecond?*?time.Duration(i))
?})
?http.ListenAndServe(":8080",?nil)
}
大家可以看到在這里我們同樣用隨機(jī)數(shù)模擬請(qǐng)求的處理時(shí)間并傳給Timer的Update方法。運(yùn)行這段代碼并用hey壓測(cè):
$go?run?timer.go
2021/07/04?17:13:47?timer?timer.requests
2021/07/04?17:13:47???count:???????????13750
2021/07/04?17:13:47???min:?????????????????0.00ns
2021/07/04?17:13:47???max:??????????????9000.00ns
2021/07/04?17:13:47???mean:?????????????4406.61ns
2021/07/04?17:13:47???stddev:???????????2785.11ns
2021/07/04?17:13:47???median:???????????4000.00ns
2021/07/04?17:13:47???75%:??????????????7000.00ns
2021/07/04?17:13:47???95%:??????????????9000.00ns
2021/07/04?17:13:47???99%:??????????????9000.00ns
2021/07/04?17:13:47???99.9%:????????????9000.00ns
2021/07/04?17:13:47???1-min?rate:??????????0.00
2021/07/04?17:13:47???5-min?rate:??????????0.00
2021/07/04?17:13:47???15-min?rate:?????????0.00
2021/07/04?17:13:47???mean?rate:???????13748.57
2021/07/04?17:13:48?timer?timer.requests
2021/07/04?17:13:48???count:???????????56584
2021/07/04?17:13:48???min:?????????????????0.00ns
2021/07/04?17:13:48???max:??????????????9000.00ns
2021/07/04?17:13:48???mean:?????????????4442.61ns
2021/07/04?17:13:48???stddev:???????????2895.66ns
2021/07/04?17:13:48???median:???????????4000.00ns
2021/07/04?17:13:48???75%:??????????????7000.00ns
2021/07/04?17:13:48???95%:??????????????9000.00ns
2021/07/04?17:13:48???99%:??????????????9000.00ns
2021/07/04?17:13:48???99.9%:????????????9000.00ns
2021/07/04?17:13:48???1-min?rate:??????????0.00
2021/07/04?17:13:48???5-min?rate:??????????0.00
2021/07/04?17:13:48???15-min?rate:?????????0.00
2021/07/04?17:13:48???mean?rate:???????28289.23
2021/07/04?17:13:49?timer?timer.requests
2021/07/04?17:13:49???count:??????????102426
2021/07/04?17:13:49???min:?????????????????0.00ns
2021/07/04?17:13:49???max:??????????????9000.00ns
2021/07/04?17:13:49???mean:?????????????4436.77ns
2021/07/04?17:13:49???stddev:???????????2892.85ns
2021/07/04?17:13:49???median:???????????4000.00ns
2021/07/04?17:13:49???75%:??????????????7000.00ns
2021/07/04?17:13:49???95%:??????????????9000.00ns
2021/07/04?17:13:49???99%:??????????????9000.00ns
2021/07/04?17:13:49???99.9%:????????????9000.00ns
2021/07/04?17:13:49???1-min?rate:??????????0.00
2021/07/04?17:13:49???5-min?rate:??????????0.00
2021/07/04?17:13:49???15-min?rate:?????????0.00
2021/07/04?17:13:49???mean?rate:???????34140.68
我們看到Timer度量的輸出也的確是Histogram和Meter的聯(lián)合體!
3. 小結(jié)
通過go-metrics包,我們可以很方便地為一個(gè)Go應(yīng)用添加度量指標(biāo),go-metrics提供的meter、histogram可以覆蓋Go應(yīng)用基本性能指標(biāo)需求(吞吐性能、延遲數(shù)據(jù)分布等)。go-metrics還支持各種指標(biāo)值導(dǎo)出的,只是這里沒有提及,大家可以到go-metrics官網(wǎng)了解詳情。
本文涉及的源碼可以在這里下載[5]?- https://github.com/bigwhite/experiments/tree/master/go-metrics
參考資料
本文永久鏈接:?https://tonybai.com/2021/07/06/add-metrics-for-go-application-using-go-metrics
[2]?Coda Hale's Metrics library:?https://github.com/dropwizard/metrics
[3]?Coda Hale's Metrics library的項(xiàng)目文檔:?https://metrics.dropwizard.io/4.2.0/manual/core.html
[4]?hey工具:?https://github.com/rakyll/hey/
[5]?這里下載:?https://github.com/bigwhite/experiments/tree/master/go-metrics
[6]?改善Go語(yǔ)?編程質(zhì)量的50個(gè)有效實(shí)踐:?https://www.imooc.com/read/87
[7]?Kubernetes實(shí)戰(zhàn):高可用集群搭建、配置、運(yùn)維與應(yīng)用:?https://coding.imooc.com/class/284.html
[8]?我愛發(fā)短信:?https://51smspush.com/
[9]?鏈接地址:?https://m.do.co/c/bff6eed92687
推薦閱讀
