最近对服务进行监控,而当前监控最流行的数据库就是 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 是如何集成监控指标?监控的又是什么指标?我们如何定义我们自己的指标?下面就来解释这些问题
如何集成
上面例子中的请求方式是 HTTP,也就是在请求服务端时,监控指标数据不断被搜集。很容易想到是 中间件 的功能,具体代码:https://github.com/tal-tech/go-zero/blob/master/rest/handler/prometheushandler.go。
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 中间件。
| 名称 | 用途 | 搜集函数 | 
|---|---|---|
| CounterVec | 单一的计数。用做:QPS统计 | 
CounterVec.Inc() 指标+1 | 
| GuageVec | 单纯指标记录。适用于磁盘容量,CPU/Mem使用率(可增加可减少) | 
GuageVec.Inc()/GuageVec.Add() 指标+1/指标加N,也可以为负数 | 
| HistogramVec | 反应数值的分布情况。适用于:请求耗时、响应大小 | 
HistogramVec.Observe(val, labels) 记录指标当前对应值,并找到值所在的桶,+1 | 
所以开发者想定义自己的监控指标:
- 在使用 
goctl生成API代码指定要生成的 中间件:https://zeromicro.github.io/go-zero/middleware.html - 在中间件文件书写自己需要统计的指标逻辑
 - 当然,开发者也可以在业务逻辑中书写统计的指标逻辑。同上。
 
上述都是针对 HTTP 部分逻辑的解析,RPC 部分的逻辑类似,你可以在 拦截器 部分看到设计。
总结
本文分析了 go-zero 服务监控指标的逻辑,当然对于一些基础设施的监控,prometheus 可以通过引入对应的 exporter 来完成。
项目地址
https://github.com/tal-tech/go-zero
欢迎使用 go-zero 并 star 支持我们!










