go服务暴露prometheus指标需正确注册/metrics路径并启用runtime指标;自定义指标要复用vec实例避免高基数;prometheus采样间隔与grafana刷新频率需对齐,且保留时间配置合理。

Go 服务怎么暴露 Prometheus 指标
Go 微服务要被 Grafana 看见,第一步不是配 Grafana,而是让服务自己把指标“说清楚”。用 promhttp 暴露 HTTP 接口是最直接的方式,但很多人卡在路径注册不对或中间件拦截了 /metrics。
常见错误现象:curl http://localhost:8080/metrics 返回 404 或空响应;Grafana 显示 “no data”;Prometheus 抓取状态为 DOWN。
- 确保用
http.Handle("/metrics", promhttp.Handler())注册,不是http.HandleFunc—— 后者不支持 Prometheus 的 Content-Type 自协商 - 如果用了 Gin/echo 等框架,别直接挂到
router.GET("/metrics", ...),得用中间件桥接:Gin 要用gin.WrapH(promhttp.Handler()),echo 要用echo.WrapHandler(promhttp.Handler()) - 检查防火墙和 k8s Service 是否开放了指标端口(默认 2112 或 8080),且
Pod的readinessProbe别误把/metrics当健康检查入口
Grafana 里查不到 Go 运行时指标怎么办
Go 标准库自带的 runtime 指标(比如 go_goroutines、go_memstats_alloc_bytes)默认就注册在 prometheus.DefaultRegisterer 里,但前提是你的服务显式调用了 prometheus.MustRegister(...) 或启用了自动采集 —— 很多人漏了这步。
使用场景:你想看协程暴涨、内存泄漏、GC 频次,但 Grafana 面板里这些指标名压根不出现。
立即学习“go语言免费学习笔记(深入)”;
- 在
main()开头加一行:prometheus.MustRegister(prometheus.NewGoCollector())(v1.14+ 可省略,但低版本必须显式注册) - 别依赖第三方 SDK 自动埋点 —— 比如某些封装过的
promauto工具包可能没开 runtime 收集,得单独确认 - 验证方式:curl
/metrics后搜go_goroutines,有输出才说明 runtime 指标已暴露;没有就代表注册失败或被覆盖
自定义业务指标在 Grafana 里数值跳变或归零
用 prometheus.NewCounterVec 或 prometheus.NewHistogramVec 埋点时,指标值突变、断崖式归零、或者同一 label 组合反复创建新指标实例,基本都是生命周期管理出问题。
性能影响:每个未复用的 CounterVec 实例会占用独立内存 + Prometheus 存储空间,k8s 下 Pod 重启后若没持久化,旧指标就永远丢失。
- 全局变量声明一次,初始化一次:
var httpReqCount = prometheus.NewCounterVec(...); func init() { prometheus.MustRegister(httpReqCount) } - 别在 handler 里 new Vec、别在循环里
vec.WithLabelValues(...).Inc()前不缓存prometheus.Labels—— label 字符串拼错或顺序错,会生成新时间序列 - 注意 label 值不能含空格、斜杠、等号等非法字符,否则指标写入失败但无报错,表现为“数据消失”
Grafana 面板显示延迟高或查询超时
PromQL 查询慢,不一定是 Grafana 或网络问题,大概率是 Go 服务打点太密、label 组合爆炸,或者 Prometheus 配置没对齐采样节奏。
兼容性影响:Grafana 默认每 15s 刷一次面板,如果 Prometheus 5 分钟才 scrape 一次,面板就只能看到“阶梯状”折线,且历史数据稀疏。
- 检查 Prometheus 的
scrape_interval(建议设为15s),同时 Go 服务的指标采集逻辑别做耗时操作(比如在Counter.Inc()前查 DB) - 避免高基数 label:比如用
user_id当 label,10 万用户就生成 10 万时间序列,Prometheus 内存和查询都会崩 - Grafana 查询时少用
rate()套多层函数嵌套,优先用sum by (job) (rate(http_req_total[5m]))这类聚合先行的写法
最常被忽略的是:Prometheus 的 storage.tsdb.retention.time 设得太短(比如 2h),导致刚配好的面板查不到昨天的数据,不是配置错,是数据早被删了。










