
Go服务需暴露/metrics端点并用prometheus/client_golang库注册指标,K8s中通过ServiceMonitor按label和port名自动发现,告警由Prometheus规则基于直方图等指标触发,需确保格式合规、响应及时。
Go 服务要被 Prometheus 抓取,必须提供 /metrics HTTP 端点,返回符合 Prometheus 文本格式的指标数据。不暴露这个端点,监控系统根本看不到你的服务。
推荐用官方库 prometheus/client_golang,它提供 http.Handler 实现和指标注册器,避免手写格式出错。
prometheus.MustRegister(...) 或自定义 prometheus.NewRegistry() 避免与第三方库冲突prometheus.CounterVec)适合请求总量、错误次数;直方图(prometheus.HistogramVec)适合响应延迟;不要用 Gauge 记录请求量——它不累加,会覆盖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) }
Prometheus 在 K8s 里靠 ServiceMonitor 或 PodMonitor(取决于你用的是 Prometheus Operator)来动态发现目标。直接改 scrape_configs 手动加静态 target 不可持续,也绕过声明式管理。
关键不是“能不能抓”,而是“Prometheus 能不能认出你的 Pod 是一个可监控目标”。这依赖三个要素:Pod label、Service port 名称、以及对应的 Monitor CRD 配置。
app: my-go-app
metrics 或其他你在 ServiceMonitor 中指定的名称(如 name: http-metrics)selector.matchLabels 要匹配 Service 的 label,endpoints.port 要匹配 Service port 的 nameserviceMonitorNamespaceSelector 允许范围一致(常见坑:ServiceMonitor 在 default,但 Prometheus 只扫 monitoring)Go 应用本身不直接“触发告警”,它只暴露原始指标;告警规则由 Prometheus Server 定义,通过 Alertmanager 分发。你的职责是:提供足够维度、足够精度的指标,让规则能写得准。
例如想告警“API P99 延迟 > 500ms”,你需要暴露带 handler 和 meth 标签的直方图,并在 Prometheus 中写规则:
od
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
prometheus/client_golang 的中间件(如 ginprometheus.New()),而非自己从头埋点常见但隐蔽的问题:Prometheus 抓取时加了默认 timeout(通常 10s),而你的 /metrics handler 因阻塞、锁竞争或未做采样导致响应超时;或者指标注册器里混入了非标准指标(比如含非法字符的 label 值),导致解析失败。
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
promhttp.HandlerFor(registry, ...) 的第二个参数传入 HandlerOpts{ErrorLog: log.New(os.Stderr, "", 0)} 来捕获序列化错误指标格式容错性极低,一个非法 label 值或换行符就能让整批指标失效。上线前务必用 promtool check metrics 验证输出。