3. Prometheus 核心概念:数据模型、Pull模型、PromQL入门
好,咱们今天聊聊 Prometheus 最核心的几个概念。说实话,我刚开始接触 Prometheus 的时候,也觉得它跟传统的监控系统不太一样。但用顺手之后,你会发现它的设计其实非常优雅。
我个人习惯把 Prometheus 比作一个「时间序列数据库」+「抓取器」的组合体。它不主动推数据,而是定期去拉。这个思路,说白了就是「你来不来,我都在这里」。嗯,咱们一个一个来看。
3.1 数据模型:标签是灵魂
Prometheus 的数据模型,核心就一句话:每个时间序列由指标名和一组键值对标签唯一标识。
举个例子:
http_requests_total{method="GET", endpoint="/api/v1/users", status="200"} 1024
这里 http_requests_total 是指标名,花括号里的是标签。标签就是维度,你可以用它做任意维度的聚合、过滤、分组。
我在项目中遇到过一个问题:有个同事把所有请求都打到一个指标里,没有区分 method 和 endpoint。结果排查故障时,根本看不出是哪个接口出了问题。你想想看,一个指标里混着 GET、POST、DELETE,还有各种路径,这怎么查?
所以我的建议是:标签设计要提前规划好。常见的标签包括:
- 业务维度:service、endpoint、method
- 环境维度:env(prod/staging/dev)、region
- 技术维度:instance、job、version
但也要注意,标签不是越多越好。每个标签组合都会产生一个新的时间序列。如果标签基数太大(比如把 user_id 放进去),Prometheus 的内存和存储会爆炸。我曾经见过一个团队把 request_id 当标签,结果 Prometheus 直接 OOM 了……嗯,这个坑大家别踩。
3.2 Pull 模型:主动出击,而非被动等待
传统监控系统(比如 Zabbix)是 Agent 主动推数据到 Server。Prometheus 反其道而行之——它主动去拉(Pull)目标暴露的指标端点。
为什么会这样?我个人觉得有几点好处:
- 更容易控制采集频率:Prometheus 自己决定什么时候拉,拉多快。不会被突发的数据洪流冲垮。
- 健康检查天然集成:如果目标挂了,Prometheus 拉不到数据,立马就能发现。不需要额外的心跳机制。
- 更容易做水平扩展:多个 Prometheus 实例可以各自拉各自的目标,互不干扰。
配置方式也很简单,在 prometheus.yml 里定义 scrape_configs:
scrape_configs:
- job_name: 'node-exporter'
static_configs:
- targets: ['localhost:9100']
labels:
env: 'prod'
- job_name: 'api-service'
metrics_path: '/metrics'
scrape_interval: 15s
static_configs:
- targets: ['192.168.1.10:8080', '192.168.1.11:8080']
这里有个细节:scrape_interval 默认是 1 分钟,但你可以按需调整。我一般把核心服务设为 15 秒,非核心的 30 秒甚至 1 分钟。别所有目标都用同一个频率,浪费资源。
3.3 PromQL 入门:用查询语言说话
PromQL 是 Prometheus 的查询语言。说实话,刚开始看它那套语法,我有点懵。但用多了你会发现,它其实很符合直觉。
咱们从最基础的开始:即时查询和范围查询。
3.3.1 即时查询
就是查「当前这一刻」的值。比如:
http_requests_total{method="GET"}
返回的是当前时间点,所有 method 为 GET 的请求总数。注意,这里返回的是最新值,不是历史值。
3.3.2 范围查询
如果你想看过去 5 分钟的趋势,就得用范围查询:
http_requests_total{method="GET"}[5m]
这个 [5m] 就是时间范围。返回的是过去 5 分钟内每个采样点的值。你可以用它做聚合、计算速率等。
3.3.3 常用函数
PromQL 内置了很多函数,我挑几个最常用的说说:
| 函数 | 作用 | 示例 |
|---|---|---|
rate() |
计算每秒增长率(适合 Counter) | rate(http_requests_total[5m]) |
irate() |
计算瞬时增长率(更敏感,适合短时间窗口) | irate(http_requests_total[1m]) |
avg_over_time() |
计算一段时间内的平均值 | avg_over_time(cpu_usage[5m]) |
sum() |
聚合求和 | sum(rate(http_requests_total[5m])) |
topk() |
取前 N 个 | topk(3, rate(http_requests_total[5m])) |
举个例子,我想看过去 5 分钟每个接口的 QPS:
rate(http_requests_total[5m])
如果我想按 endpoint 分组看:
sum(rate(http_requests_total[5m])) by (endpoint)
嗯,这里要注意:rate() 只能用于 Counter 类型(只增不减的指标)。如果是 Gauge(可增可减),用 avg_over_time() 更合适。
3.4 避坑指南:我踩过的那些坑
最后分享几个我实际踩过的坑,希望能帮你省点时间:
- 坑一:标签值带空格。PromQL 里标签值如果包含空格,必须用双引号括起来,否则会报错。比如
{method="GET /api"}是错的,得写成{method="GET /api"}但注意,Prometheus 标签值本身不支持空格,所以最好别用。 - 坑二:忘记加时间范围。用
rate()时忘了加[5m],结果返回空。我当时排查了半天,才发现是语法问题。 - 坑三:指标名大小写。Prometheus 指标名是大小写敏感的。我见过有人把
http_requests_total写成Http_Requests_Total,结果查不到数据。
好了,这一章的内容就这些。数据模型、Pull 模型、PromQL 入门,这三块是 Prometheus 的基石。下一章咱们会深入告警规则和 Alertmanager,到时候你会看到 PromQL 的更多妙用。