Go服务需暴露/metrics端点并用prometheus/client_golang库注册指标,K8s中通过ServiceMonitor按label和port名自动发现,告警由Prometheus规则基于直方图等指标触发,需确保格式合规、响应及时。

Go 服务怎么暴露 Prometheus 指标端点
Go 服务要被 Prometheus 抓取,必须提供 /metrics HTTP 端点,返回符合 Prometheus 文本格式的指标数据。不暴露这个端点,监控系统根本看不到你的服务。
推荐用官方库 prometheus/client_golang,它提供 http.Handler 实现和指标注册器,避免手写格式出错。
- 初始化全局注册器:
prometheus.MustRegister(...)或自定义prometheus.NewRegistry()避免与第三方库冲突 - 指标类型选对:计数器(
prometheus.CounterVec)适合请求总量、错误次数;直方图(prometheus.HistogramVec)适合响应延迟;不要用Gauge记录请求量——它不累加,会覆盖 - HTTP 路由别写成
http.HandleFunc("/metrics", handler),要用http.Handle("/metrics", promhttp.HandlerFor(registry, promhttp.HandlerOpts{})),否则缺失 Content-Type 和压缩支持
package mainimport ( "net/http" "github.com/prometheus/client_golang/prometheus" "github.com/prometheus/client_golang/prometheus/promhttp" )
var ( httpRequestsTotal = prometheus.NewCounterVec( prometheus.CounterOpts{ Name: "http_requests_total", Help: "Total number of HTTP requests.", }, []string{"method", "status_code"}, ) )
func init() { prometheus.MustRegister(httpRequestsTotal) }
func main() { http.Handle("/metrics", promhttp.Handler()) http.ListenAndServe(":8080", nil) }
如何在 Kubernetes 中自动发现 Go 服务并抓取指标
Prometheus 在 K8s 里靠 ServiceMonitor 或 PodMonitor(取决于你用的是 Prometheus Operator)来动态发现目标。直接改 scrape_configs 手动加静态 target 不可持续,也绕过声明式管理。
关键不是“能不能抓”,而是“Prometheus 能不能认出你的 Pod 是一个可监控目标”。这依赖三个要素:Pod label、Service port 名称、以及对应的 Monitor CRD 配置。
立即学习“go语言免费学习笔记(深入)”;
- 给 Go 服务的 Deployment 加 label,比如
app: my-go-app - Service 的 port 必须带 name,且为
metrics或其他你在 ServiceMonitor 中指定的名称(如name: http-metrics) - ServiceMonitor 的
selector.matchLabels要匹配 Service 的 label,endpoints.port要匹配 Service port 的 name - 确保 ServiceMonitor 所在 namespace 与 Prometheus 实例的
serviceMonitorNamespaceSelector允许范围一致(常见坑:ServiceMonitor 在default,但 Prometheus 只扫monitoring)
Go 应用怎么上报告警触发条件(比如 P99 延迟超 500ms)
Go 应用本身不直接“触发告警”,它只暴露原始指标;告警规则由 Prometheus Server 定义,通过 Alertmanager 分发。你的职责是:提供足够维度、足够精度的指标,让规则能写得准。
例如想告警“API P99 延迟 > 500ms”,你需要暴露带 handler 和 method 标签的直方图,并在 Prometheus 中写规则:
groups:
- name: go-api-alerts
rules:
- alert: HighLatencyAPICall
expr: histogram_quantile(0.99, sum(rate(http_request_duration_seconds_bucket{job="my-go-app"}[5m])) by (le, handler, method)) > 0.5
for: 2m
labels:
severity: warning
annotations:
summary: "High latency on {{ $labels.handler }}"
description: "{{ $labels.handler }} has P99 latency > 500ms for 2 minutes"- 直方图
bucket边界必须覆盖你关心的阈值(比如[]float64{0.1, 0.25, 0.5, 1.0, 2.0}),否则histogram_quantile插值不准或返回空 - 别用
time.Since()直接除以秒——要转成秒为单位的float64,用seconds := float64(d.Microseconds()) / 1e6 - 如果用 Gin/Echo 等框架,优先集成
prometheus/client_golang的中间件(如ginprometheus.New()),而非自己从头埋点
为什么 metrics 端点返回 200 但 Prometheus 显示 “target down”
常见但隐蔽的问题:Prometheus 抓取时加了默认 timeout(通常 10s),而你的 /metrics handler 因阻塞、锁竞争或未做采样导致响应超时;或者指标注册器里混入了非标准指标(比如含非法字符的 label 值),导致解析失败。
- 检查 Prometheus targets 页面的 “Last Scrape Error” 字段,常见错误包括:
context deadline exceeded(超时)、expected a valid metric name, got ""(空指标名)、invalid metric name(含大写字母或特殊符号) - 用
curl -v http://your-pod:8080/metrics手动测,看是否真能在 5 秒内返回、Content-Type 是否为text/plain; version=0.0.4 - 避免在指标收集路径中调用数据库或远程 API;所有指标应来自内存状态或原子变量
- 如果用了自定义 Registry,确认没漏掉
promhttp.HandlerFor(registry, ...)的第二个参数传入HandlerOpts{ErrorLog: log.New(os.Stderr, "", 0)}来捕获序列化错误
指标格式容错性极低,一个非法 label 值或换行符就能让整批指标失效。上线前务必用 promtool check metrics 验证输出。










