共计 3190 个字符,预计需要花费 8 分钟才能阅读完成。
最近对服务进行监控,而以后监控最风行的数据库就是 Prometheus
,同时 go-zero
默认接入也是这款数据库。明天就对 go-zero
是如何接入 Prometheus
,以及开发者如何本人定义本人监控指标。
监控接入
go-zero
框架中集成了基于 prometheus
的服务指标监控。然而没有显式关上,须要开发者在 config.yaml
中配置:
Prometheus:
Host: 127.0.0.1
Port: 9091
Path: /metrics
如果开发者是在本地搭建 Prometheus
,须要在 Prometheus
的配置文件 prometheus.yaml
中写入须要收集服务监控信息的配置:
- job_name: 'file_ds'
static_configs:
- targets: ['your-local-ip:9091']
labels:
job: activeuser
app: activeuser-api
env: dev
instance: your-local-ip:service-port
因为本地是用 docker
运行的。将 prometheus.yaml
搁置在 docker-prometheus
目录下:
docker run \
-p 9090:9090 \
-v dockeryml/docker-prometheus:/etc/prometheus \
prom/prometheus
关上 localhost:9090
就能够看到:
点击 http://service-ip:9091/metrics
就能够看到该服务的监控信息:
上图咱们能够看出有两种 bucket
,以及 count/sum
指标。
那 go-zero
是如何集成监控指标?监控的又是什么指标?咱们如何定义咱们本人的指标?上面就来解释这些问题
以上的根本接入,能够参看咱们的另外一篇:https://zeromicro.github.io/g…
如何集成
下面例子中的申请形式是 HTTP
,也就是在申请服务端时,监控指标数据一直被收集。很容易想到是 中间件 的性能,具体代码:https://github.com/tal-tech/g…。
var (
metricServerReqDur = metric.NewHistogramVec(&metric.HistogramVecOpts{
...
// 监控指标
Labels: []string{"path"},
// 直方图散布中,统计的桶
Buckets: []float64{5, 10, 25, 50, 100, 250, 500, 1000},
})
metricServerReqCodeTotal = metric.NewCounterVec(&metric.CounterVecOpts{
...
// 监控指标:间接在记录指标 incr() 即可
Labels: []string{"path", "code"},
})
)
func PromethousHandler(path string) func(http.Handler) http.Handler {return func(next http.Handler) http.Handler {return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
// 申请进入的工夫
startTime := timex.Now()
cw := &security.WithCodeResponseWriter{Writer: w}
defer func() {
// 申请返回的工夫
metricServerReqDur.Observe(int64(timex.Since(startTime)/time.Millisecond), path)
metricServerReqCodeTotal.Inc(path, strconv.Itoa(cw.Code))
}()
// 中间件放行,执行完后续中间件和业务逻辑。从新回到这,做一个残缺申请的指标上报
// [????:洋葱模型]
next.ServeHTTP(cw, r)
})
}
}
其实整个很简略:
-
HistogramVec
负责申请耗时收集:bucket
寄存的就是option
指定的耗时指标。某个申请耗时多少就会被汇集对应的桶,计数。- 最终展现的就是一个路由在不同耗时的散布,很直观提供给开发者能够优化的区域。
-
CounterVec
负责指定labels
标签收集:Labels: []string{"path", "code"}
labels
相当一个tuple
。go-zero
是以(path, code)
作为整体,记录不同路由不同状态码的返回次数。如果4xx,5xx
过多的时候,是不是应该看看你的服务衰弱水平?
如何自定义
go-zero
中也提供了 prometheus metric
根本封装,供开发者本人开发本人 prometheus
中间件。
代码:https://github.com/tal-tech/g…
名称 | 用处 | 收集函数 |
---|---|---|
CounterVec | 繁多的计数。用做:QPS 统计 | CounterVec.Inc() 指标 +1 |
GuageVec | 单纯指标记录。实用于磁盘容量,CPU/Mem 使用率(可减少可缩小) | GuageVec.Inc()/GuageVec.Add() 指标 +1/ 指标加 N,也能够为正数 |
HistogramVec | 反馈数值的散布状况。实用于:申请耗时、响应大小 | HistogramVec.Observe(val, labels) 记录指标以后对应值,并找到值所在的桶,+1 |
另外对
HistogramVec.Observe()
做一个根本剖析:咱们其实能够看到上图每个
HistogramVec
统计都会有 3 个序列呈现:
_count
:数据个数_sum
:全副数据加和_bucket{le=a1}
:处于[-inf, a1]
的数据个数所以咱们也猜想在统计过程中,分 3 种数据进行统计:
// 基本上在 prometheus 的统计都是应用 atomic CAS 形式进行计数的 // 性能要比应用 Mutex 要高 func (h *histogram) observe(v float64, bucket int) {n := atomic.AddUint64(&h.countAndHotIdx, 1) hotCounts := h.counts[n>>63] if bucket < len(h.upperBounds) { // val 对应数据桶 +1 atomic.AddUint64(&hotCounts.buckets[bucket], 1) } for {oldBits := atomic.LoadUint64(&hotCounts.sumBits) newBits := math.Float64bits(math.Float64frombits(oldBits) + v) // sum 指标数值 +v(毕竟是总数 sum)if atomic.CompareAndSwapUint64(&hotCounts.sumBits, oldBits, newBits) {break} } // count 统计 +1 atomic.AddUint64(&hotCounts.count, 1) }
所以开发者想定义本人的监控指标:
- 在应用
goctl
生成 API 代码指定要生成的 中间件:https://zeromicro.github.io/g… - 在中间件文件书写本人须要统计的指标逻辑
- 当然,开发者也能够在业务逻辑中书写统计的指标逻辑。同上。
上述都是针对 HTTP
局部逻辑的解析,RPC
局部的逻辑相似,你能够在 拦截器 局部看到设计。
总结
本文剖析了 go-zero
服务监控指标的逻辑,当然对于一些基础设施的监控,prometheus
能够通过引入对应的 exporter
来实现。
我的项目地址
https://github.com/tal-tech/go-zero
欢送应用 go-zero 并 star 反对咱们!
go-zero 系列文章见『微服务实际』公众号