必须定义长连接专属指标(如connection_up_total、active_connections、heartbeat_latency_seconds等),在Go服务中精准打点并注册,配合Prometheus低频抓取与Grafana正确聚合查询,才能实现真实可用的长连接质量监控。

长连接质量监控不能只靠 Grafana 面板画图——它必须依赖 Go 服务主动暴露连接生命周期、心跳延迟、断连原因等指标,且 Prometheus 抓取频率、标签设计、直方图分桶方式都要适配长连接场景。否则面板永远显示“no data”或数值失真。
Go 服务必须暴露长连接专属指标,不能复用 HTTP 指标模板
HTTP 的 http_requests_total 和 http_request_duration_seconds 对长连接(如 WebSocket、gRPC stream、TCP 连接池)完全不适用:它们按请求-响应建模,而长连接是持续状态。你得定义新指标:
-
connection_up_total:Counter,记录成功建立的连接数(含重连),带protocol(ws/grpc/tcp)、region标签 -
connection_duration_seconds:Histogram,记录单次连接存活时长(单位秒),Buckets 建议设为[60, 300, 1800, 3600, 7200, 14400](1 分钟到 4 小时),覆盖心跳保活、异常断连、客户端主动下线等典型区间 -
heartbeat_latency_seconds:Histogram,记录心跳响应延迟(从发 ping 到收 pong 的耗时),Buckets 要细粒度,如[0.05, 0.1, 0.2, 0.5, 1.0, 3.0],便于查 P95/P99 毛刺 -
connection_close_reasons_total:Counter,带reason标签(值为"timeout"、"network_error"、"client_shutdown"、"server_kick"),用于归因分析
所有指标必须在 init() 或服务启动早期调用 prometheus.MustRegister() 注册;打点位置要精准——比如 connection_duration_seconds.Observe(time.Since(conn.StartTime).Seconds()) 必须在 conn.Close() 前触发,不能放在 defer 里等 goroutine 退出(可能已提前被 kill)。
心跳延迟直方图查询必须聚合 le 标签,且不能漏掉 _bucket 后缀
Grafana 里写 histogram_quantile(0.95, rate(heartbeat_latency_seconds_bucket[5m])) 会永远返回空——Prometheus 不知道你要按哪个维度聚合。正确写法是:
histogram_quantile(0.95, sum(rate(heartbeat_latency_seconds_bucket[5m])) by (le, protocol))
注意两点:
- 必须用
heartbeat_latency_seconds_bucket(带_bucket),不是heartbeat_latency_seconds(那是 Summary 类型才有的) - 必须
by (le, protocol):le是直方图强制聚合维度,漏掉就无法计算分位数;加protocol是为了区分不同协议的延迟特征
如果 Grafana 面板里 P95 延迟曲线是平的或跳变剧烈,先去 Prometheus 表达式浏览器里跑这句,看是否返回多个 series;没有,说明 Go 端没打点,或 Prometheus targets 状态不是 UP。
Prometheus targets 配置必须支持长连接保活与低频抓取
长连接服务通常不希望被高频轮询干扰,但 Prometheus 默认 scrape_interval: 15s 会引发大量短连接建立/关闭,掩盖真实问题。调整策略:
- 在
prometheus.yml的scrape_configs中单独为长连接服务设 job:job_name: 'long-conn-app' scrape_interval: 60s scrape_timeout: 30s static_configs: - targets: ['10.0.1.100:8080']
- 确保 Go 服务监听的是
0.0.0.0:8080,不是127.0.0.1:8080(Docker 容器内 Prometheus 无法访问 localhost) - 若服务部署在 Kubernetes,target 应写成
service-name.namespace.svc.cluster.local:8080,并确认 Service 的clusterIP可达、Pod readiness probe 不误杀 /metrics 路径
抓取超时设为 30s 是因为长连接服务的 /metrics 响应可能涉及连接池状态快照,比普通 HTTP 指标更耗时;超时太短会导致 scrape error 显示 context deadline exceeded,但 targets 状态仍显示 UP(假阳性)。
Grafana 面板里“连接存活率”不能直接用 rate 计算
想看“当前有多少连接还活着”,别用 rate(connection_up_total[1h])——这是每秒新建连接数,不是存量。正确做法是用 Gauge:
- 在 Go 服务中定义
active_connections:var activeConnections = prometheus.NewGauge( prometheus.GaugeOpts{ Name: "active_connections", Help: "Number of currently active long connections", }) - 每次新连接建立时
activeConnections.Inc(),断开时activeConnections.Dec()(注意并发安全,Dec()可能为负,需加锁或用Set()替代) - Grafana 查询直接写
active_connections,或按region分组:sum(active_connections) by (region)
这个值才是真正的“连接池水位”。如果它长期低于预期,说明客户端频繁断连或未重连;如果突降为 0,结合 connection_close_reasons_total 查 reason="timeout" 是否激增——大概率是心跳超时配置过严或网络抖动。
长连接监控最难的不是埋点,而是指标语义对齐:Go 端记录的“断连原因”必须和运维侧实际排查路径一致,比如 reason="network_error" 要对应到 TCP RST 包或 TLS handshake timeout,不能笼统归为“unknown”。否则 Grafana 面板再漂亮,也帮不上故障定位。











