用Prometheus+client_golang采集Go微服务HTTP延迟和错误率,需:1.用HistogramVec按预定义路径分组(如/api/v1/users/*)记录延迟,避免标签爆炸;2.用CounterVec按status_code和route_group统计错误率;3.在init或启动早期注册指标,确保/metrics端点正确挂载并返回非空数据。

如何用 Prometheus + client_golang 采集 Go 微服务的 HTTP 请求延迟和错误率
Go 微服务默认不暴露任何可观测指标,必须手动集成 prometheus/client_golang 并注册指标。关键不是“加库”,而是选对指标类型和暴露时机。
常见错误是直接在 http.HandlerFunc 里用 promauto.NewHistogramVec 记录每次请求耗时,结果导致高频服务下 goroutine 泄漏或标签爆炸(比如把 req.URL.Path 全量当 label)。正确做法是预定义路径分组(如 /api/v1/users/*、/health),再用 WithLabelValues 控制 label 维度。
- 延迟指标优先用
prometheus.HistogramVec,而非SummaryVec:Histogram 支持服务端聚合,适合多实例统一计算 P95;Summary 在客户端计算分位数,无法跨实例合并 - 错误率建议用
prometheus.CounterVec统计状态码,label 至少包含status_code和route_group,避免只记2xx/5xx这种粗粒度分类 - 务必在
init()或服务启动早期调用prometheus.MustRegister(),否则http.Handler中调用Observe()会 panic
为什么 /metrics 端点返回空或 404,但程序没报错
空响应或 404 通常不是路由问题,而是 promhttp.Handler() 没被正确挂载,或指标未被注册到默认 registry。
典型场景:你用了自定义 prometheus.Registry,但 promhttp.Handler() 默认读的是 prometheus.DefaultRegisterer。或者你在多个包里重复调用 promauto.NewCounter,而没传入同一个 registry 实例,导致部分指标“注册丢失”。
立即学习“go语言免费学习笔记(深入)”;
- 检查是否误用了
promhttp.HandlerFor(reg, promhttp.HandlerOpts{})却传了空 registry —— 此时返回空 body,HTTP 状态码仍是 200 - 确认
http.HandleFunc("/metrics", promhttp.Handler().ServeHTTP)是最后注册的路由,避免被更宽泛的通配路由(如http.HandleFunc("/", ...))覆盖 - 本地调试时 curl
curl -v http://localhost:8080/metrics,若返回 200 但 body 为空,立刻检查prometheus.DefaultRegistry.Gather()返回值长度是否为 0
Grafana 告警规则中 should_use_for 的陷阱:什么时候该用 increase() 而不是 rate()
在微服务场景下,用 rate() 计算错误率容易误告:当某实例短暂重启或 scrape 失败,rate(http_requests_total{code=~"5.."}[5m]) 可能因分子突增、分母归零而产生极大噪声值。
increase() 更稳定,但它依赖单调递增计数器且时间窗口内不能有重置(counter reset)。Go 的 prometheus.Counter 在进程重启时会重置,所以必须配合 rate() 的内置重置处理逻辑 —— 这也是为什么官方文档强调:永远优先用 rate(),除非你明确控制了 counter 生命周期。
- 真正该用
increase()的场景:短周期内统计绝对增量(如“过去 1 分钟新增订单数”),且你已确保该 counter 不会在窗口内重置 - 告警阈值设为
rate(http_errors_total[5m]) > 0.05比increase(http_errors_total[5m]) > 10更可靠,因为后者在低流量服务中可能永远不触发(基数太小) - Prometheus 2.30+ 开始支持
resets()函数,可检测 counter 重置次数,用于辅助判断increase()是否可信
告警静默与抑制配置常被忽略的两个细节
微服务集群中,一个节点宕机常触发连锁告警(如 node_down → process_cpu_usage_high → api_latency_p95_high),但多数人只配了 alert rules,没配 inhibit_rules 或 mute_time_intervals,导致值班人员被刷屏。
另一个易错点是静默规则匹配字段写错:Prometheus 静默基于 alert 的 label 匹配,不是 metrics 的 label。例如你的 alert rule 定义了 labels: {service: "auth", severity: "critical"},那么静默规则的 matchers 必须写 service = "auth",而不是 job = "auth-service"(后者是 target label)。
- 抑制规则中
source_matchers应尽量窄(如只匹配alertname = "InstanceDown"),target_matchers可稍宽(如service =~ "auth|order|payment"),避免过度抑制 - 使用
time_intervals配置维护窗口时,注意时区:所有时间按 UTC 解析,即使你的alertmanager.yml里写了location: Asia/Shanghai,它只影响 UI 显示,不影响匹配逻辑 - 测试静默是否生效?用
curl -s http://alertmanager/api/v2/alerts | jq '.[] | select(.status.state == "firing")'查看 firing alerts 的labels,再比对静默规则的matchers
by (job, instance) 分组 —— 这类细微偏差在多副本部署中几乎必然出现,但排查时最容易被当成“监控不准”。



















