3. Prometheus深入:PromQL查询语言、Exporter原理与部署、告警规则配置(Alertmanager)
聊到Prometheus,很多人第一反应是“哦,一个监控系统”。但说实话,如果只会装个Server、配个Target,那你只用了它20%的能力。真正让Prometheus强大的,是它的查询语言PromQL,以及围绕Exporter和Alertmanager构建的生态。
这一章,我会把这三块核心内容掰开揉碎讲清楚。嗯,都是我在生产环境里踩过坑、流过泪之后总结出来的经验。
3.1 PromQL:不只是查数据,是数据分析
PromQL(Prometheus Query Language)是Prometheus的查询语言。它跟SQL有点像,但又不完全一样。SQL查的是关系型数据库里的表,PromQL查的是时序数据库里的指标。
说白了,PromQL就是用来“算”指标的。
3.1.1 基础查询:Instant Vector与Range Vector
先搞清楚两个核心概念:
- Instant Vector(瞬时向量):某个时间点上的数据。比如
node_cpu_seconds_total,查的是“现在”这个时刻的CPU使用时间。 - Range Vector(范围向量):一段时间内的数据。比如
node_cpu_seconds_total[5m],查的是过去5分钟内的所有数据点。
我刚开始学的时候,经常搞混这两个概念。后来我给自己总结了一句话:“瞬时向量看快照,范围向量看趋势”。
重要提示: 在写告警规则时,绝大多数场景用的是Instant Vector。因为告警需要的是“当前是否异常”,而不是“过去5分钟的数据长什么样”。
3.1.2 常用函数:rate、irate、increase
这三个函数,我敢说你在生产环境里天天都会用到。它们专门用来处理Counter类型的指标。
- rate():计算一段时间内的平均每秒增长率。比如
rate(node_cpu_seconds_total[5m]),算的是过去5分钟内CPU使用率的平均值。 - irate():计算瞬时增长率。它只看最近两个数据点,反应更灵敏,但容易抖动。
- increase():计算一段时间内的总增量。比如
increase(node_network_receive_bytes_total[1h]),算的是过去1小时内网络接收的总字节数。
我的习惯: 在告警规则里,我一般用rate(),因为它平滑,不容易误报。在Grafana图表里,我偶尔用irate(),因为它能更快反映变化。你想想看,告警要是天天抖动,运维同学会疯掉的。
3.1.3 聚合操作:by、without、topk
有时候我们需要把多个维度的数据合并起来看。比如,我想知道所有机器的平均CPU使用率,而不是每台机器的。
# 按instance分组,计算平均CPU使用率
avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))
# 排除mode维度,计算所有mode的总和
sum without(mode) (rate(node_cpu_seconds_total[5m]))
# 取CPU使用率最高的前5台机器
topk(5, avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])))
我曾经在排查一个性能问题时,用topk快速定位到了某台机器CPU异常飙升。如果没有这个函数,你得一台一台看,效率差太多了。
3.2 Exporter原理与部署:把数据喂给Prometheus
Prometheus自己不会凭空产生数据。它需要Exporter来采集。Exporter说白了就是一个“数据翻译官”,把各种系统、中间件的指标翻译成Prometheus能理解的格式。
3.2.1 Exporter的工作原理
Exporter的核心逻辑其实很简单:
- 通过系统调用、API、或者读取文件等方式获取原始数据。
- 把数据转换成Prometheus的Metrics格式(通常是
# HELP、# TYPE开头的文本)。 - 暴露一个HTTP端点(通常是
/metrics),等待Prometheus来抓取。
嗯,这里要注意:Exporter本身不存储数据,它只负责“采集-转换-暴露”。数据存哪里?那是Prometheus Server的事。
3.2.2 常用Exporter部署示例
我挑两个最常用的Exporter讲讲:Node Exporter和Blackbox Exporter。
Node Exporter: 采集Linux系统指标(CPU、内存、磁盘、网络等)。
# 下载并启动Node Exporter
wget https://github.com/prometheus/node_exporter/releases/download/v1.6.0/node_exporter-1.6.0.linux-amd64.tar.gz
tar xvf node_exporter-1.6.0.linux-amd64.tar.gz
cd node_exporter-1.6.0.linux-amd64
./node_exporter --web.listen-address=":9100"
Blackbox Exporter: 用于探测外部服务的可用性(HTTP、TCP、ICMP等)。
# 启动Blackbox Exporter
./blackbox_exporter --config.file=blackbox.yml --web.listen-address=":9115"
避坑指南: 我曾经在生产环境里直接用了默认端口,结果跟其他服务冲突了。建议你提前规划好端口分配,比如Node Exporter统一用9100,Blackbox用9115,MySQL Exporter用9104。这样后期维护起来省心很多。
3.2.3 自定义Exporter:什么时候需要自己写?
官方和社区提供的Exporter已经覆盖了大部分场景。但如果你遇到以下情况,就得自己动手了:
- 监控一个自研的中间件或内部系统。
- 需要采集一些业务层面的指标(比如订单量、用户活跃数)。
- 官方Exporter的性能或功能不满足需求。
写一个自定义Exporter其实不难。你只需要暴露一个/metrics端点,返回符合Prometheus格式的文本就行。我建议用Go语言写,因为Prometheus官方提供了Client Library,几行代码就能搞定。
3.3 告警规则配置与Alertmanager
数据有了,查询也会了,接下来就是告警。告警是监控的“最后一公里”,也是最有价值的一环。
3.3.1 告警规则怎么写?
告警规则定义在Prometheus Server的配置文件中。核心是rules字段,里面包含一组alert规则。
groups:
- name: node_alerts
rules:
- alert: NodeCPUUsageHigh
expr: (1 - avg by(instance) (rate(node_cpu_seconds_total{mode="idle"}[5m]))) > 0.9
for: 5m
labels:
severity: critical
annotations:
summary: "{{ $labels.instance }} CPU使用率超过90%"
description: "当前CPU使用率: {{ $value | humanizePercentage }}"
这里有几个关键点:
- expr:触发条件,就是一条PromQL表达式。
- for:持续时间。比如上面这个规则,CPU使用率超过90%持续5分钟才告警。这能有效避免瞬时抖动导致的误报。
- labels:告警的标签,可以用来区分告警级别。
- annotations:告警的描述信息,支持模板变量。
重要提示: for字段一定要用好。我见过很多新手不写for,结果CPU一波动就收到一堆告警。你想想看,凌晨3点被叫起来,结果发现只是瞬间抖动,那得多崩溃。
3.3.2 Alertmanager:告警的“调度中心”
Prometheus Server只负责“产生告警”,不负责“发送告警”。发送告警是Alertmanager的事。
Alertmanager的核心功能有三个:
- 分组(Grouping):把相似的告警合并成一条通知。比如100台机器同时CPU高,你不会想收到100条短信的。
- 抑制(Inhibition):如果某个高级别告警触发了,就屏蔽相关的低级别告警。比如机器宕机了,那CPU高、内存高这些告警就没意义了。
- 静默(Silencing):在维护窗口期,可以临时屏蔽某些告警。
下面是一个简单的Alertmanager配置示例:
route:
receiver: 'email-admin'
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
routes:
- match:
severity: critical
receiver: 'pagerduty-critical'
receivers:
- name: 'email-admin'
email_configs:
- to: 'admin@example.com'
- name: 'pagerduty-critical'
pagerduty_configs:
- routing_key: 'your-pagerduty-key'
我个人习惯把告警分成两个级别:Warning和Critical。Warning走邮件或钉钉,Critical走PagerDuty或电话。这样既不会漏掉重要告警,也不会被无关紧要的通知淹没。
3.3.3 告警的“去重”与“降噪”
告警疲劳是运维的大敌。我见过一个团队,一天收到上千条告警,最后大家直接无视了所有告警。这跟没有监控有什么区别?
要解决这个问题,可以从几个方面入手:
- 合理设置
for持续时间:避免瞬时抖动。 - 用好分组和抑制:减少重复告警。
- 设置合适的
repeat_interval:告警恢复前,不要频繁重复发送。我一般设成4小时。 - 定期Review告警规则:把那些“从来没人看”的告警删掉或降级。
我的经验: 告警规则不是越多越好。我建议你从“最核心的5个指标”开始,比如CPU、内存、磁盘、网络、进程存活。等稳定了再慢慢加。一口吃不成胖子,告警也一样。
3.4 本章知识体系图
下面这张图展示了Prometheus核心三件套的关系:
这张图把Prometheus的核心逻辑串起来了。你想想看,Exporter是“眼睛”,负责看;PromQL是“大脑”,负责分析;Alertmanager是“嘴巴”,负责喊人。三者缺一不可。
公众号:蓝海资料掘金营,微信deep3321