第4章:可观测性基石:指标(Metrics)体系设计、黄金指标(USE、RED)、Prometheus基础
聊到系统稳定性,我第一个想到的就是——你得先知道系统在干嘛。说白了,可观测性就是系统的「仪表盘」。没有它,你就像蒙着眼开车,出了事只能靠猜。
这一章,我们聚焦可观测性的第一块基石:指标(Metrics)。我会结合自己踩过的坑,聊聊怎么设计指标体系,什么是USE和RED黄金指标,以及Prometheus这个工具到底怎么用。
4.1 指标到底是什么?
指标,就是系统运行状态的数值化描述。比如CPU用了多少、请求延迟多高、错误率多少。它们通常是时间序列数据——每个数值都带一个时间戳。
我个人习惯把指标分成三类:
- 工作负载指标:用户请求量、吞吐量、延迟、错误率。这些直接反映用户体验。
- 资源指标:CPU、内存、磁盘、网络。这些反映系统「身体」是否健康。
- 事件指标:部署次数、配置变更、告警触发。这些反映系统「行为」变化。
嗯,这里要注意:指标不是越多越好。我在项目中遇到过团队把几百个指标全堆到监控面板上,结果没人看得懂。你想想看,这跟没有监控有什么区别?
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,用户立马就骂娘了。
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格式的数据。
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是查询语言,写告警规则时特别有用。
下一章,我们会深入日志体系设计。日志和指标是两兄弟,配合起来威力更大。到时候我会分享一个真实案例——怎么用日志定位一个「间歇性超时」的诡异问题。