第4章:可观测性基石:指标(Metrics)体系设计、黄金指标(USE、RED)、Prometheus基础

聊到系统稳定性,我第一个想到的就是——你得先知道系统在干嘛。说白了,可观测性就是系统的「仪表盘」。没有它,你就像蒙着眼开车,出了事只能靠猜。

这一章,我们聚焦可观测性的第一块基石:指标(Metrics)。我会结合自己踩过的坑,聊聊怎么设计指标体系,什么是USE和RED黄金指标,以及Prometheus这个工具到底怎么用。

4.1 指标到底是什么?

指标,就是系统运行状态的数值化描述。比如CPU用了多少、请求延迟多高、错误率多少。它们通常是时间序列数据——每个数值都带一个时间戳。

我个人习惯把指标分成三类:

  • 工作负载指标:用户请求量、吞吐量、延迟、错误率。这些直接反映用户体验。
  • 资源指标:CPU、内存、磁盘、网络。这些反映系统「身体」是否健康。
  • 事件指标:部署次数、配置变更、告警触发。这些反映系统「行为」变化。

嗯,这里要注意:指标不是越多越好。我在项目中遇到过团队把几百个指标全堆到监控面板上,结果没人看得懂。你想想看,这跟没有监控有什么区别?

我的经验: 每个服务核心指标控制在10个以内。多了就是噪音,少了又不够用。先抓关键,再慢慢补充。

4.2 黄金指标:USE与RED

说到指标设计,有两个方法论我特别推荐。一个是针对资源的USE,一个是针对服务的RED。它们就像两把尺子,帮你量清楚系统状态。

4.2.1 USE方法:资源视角

USE是Brendan Gregg提出的。它关注三个维度:

  • Utilization(利用率):资源有多忙?比如CPU使用率80%。
  • Saturation(饱和度):资源排队有多严重?比如CPU run queue长度。
  • Errors(错误):资源出错了没?比如磁盘I/O错误计数。

举个例子。我记得有一次线上告警说磁盘利用率到了95%。我第一反应不是扩容,而是先看饱和度——磁盘I/O等待队列有多长?结果发现队列几乎为空。这说明磁盘虽然满了,但实际读写压力不大。后来一查,是日志文件没轮转,清理一下就解决了。

你看,如果只看利用率,你可能会误判。USE方法逼你从三个角度交叉验证。

资源 利用率指标 饱和度指标 错误指标
CPU CPU使用率 运行队列长度 CPU错误计数
内存 内存使用率 交换空间使用量 OOM事件
磁盘 磁盘使用率 I/O等待队列 磁盘错误
网络 带宽使用率 丢包率 网络错误

4.2.2 RED方法:服务视角

RED是Tom Wilkie提出的,专门针对微服务。它关注:

  • Rate(速率):每秒多少请求?
  • Errors(错误):请求失败率多少?
  • Duration(持续时间):请求延迟分布如何?

说白了,RED就是回答三个问题:服务忙不忙?服务好不好?服务快不快?

我建议每个微服务都暴露这三个指标。为什么?因为它们是用户能直接感知的。CPU再高,只要请求正常,用户就不在乎。但延迟从100ms涨到2s,用户立马就骂娘了。

核心原则: USE管资源,RED管服务。两者互补,缺一不可。资源出问题会反映到服务上,服务出问题也能追溯到资源。

4.3 Prometheus基础

指标设计好了,总得有个地方存和查吧?Prometheus就是干这个的。它是CNCF毕业项目,也是目前最流行的指标监控系统。

4.3.1 核心概念

Prometheus有几个关键概念,我简单捋一下:

  • 指标名称:比如 http_requests_total,描述指标含义。
  • 标签:键值对,比如 method="GET",用来区分不同维度。
  • 样本:一个具体的数值+时间戳。
  • 时间序列:同一指标+同一标签组合的样本序列。

举个例子。你暴露了一个指标:

http_requests_total{method="GET", endpoint="/api/users", status="200"} 1024

