白名单优先级高于黑名单,AllowedLabels为空时仅放行指定标签,BlockedLabels形同虚设;混用无意义,应根据场景单用其一。

AllowedLabels 和 BlockedLabels 怎么配才不冲突?
白名单和黑名单同时设置时,AllowedLabels 优先级更高——哪怕某个标签在 BlockedLabels 里,只要它没出现在 AllowedLabels 中,照样被过滤掉。这不是“先黑后白”,而是“只放行白名单里的,其余全拒”。
常见误配:AllowedLabels = []string{"env", "service"} 同时又写 BlockedLabels = []string{"user_id", "request_id"},以为能“保底拦截”,其实 user_id 根本不会进到过滤逻辑里,因为第一步就被白名单机制拦死了。
- 只用黑名单:适合已知几个高危标签(如
user_id、trace_id),其他都留着 - 只用白名单:适合明确业务维度(如
env、region、endpoint),其余一律不信任 - 两者混用无意义:白名单已做严格收口,黑名单形同虚设
为什么 metrics.NewCounterVec 的 label 基数比直写 string 更危险?
NewCounterVec 本身不控制基数,它只是把 label 组合映射成内部 map key。一旦你传入的 WithLabelValues("GET", "200", "user_id_12345"),就等于为每个用户创建一个独立时间序列——Prometheus 里会生成 http_requests_total{method="GET",status="200",user_id="user_id_12345"} 这种指标,而 user_id_12345 是典型高基数值。
对比直接拼字符串:fmt.Sprintf("http_requests_total{method=\"%s\",status=\"%s\"}", method, status) 虽然丑,但至少你得手动拼、手动发,不容易误塞动态值;而 WithLabelValues 看似安全,实则把“构造 label”这步封装掉了,反而更容易漏检。
立即学习“go语言免费学习笔记(深入)”;
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 必须提前对 label 值做泛化:比如
path不能是/users/12345,得转成/users/{id} - 禁止把请求上下文字段(
user_id、order_no、ip)直接塞进WithLabelValues - 上线前用
curl http://localhost:8080/metrics | grep -E 'your_metric_name.*=' | wc -l粗估时间序列数量,超 1000 就要查 label 来源
go-metrics 的标签过滤在 StatsdSink 和 PrometheusSink 下行为一致吗?
不一致。AllowedLabels 和 BlockedLabels 是 metrics.Config 层的逻辑,只对 go-metrics 内部指标对象生效;但不同 Sink 对 label 的处理方式不同:
StatsdSink(如 StatsiteSink)会把 label 拼进 metric key 名,例如 http.requests.total.env.prod.service.api,此时过滤发生在 key 构建前,有效。
PrometheusSink 则依赖 prometheus.CounterVec 的原生 label 机制,go-metrics 的 Config 过滤对它**完全无效**——因为 PrometheusSink 不走 go-metrics 的 label 路径,而是把整个 CounterVec 当作黑盒透传。你配了 AllowedLabels,Prometheus 该收的高基数 label 还是全收。
- 用 PrometheusSink 时,必须靠
prometheus.NewCounterVec自身的 label 定义 + 上游代码过滤来控基数 - 用 StatsdSink 时,
Config.AllowedLabels才真正起作用 - 别指望一套配置通吃所有 Sink,切换 Sink 时必须重验 label 行为
label 基数爆炸后,第一反应不该是加机器
内存暴涨、查询变慢、Prometheus OOM,这些表象背后往往不是资源不够,而是某条指标的 label 组合失控。比如 http_request_duration_seconds_bucket{le="0.1", path="/api/search?q=xxx"},其中 q=xxx 是未脱敏的查询参数,distinct 值上万,每个都生成新 bucket 时间序列。
这种问题没法靠横向扩容解决:加节点只会让每台 Prometheus 都存一份爆炸数据,且 federate 查询更卡。真正要做的,是立刻停掉对应埋点,回溯代码中 Observe() 或 Inc() 的调用点,检查 label 值来源是否含动态 ID、随机串、长文本等。
- 本地调试时加一行
log.Printf("label values: %+v", labels),确认值是否稳定 - 生产环境用
prometheus_tsdb_head_series_created_total监控新 series 创建速率,突增即告警 - 别在 label 里塞 JSON 或 URL 参数——那是日志的事,不是指标的事

















