必须手动注册 NewGoCollector(),否则 /metrics 中看不到 gogc* 等运行时指标;Kratos 默认不暴露 GC 指标是因为其 Prometheus 中间件仅注册业务指标,而 Go client 库仅提供收集器,不自动调用 MustRegister()。

必须手动注册 NewGoCollector(),否则 /metrics 里根本看不到 go_gc_* 系列指标。
为什么 Kratos 默认不暴露 GC 指标
Kratos 自带的 Prometheus 中间件(如 prometheus.NewServer() 或 kratos/middleware/metrics)只负责注册业务指标(如 HTTP 请求计数、延迟直方图),go_goroutines、go_gc_duration_seconds 这类运行时指标不属于业务逻辑,Go client 库不会自动注册——它只提供收集器,不替你调 MustRegister()。
常见现象:curl http://localhost:8080/metrics | grep gc 返回空,但 go_goroutines 也同时缺失,说明整个 runtime 指标链路没打通。
- 不是 Kratos 的 bug,是所有基于
prometheus/client_golang的框架共性约束 - 哪怕你用了
promhttp.Handler(),只要没显式注册NewGoCollector(),指标就不存在 - 如果 Kratos 项目用了自定义
prometheus.Registry(比如通过metrics.WithRegistry(reg)配置),那更得确保NewGoCollector()是注册到这个 registry 上,而不是默认全局注册器
正确注册方式:init() 或 main() 开头执行
在 Kratos 启动流程早期(init() 函数或 main() 最开头)注册,不能放在 HTTP handler 里、中间件里、或者服务启动之后的任意 goroutine 中——MustRegister() 是一次性操作,重复调用会 panic。
示例代码:
func init() {
// 必须注册,否则 /metrics 无 go_gc_* 等指标
prometheus.MustRegister(prometheus.NewGoCollector())
prometheus.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
}
如果你的 Kratos 项目使用了自定义 registry(例如通过 app := kratos.New(..., metrics.WithRegistry(reg))),则需改为:
reg := prometheus.NewRegistry()
reg.MustRegister(prometheus.NewGoCollector())
reg.MustRegister(prometheus.NewProcessCollector(prometheus.ProcessCollectorOpts{}))
// 再传给 Kratos metrics 中间件
注意 GOMEMLIMIT 和 GOGC 对 GC 指标的意义
go_gc_duration_seconds 等指标本身只是记录 GC 行为,但要让这些数据有分析价值,得配合运行时调参:
-
GOGC=50会让 GC 更频繁,go_gc_duration_seconds_count上升明显,适合压测中观察抖动 -
GOMEMLIMIT=2GiB(环境变量或debug.SetMemoryLimit())会强制 runtime 在接近该阈值时提前触发 GC,此时go_gc_pauses_seconds_total可能增加,但能避免容器 OOM kill - 别依赖单次
go_gc_pauses_seconds_total绝对值——要看 P99 延迟趋势,结合go_memstats_heap_alloc_bytes判断是否内存泄漏
GC 指标不是“开了就能用”,而是“注册了 + 调参了 + 持续采样了”才真正可用。漏掉任一环,Prometheus 抓到的都是静止或失真的数字。











