必须用CounterVec而非Counter的指标包括HTTP请求总量、消息队列消费成功数、数据库写入行数,因其需按method/path/status_code等低基数维度切分且只增不减;错误做法是将user_id等高基数字段打入标签,应改用Histogram记录延迟并在日志/trace中关联业务ID。

Go微服务监控告警系统里,指标定义不是“写几个Prometheus Counter就行”,关键在是否能对齐业务故障域、是否可下钻归因、是否避免标签爆炸。
哪些指标必须用prometheus.CounterVec而非prometheus.Counter
HTTP请求总量、消息队列消费成功数、数据库写入行数这类“只增不减+需按维度切分”的场景,必须用CounterVec。比如:
httpRequestsTotal := prometheus.NewCounterVec(
prometheus.CounterOpts{
Name: "http_requests_total",
Help: "Total HTTP requests processed",
},
[]string{"method", "path", "status_code"}, // 标签不能含业务ID、用户ID等高基数字段
)- 错误做法:把
user_id或order_id塞进标签——会导致时间序列爆炸,Prometheus内存飙升甚至OOM - 正确替代:用
prometheus.Histogram记录响应延迟,并在日志或trace中关联业务ID - 注意
CounterVec的WithLabelValues()调用频率要可控,避免在高频循环内无节制打点
为什么prometheus.Gauge不适合记录“当前在线用户数”
它适合瞬时值(如内存使用率、goroutine数量),但“在线用户数”本质是状态聚合,直接用Gauge更新极易因上报延迟/重试/重启导致数据跳变或丢失。
- 更稳的做法:用
CounterVec记录登录/登出事件,再通过PromQL计算rate(login_events_total[1h]) - rate(logout_events_total[1h])做趋势估算 - 若必须暴露实时值,改用
prometheus.NewGaugeFunc,从本地缓存(如sync.Map)拉取,避免每次打点都写TSDB - 警惕
Gauge被误设为负值——Prometheus不拒绝,但Grafana图表会断层,建议在Set前加math.Max(0, v)
自定义指标命名和标签怎么避开Prometheus反模式
Prometheus官方规范要求指标名用snake_case,且以子系统名开头;标签名统一小写,禁止用typeclassid等泛化词。
立即学习“go语言免费学习笔记(深入)”;
- 错例:
user_count→ 应为auth_user_active_total(明确子系统+语义+类型) - 错例:
label="prod"→ 应为env="prod"(所有服务统一用env,别用environment或stage) - 错例:
service="order"+instance="10.0.1.5:8080"→ 实际应由Prometheus服务发现自动注入job和instance,代码里只保留业务维度如clustershard - Go SDK默认启用
go_*指标,若服务无GC压力可关掉:prometheus.Unregister(prometheus.NewGoCollector())
指标定义最易被忽略的点:没有配套设计对应的告警规则和降级兜底逻辑。比如定义了rpc_client_errors_total,却没配rate(rpc_client_errors_total[5m]) > 0.1的告警,也没在错误率超阈值时自动切换降级接口——那这个指标只是个好看的数据装饰品。


