这个指标叫 http_requests_total,有三个标签:method、endpoint、status。数值1024表示到目前为止,GET请求/api/users接口返回200的次数。

4.3.2 四种指标类型

Prometheus支持四种指标类型。我一个个说:

类型 说明 典型用途
Counter 只增不减的计数器 请求总数、错误总数
Gauge 可增可减的测量值 CPU使用率、内存使用量
Histogram 分桶统计,可计算分位数 请求延迟分布
Summary 类似Histogram,但预计算分位数 延迟的p50/p99

我建议:能用Counter就别用Gauge。为什么?Counter天然适合做速率计算,比如 rate(http_requests_total[5m]) 就能得到每秒请求数。Gauge只能看瞬时值,做趋势分析比较麻烦。

4.3.3 实战:暴露一个指标

假设你有一个Go服务,想暴露RED指标。代码大概长这样:

package main

import (
    "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", "endpoint", "status"},
    )
    httpRequestDuration = prometheus.NewHistogramVec(
        prometheus.HistogramOpts{
            Name:    "http_request_duration_seconds",
            Help:    "HTTP request latency in seconds.",
            Buckets: prometheus.DefBuckets,
        },
        []string{"method", "endpoint"},
    )
)

func init() {
    prometheus.MustRegister(httpRequestsTotal)
    prometheus.MustRegister(httpRequestDuration)
}

func handler(w http.ResponseWriter, r *http.Request) {
    timer := prometheus.NewTimer(httpRequestDuration.WithLabelValues(r.Method, r.URL.Path))
    defer timer.ObserveDuration()

    // 你的业务逻辑
    w.Write([]byte("Hello, world!"))

    httpRequestsTotal.WithLabelValues(r.Method, r.URL.Path, "200").Inc()
}

func main() {
    http.HandleFunc("/api/users", handler)
    http.Handle("/metrics", promhttp.Handler())
    http.ListenAndServe(":8080", nil)
}

这段代码暴露了两个指标:http_requests_total(Counter)和 http_request_duration_seconds(Histogram)。访问 /metrics 就能看到Prometheus格式的数据。

避坑指南: 我曾经犯过一个错——把标签值设成无限增长的,比如用户ID。结果Prometheus内存直接爆了。记住:标签基数不能太高,一般控制在几千以内。否则Prometheus会变成「Prometheus杀手」。

4.3.4 查询语言PromQL入门

指标存进去了,怎么查?PromQL是Prometheus的查询语言。我挑几个最常用的:

  • rate(http_requests_total[5m]):过去5分钟每秒请求数。
  • histogram_quantile(0.99, rate(http_request_duration_seconds_bucket[5m])):过去5分钟的p99延迟。
  • sum by (method) (rate(http_requests_total[5m])):按method分组求和。

我个人习惯把PromQL写成告警规则。比如:

groups:
- name: example
  rules:
  - alert: HighErrorRate
    expr: |
      sum(rate(http_requests_total{status=~"5.."}[5m]))
      /
      sum(rate(http_requests_total[5m])) > 0.05
    for: 5m
    labels:
      severity: critical
    annotations:
      summary: "错误率超过5%"

这个规则的意思是:如果过去5分钟5xx错误率超过5%,并且持续5分钟,就触发告警。

4.4 小结

这一章我们聊了:

  • 指标是系统稳定性的「眼睛」,但别贪多,抓核心。
  • USE方法管资源,RED方法管服务。两者结合,覆盖全面。
  • Prometheus是当前最主流的指标系统,掌握Counter、Gauge、Histogram就够了。
  • PromQL是查询语言,写告警规则时特别有用。

下一章,我们会深入日志体系设计。日志和指标是两兄弟,配合起来威力更大。到时候我会分享一个真实案例——怎么用日志定位一个「间歇性超时」的诡异问题。

课后作业: 找一个你负责的服务,用RED方法设计三个核心指标,然后用Prometheus暴露出来。试试用PromQL画个延迟分布图。你会发现,原来系统状态这么清晰。