针对中小型项目,介绍一下简单的 Prometheus 监控方案。
Prometheus 帮助我们解决了 Metrics 监控的难题,后续出现的 Thanos 解决了 Prometheus 存储扩展的难题。总体来说,Prometheus 已经是一个非常成熟的监控方案。 各大云厂商也相继推出了云版本的 Prometheus,用户可以不用去考虑如何运维 Prometheus,降低了人工运维成本。
既然 Prometheus 的运行问题已经得到解决,接下来就看看,如何使用它。
棘手的问题
Prometheus 的 Client 接口设计的很合理,使用上也没什么问题。随之会出现几个棘手的问题。
- 监控什么
- 代码里怎么写监控指标,Label 该怎么带
- 怎么配置图形化
不要小看这个问题,监控什么跟设计 API 一样不是一件容易的事。如果我们强行往代码里【塞入】Prometheus 监控相关代码,我敢保证,代码会很乱。
举个例子,监控一个函数运行了多长时间,我们要做如下几个事。
- 合理命名监控项
- 合理配置 Label
- 代码里嵌入计时代码
- 处理错误逻辑
- 图像化
光上面几个逻辑,至少需要20+行代码,如果每个函数都是如此,整个项目的代码会非常【难看】。
对于追求【干净,简介】代码的我们来说,这是一个难受的体验。
干净的解决方案
这里我们介绍 rk-boot/v2 + Prometheus + Grafana 的解决方案。这个方案里,我们使用两个方法解决上述棘手的问题。
简单来说,就是在函数里面添加两行代码,监控这个函数。
- Wrap Prometheus 相关逻辑
- 现成 Grafana 图表
代码干净
Golang 不像 Spring 一样有 annotation 的支持,可以在函数上面标记一个 @xxx 可以轻松实现函数监控。不过,我们可以在代码里添加【两行代码】,以最低成本实现函数监控。
现成图表(Grafana)
有一个通用 Grafana 监控 Dashboard 是一个很幸福的事情,毕竟上手 Grafana 不是几个小时就能搞定的事情。
Demo
1.Docker 启动 Prometheus
我们需要创建一个 prometheus.yml 文件,告诉 prometheus 从哪里收集监控数据。
- prometheus.yml
- 启动 Prometheus
2.使用 Docker 启动 grafana 并配置 Prometheus
初始化账号: admin
初始化密码:admin

- 选择 Prometheus 为数据源

- 配置 Prometheus 地址

3.下载 rk-boot/v2
rk-boot/v2 是可以通过 YAML 文件启动 Golang 流行框架的依赖库,里面包含了很多实用中间件。
为了模拟微服务,我们同时还下载 rk-gin/v2 来启动 gin-gonic 服务。
4.配置 boot.yaml
boot.yaml 文件告诉 rk-boot/v2 启动哪些 Gin 配套的服务。
5.写个 API
6.启动 main.go & 发送请求
7.查看图形化监控
boot.yaml 文件告诉 Gin 启动 API 监控中间件,所以我们可以监控两个东西。
rk-prom: 自动记录每个 API 的 Metrics,有默认 grafana dashboard rk-cursor: 代码里嵌入的监控(就是我们写的那两行代码),有默认 grafana dashboard
- 引入 rk-prom dashboard (代号:15111):



我们可以看到 API 的监控了,不需要任何代码改动。

- 引入 rk-cursor dashboard (代号:15937):

我们可以看到 Cursor 的监控了

8.解释一下 rk-prom & rk-cursor dashboard
rk-prom 是一个自带的监控中间件,会默认监控所有 API 的运行时间,错误码。包含的监控项有【运行时间】,【API 可用性】,【API 速率】
如果想要看到本地的输出的监控数据,可以查看 localhost:8080/metrics
rk-cursor 是一个 struct,通过 Click() 方法获取一个 Pointer struct,再通过 pointer.Release() 方法结束监控。 会默认监控所有 API 的运行时间,错误码。包含的监控项有【Function 运行时间】,【Function 可用性】,【Function 速率】。
rk-cursor 使用方法
rk-cursor 可以实现如下三个监控。
- 监控 Function 运行时间
- 监控 Function 错误
- 监控 Function 里调用其他 Function 的运行时间(相当于 1层的调用链)
监控 Function 错误
对于上面的代码进行一行改动。
再运行一次,发送请求,并观察日志和 grafana dashboard

监控 Function 调用链
rk-cursor 会使用 runtime.Caller() 函数记录上一层调用函数的名字。
举个例子,Greeter() 函数调用 B() 函数和 C() 函数,那么我们可以观察 Greeter() 函数的里,B() 和 C() 花了多尝试时间。
我们稍微修改一下 main.go
这个例子里,函数的入口是 main.Greeter(),这个函数的 parentOperation 标记为 -

main.Greeter() 调用了 B() 和 C(),在 parentOperation 里选择 main.Greeter(),我们就可以看到,1层的调用链。
