应使用 prometheus.histogramvec 记录耗时、countervec 统计 qps,初始化注册指标并设合理分桶;handler 入口计数、开头记时间、结尾用 seconds() 观察耗时,避免 defer 误用和单位错误。

怎么给 HTTP handler 加上 QPS 和耗时指标?
直接用 promhttp 暴露指标端点,再在 handler 里用 prometheus.HistogramVec 记录耗时、prometheus.CounterVec 统计请求数。别自己手写原子计数器——Prometheus 官方 client 已经做了并发安全封装。
常见错误是把 Observe() 放在 defer 里但没传入正确的时间差,或者忘记调用 Inc() 导致 QPS 始终为 0。耗时必须是 float64 秒单位(不是毫秒),否则直方图分桶会全挤在 0~0.001s 区间里。
- 初始化时注册指标:用
prometheus.NewHistogramVec定义耗时指标,标签建议至少包含method和path - 在 handler 开头记录开始时间:
start := time.Now() - 在 handler 结尾调用:
histogram.WithLabelValues(r.Method, r.URL.Path).Observe(time.Since(start).Seconds()) - QPS 计数放在 handler 入口:
counter.WithLabelValues(r.Method, r.URL.Path).Inc()
为什么 histogram.Buckets 要手动设?默认值根本不能用
默认的 prometheus.DefBuckets 是 [0.005, 0.01, 0.025, ...],单位秒,对应 5ms ~ 10s。对多数 Web API 来说太细(99% 请求在 100ms 内)又太粗(超时 30s 的请求全堆在最后一个桶)。结果就是 P99 看起来是 0.1s,实际可能是 28s —— 因为所有慢请求都进了最大桶。
实战建议按业务 SLA 设:比如接口要求 99% []float64{0.05, 0.1, 0.2, 0.5, 1.0, 3.0}(单位秒)。这样 P99 才真能反映真实长尾。
- 别复用全局 histogram 实例去打不同延迟特征的接口——不同业务延迟分布差异大,混用会导致分桶失效
- 如果用了 Gin/Echo 等框架,注意中间件里
next(c)后再Observe(),否则 panic 时耗时统计不到
如何避免 metrics 暴增导致内存泄漏?
标签值不可控时(比如 user_id、order_id),WithLabelValues 会为每个唯一组合创建新指标实例,几分钟就能吃光内存。Prometheus 官方明确警告:标签值必须是有限集合。
典型翻车场景:用 r.URL.Query().Get("id") 当标签值;或把 r.RemoteAddr 当标签。这些本质上是无限集。
- 只允许用稳定枚举值做标签:如
method、status_code、预定义的service_name - 动态值一律打到日志,或走 tracing(如 Jaeger),别塞进 metrics
- 加一层防御:用
strings.HasPrefix(r.URL.Path, "/api/v1/")截断路径,避免带参数的长 URL 生成爆炸性 label
怎么验证埋点是否生效?
别等 Grafana 配好才看——直接 curl /metrics 端点,搜 http_request_duration_seconds 和 http_requests_total。看到行末有 {method="GET",path="/health"} 123 这种才算活的。
容易被忽略的是:指标名里带 _total 后缀的 counter 必须配合 PromQL 的 rate() 函数算 QPS,直接看原始值毫无意义。而 histogram 的 _sum 和 _count 也要一起存在,缺一不可,否则 histogram_quantile() 会返回空。
- 启动后立刻发几笔请求,再 curl 指标端点,确认 label 值符合预期(比如 path 不是
/user/12345而是/user/:id) - 检查 Prometheus server 的 targets 页面,确认 job 状态是 UP,且 last scrape 时间距现在
- 如果用的是
promauto包,注意它默认注册到 default registry,和promhttp.Handler()用的 registry 要一致
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











