前两周有个运维同事跑来找我,说自己 Grafana 面板做得挺漂亮,CPU 阈值画到了 85,可机器负载到 95% 半天了,手机上一个告警都没收到。我过去看了一眼就发现问题了:他把 Dashboard 面板里的阈值线当成了告警开关,以为阈值到了 Grafana 就会自动通知。这是很多人配置 Grafana 告警时的第一个误区——可视化面板和告警体系是两套逻辑。真正想实现“页面告警”,也就是直接在 Grafana 页面里完成告警规则的创建、通知渠道的绑定和策略的编排,需要走完整的新版统一告警流程。
这篇文章我就以在 Grafana 页面上配置告警为主线,从新版统一告警的核心概念讲起,到数据源、联系人点、告警规则、通知策略的完整配置实操,最后把我在实际环境里踩过的坑、排查过的典型问题一起整理出来。内容不依赖外部 Alertmanager,直接在 Grafana 页面内搞定,适合已经用 Grafana 做可视化、想快速给核心指标加告警的团队参考。
1. 页面告警的本质:一套从评估到送达的完整链路
很多人第一次打开 Grafana 的 Alerting 菜单会懵,因为里面并不是一个简单的“打开告警”开关,而是一组相互配合的模块。要想在 Grafana 页面里配置出真正能用的告警,第一步是先把这套体系跑通。
1.1 面板上的阈值线,不等于告警规则
旧版 Grafana(8.0 之前)确实支持直接在面板上创建告警,配置写在面板 JSON 里,面板在页面上展示什么,告警就按什么逻辑判断。那个年代的玩法相对简单,但也问题不少:一个面板改动查询,告警跟着变,经常误伤;面板删了,告警也没了;通知渠道还只有 email、slack 等少数几种。
从 Grafana 8.0 开始,官方推出了统一告警(Unified Alerting),把告警从面板里拆了出来,彻底独立成一套系统。你可以通过 Dashboard 面板的 Alert 页签快速创建一条绑定到该面板的规则,但这只是创建入口,规则本身存储在告警系统里,不再和面板查询强绑定。也就是说,页面告警里的“页面”更像是一个操作入口,而不是告警的运行载体。
刚开始不习惯,但用久了你会发现这套设计是对的:面板负责展示,告警负责判活和通知,两者解耦之后,规则可以独立修改、独立测试、独立路由,不会因为谁动了一下仪表盘就导致报警逻辑失控。
1.2 五个核心组件,先记住它们的分工
在页面里配置告警,我习惯先在心里过一遍这五个组件,顺序正好也是告警从产生到到达你手机的完整链路:
- 数据源(Data Source):告警要查询的监控数据来源,比如 Prometheus、Loki、MySQL、CloudWatch 等。告警规则执行的查询都基于数据源。
- 告警规则(Alert Rule):定义“什么时候算异常”。包括查询表达式、判断阈值、评估频率、等待时长,以及告警要携带的标签和说明。
- 联系人点(Contact Point):定义“告警发给谁”。它是一个接收器,比如一个企业微信群机器人、一个邮箱地址、一个 Webhook URL,也可以同时挂多个渠道。
- 通知策略(Notification Policy):定义“这批告警怎么路由、怎么分组、怎么重复”。我们根据告警上的标签决定它走哪个联系人点,就像快递分拣中心根据地址分拣包裹。
- 静默与抑制(Silences / Mute Timings):临时关闭某些告警通知的“静音开关”,比如发布窗口期不想被打扰,就可以按标签做一段时间的静默。
很多新手上来就直奔“创建告警规则”,忽略了联系人点和通知策略,结果告警状态明明已经 Firing,人却什么都收不到,问题往往就出在通知链路没打通。所以后面我会把规则和通知策略放在同等重要的位置去讲。
1.3 什么场景适合直接用 Grafana 页面告警
Grafana 页面告警不是万能的,但它对中小团队特别友好。如果你的监控体量在几十台到几百台规模,指标主要来自 Prometheus、Loki、云监控这些数据源,又不想额外维护一套 Alertmanager 集群,那 Grafana 内置告警就是最省事的方案。直接在页面上配置规则,查询 PromQL,绑定企业微信或钉钉机器人,整个流程基本没有额外的开发成本。
如果你的规模已经上千台,告警规则上千条,确实要考虑更专业的告警编排,比如把 Grafana 告警接到现有 Alertmanager 再做二次路由。但我个人建议,团队刚起步阶段,不用一上来就搭特别重的告警体系,先用 Grafana 页面把核心告警跑起来,规则多了再逐步演进到多层架构。少一个环节,就少一个故障点。
2. 动手之前:先确认数据源和通知渠道
配置告警规则之前,有两项准备工作必须做,否则后面一定会卡壳:数据源是否支持告警查询,以及通知能不能真正送达。
2.1 检查数据源是否具备告警能力
不是所有数据源都能直接用于告警。Grafana 统一告警要求数据源实现查询后端(Backend)能力,通俗点说,就是数据源能够在 Grafana 服务端主动执行查询,而不是依赖浏览器前端。目前常用的 Prometheus、Loki、Graphite、CloudWatch、InfluxDB、MySQL 等主流数据源都支持,但具体到某个数据源版本,可能还要在数据源设置里打开“Alerting”相关的开关。
检查方法很直接:打开一个数据源页面,看配置项里有没有“Alerting”相关区域。比如 Prometheus 数据源有一个“Enable alerting”的开关,默认是开着的;如果你用老版本或某些自定义数据源,可能根本没有这个选项,那它在告警规则里就用不了。
还有一点容易被忽略:Grafana 页面告警执行查询时,用的是数据源配置里的“保存的”连接,和你当前浏览器登录 Grafana 用的账号无关。如果数据源配置时填了只读账号,要确保这个账号有足够的查询权限,否则规则会一直报查询错误。
2.2 先把通知渠道建好:企业微信群机器人 Webhook
通知渠道我在实际项目里用得最多的不是邮件,而是企业微信群机器人。因为大多数运维值班现在都在群里,机器人直接推消息比邮件更及时。Grafana 联系人点支持很多集成,Webhook 是兼容性最好的一个,可以对接企业微信、钉钉、飞书、Slack 的机器人。
以企业微信群机器人举例,配置步骤:
- 打开企业微信群,点击右上角群设置,找到“群机器人”,添加一个机器人,复制它的 Webhook 地址。
- 在 Grafana 中进入 Alerting → Contact points,点击 “Add contact point”。
- 名称填 wecom,比如 “wecom-ops-group”。
- 集成类型选择 Webhook。
- URL 填企业微信机器人的 Webhook 地址。
- 关键步骤:Webhook 的 Body 不能直接用 Grafana 默认格式,企业微信要求固定的 JSON 结构。在可选设置里,把 HTTP Method 设为 POST,Body 写成这样:
{ "msgtype": "text", "text": { "content": "{{ range .alerts }}{{ .annotations.summary }}\n{{ end }}" } }这一步是很多人踩坑的重灾区。Grafana 默认 Webhook 发送的是自己的告警 JSON,企业微信机器人会直接拒绝或者不识别,必须手动把发送内容改造成企业微信要求的格式。保存后点 “Test”,如果群里能收到机器人消息,说明渠道通了。
注意:企业微信机器人的 Webhook 地址需要妥善保管,它可以往群里发消息,相当于群的一个入口权限,泄露了会导致垃圾消息频繁轰炸。
2.3 邮件通知渠道:配置 grafana.ini 的 SMTP
如果你所在的团队还是习惯邮件收告警,那 Grafana 的邮件通知也得配好。邮件通知依赖 Grafana 服务端自己去发信,所以要配置 SMTP。
以最常见的 /etc/grafana/grafana.ini 为例,在 [smtp] 段配置:
[smtp] enabled = true host = smtp.example.com:465 user = alert@example.com password = your_password from_address = alert@example.com from_name = Grafana Alert如果是 Docker 方式部署,建议直接用环境变量,省得挂载文件:
GF_SMTP_ENABLED=true GF_SMTP_HOST=smtp.example.com:465 GF_SMTP_USER=alert@example.com GF_SMTP_PASSWORD=your_password GF_SMTP_FROM_ADDRESS=alert@example.com GF_SMTP_FROM_NAME=Grafana Alert改完配置需要重启 Grafana 服务。然后在联系人点里添加“Email”类型的集成,填上收件地址,点 Test 发一封测试邮件,确认能收到再往下走。我一直强调“先测邮件,再写规则”,因为很多运维环境里 SMTP 服务器的 25 端口被封,或者用 465 端口时没有配置 SSL 参数,等到规则触发时才想起测邮箱,就太被动。
3. 在 Grafana 页面里创建第一条告警规则
准备工作做完,终于到核心环节:创建告警规则。这一节我会给出两条路径,一条是从面板快速进入,一条是直接新建,同时把规则里的几个关键参数讲透。
3.1 最顺手的方式:从面板的 Alert 页签进入
如果你已经在某个 Dashboard 上画好了指标面板,想基于当前查询加一条告警,最快的方式是进入面板编辑模式,切到 Alert 页签。
操作路径:打开 Dashboard,进入某个 Panel 的编辑界面(鼠标悬停在标题上,选择 Edit,或者直接按 e),在右侧面板设置里找到 Alert 页签,点击“New alert rule”。
从面板创建规则有一个好处:面板当前的查询表达式会自动带过来,不用重新写一遍。比如你在面板上画的是一条 CPU 使用率曲线,点击创建后,告警规则里已经带上了这条 PromQL。但如果后续你在面板上改了查询,已创建的告警规则不会自动同步——这是新版统一告警和旧版面板告警最大的区别。规则创建后就是独立实体,面板只是当时给了你一个快捷入口。
同样,如果面板被删除,规则不会马上被物理删除(旧版会),但会变成失效状态。我见过有人在 rework dashboard 的时候删了一堆旧面板,结果某条告警突然不报警了,查了半天才发现是面板被删导致规则失效。所以告警规则命名和组织要规范,别让它跟某个“临时面板”绑定得那么随意。
3.2 把查询、Reduce、Threshold 三步配明白
不管从哪个入口创建规则,核心的规则配置区都是一样的。以一个 Prometheus 数据源的 CPU 使用率告警为例,新版告警规则默认是 A、B、C 三个子查询节点结构:
- A 查询:取原始指标,比如
100 - (avg by (instance) (rate(node_cpu_seconds_total{mode="idle"}[5m])) * 100),这一步算出来的是每台机器的 CPU 使用率。 - B Reduce:Grafana 告警需要一个“当前值”来做阈值判断,但查询返回的是一个时间序列,所以先用 Reduce 把序列聚合到一个数值。Reduce 函数通常用 Last,即取最新一个点的值。
- C Threshold:这才是真正的“报警条件”,比如设置为
> 85,如果 Reduce 出来的值大于 85,条件成立,规则就会进入待触发状态。
如果查询本身是布尔表达式,比如up == 0,那么 A 查询返回的数据本身就是“异常”的,可以不用再套 Threshold。这种情况下 Grafana 会对每个返回的序列分别做判断,只要查询有数据,就认为条件成立。
实际配置中容易翻车的地方在于:对多实例环境,A 查询会返回多条序列,B 的 Reduce 要对所有序列做计算。如果你在 Reduce 里选了 Mean,就会把所有机器的 CPU 合并成一个“平均使用率”,某一台机器跑到 99% 反而被其他机器拉低平均值,导致告警漏报。正确做法是保留 instance 维度,Reduce 用 Last,每条序列单独判断,这样任何一台机器超过阈值都会触发告警。
提示:告警规则里的“查询表达式”和面板查询虽然长得一样,但最好不要共用一份复杂的 PromQL。面板查询可以为了展示做各种聚合,告警查询要尽量简单明确,优先保证判断逻辑的可读性。
3.3 理解 Pending 和 For:别把瞬间抖动当故障
规则创建页面里最容易被忽视的一组参数,就是评估频率(Evaluate every)和等待时长(For)。
- Evaluate every:多久评估一次,生产环境一般设置 30s 或 1m,不建议低于 30s,因为评估会产生真实的数据源查询压力,Prometheus 扛得住不代表 Grafana 自身没有开销。
- For:条件满足之后需要持续多久才真正触发告警。比如设置 For = 5m,那么 CPU 使用率超过 85% 后,需要连续保持 5 分钟,规则才从 Pending 变成 Firing,才真正发送通知。
这个 For 太重要了。我见过有团队把 For 设成 0s,某台机器 CPU 瞬时飙一下(比如编译一个小程序),告警就分钟级轰炸,值班同学半夜被骚扰得想骂人。反过来,也有团队把 For 设成 30m,结果故障老半天了,手机还没动静。
我的建议是:核心可用性指标用 1m 左右,避免无谓抖动;容量类指标(比如磁盘使用率)可以用 5m-10m,因为这类指标不会瞬间恶化,允许它多观察一会,减少误报。配置完成后,你可以看到状态变化链路:
Normal(正常)→ 条件满足后进入 Pending(等待观察)→ For 时间到后进入 Firing(真正触发)→ 条件恢复后回到 Normal,并发送 Resolved(恢复)通知。
这条链路里,Pending 是一个中间状态,很多人看到规则一直黄色 Pending 就以为坏了,其实它只是在等 For 时间走完,这正是保护机制在工作。
3.4 给规则加标签和说明,后面路由全靠它们
创建规则时有一块“Labels” 和 “Annotations”区域,很多人直接跳过,这是大忌。有了标签,通知策略才能做路由;有了说明,告警消息里才能展示“哪台机器、什么指标、什么原因”。
标签建议统一规范,比如:
- severity:critical、warning、info
- team:infra、app、db
- service:gateway、order、user
这样一条告警规则打上了severity=critical, team=infra,后面通知策略就可以配置:凡是 severity=critical 的告警,直接推到核心值班群并重复通知;凡是 team=app 的告警,推到应用开发群,由开发自处理。
Annotations 里常用 summary 和 description。summary 是指示栏标题,description 是详细内容,里面可以用模板语法引用查询出来的标签值,比如:
实例 {{ $labels.instance }} 的 CPU 使用率超过 85%,当前值 {{ $values.C | humanize }}%这样告警到群里就能直接看完整个上下文,不用再打开 Grafana 查是哪台机器。这一步骤看起来只是写文案,实际是在降低值班同学的响应成本,非常值得花几分钟设计好。
4. 联系人点和通知策略,让告警送对地方
规则创建好了,不等于告警能送到正确的人。Grafana 把“发给谁”和“怎么发”拆成了两个独立概念:联系人点负责定义渠道,通知策略负责定义路由规则。我见过很多团队规则一大堆,联系人点也建了好几个,但通知策略还是默认的根策略,所有告警一股脑全发到默认联系人,值班同学每天被大量无关告警淹没。要改变这种情况,重点在通知策略。
4.1 创建联系人点:一个联系人点可以挂多个渠道
进入 Alerting → Contact points,点击“Add contact point”。给联系人点起一个容易认的名字,例如 critical-wecom、warning-email、ops-all。同一联系人点可以添加多个集成,也就是同时支持多个渠道。
举个例子,我给“critical-wecom”这个联系人点挂了两个集成:企业微信群机器人 Webhook 和 Email。这样有一条 critical 告警产生,群机器人立刻在群里播报,同时邮件抄送一份给技术负责人存档。两个渠道同时触发,谁也不会漏掉,而且配置成本很低。
在联系人点列表里,每一条都有一个“Test”按钮,建议创建完就测试一遍。测试通过只代表该联系人点能发消息,但具体某条告警能不能走到这个联系人点,还得看通知策略。
4.2 用通知策略做路由:标签就是告警的“地址”
通知策略的运作方式和路由器很像。根策略(Default policy)会匹配所有未被其他策略匹配的告警,通常我们不会把根策略直接设成某个联系人点,而是搭一层子路由。
比如这样设计:
- 根策略:默认走 wecom-ops(运维值班群兜底)
- 子路由 1:匹配
severity="critical",走 critical-wecom(核心群 + 邮件) - 子路由 2:匹配
team="app",走 app-dev(应用开发群)
在页面上配置时,“匹配”用的是 PromQL 风格的标签匹配语法,比如:
severity="critical" team="app"一个告警的标签如果同时匹配多个子路由,Grafana 会采用最具体(最长匹配)的规则。这个规则有点绕,但好处是灵活性极高。比如你可以先配置一条severity="critical",再配置一条severity="critical", team="order",那么订单服务的 critical 告警会走更具体的第二条,其他 critical 告警走第一条通用规则。
4.3 分组、重复通知和静默,配置一次就省心
通知策略里还有几个分组参数,新手容易忽视,但实际值班体验全看它们:
- Group by:按哪些标签聚合告警。比如按
alertname分组,同一类告警会合并成一条消息推送,不会因为 50 台机器同时 down 就刷 50 条。 - Group wait:新一组告警产生后,等待多久再发送,默认 30s,目的是把几秒内产生的同类告警合并到一条消息里。
- Group interval:同一组告警里,如果有新告警进来,至少等待多久再发下一条,默认 5m,避免短时间大量刷屏。
- Repeat interval:同一条告警通知的重复间隔,默认 4h,意思是如果告警一直不恢复,每 4 小时提醒你一次,而不是无限刷屏。
这些参数一定要按团队实际值班习惯调。我自己的习惯是 critical 告警 Repeat interval 设短一点,比如 1h;warning 告警设成 6h 甚至 12h,让不同等级的告警有完全不同的打扰程度。
静默(Silences)和抑制(Mute Timings)这个功能适合在发布窗口期用。比如每天凌晨 00:00 到 06:00 是定时任务窗口,可以配置一个 Mute Timing,在这时间段内不发送某些标签的告警。但要小心:静默只是不发送通知,告警规则本身仍在评估和记录,所以不会出现“静默期间发生故障、恢复后完全不知道”的情况,你可以在事后复盘时查看这段时间的规则状态,这个设计非常贴心。
5. 告警配置过程中的问题排查与避坑
这一节把我在实际项目中踩过的坑整理一遍,按出现的频率从高到低排列。如果你照着前面配置完了还是在页面里看不到告警,或者收到了异常提示,大概率能在下面找到原因。
5.1 规则已触发,人却没收到消息,按这条链路排查
告警链路涉及环节多,一旦没收到消息,我建议按“规则状态 → 标签匹配 → 联系人点 → 渠道端”的顺序逐个排查,不要瞎猜。
- 看规则状态。打开 Alerting → Alert rules,找到目标规则,确认状态是否变成 Firing。如果还是 Normal,说明查询或阈值条件没成立,先调整查询;如果一直是 Pending,大概率是 For 设置太长,或者查询结果在抖。
- 看评估日志。点进规则详情,可以查看每次评估的历史记录。如果评估结果有 Error 或 NoData,那问题出在数据源或者查询上。比如 PromQL 写错、数据源断连,都会在这里显示得非常清楚。
- 看标签和路由。确认这条规则产生的标签,是否真的能匹配到某条有联系人点的通知策略。很多人在这里翻车:子路由匹配条件写反了,或者根策略联系人点没设置,导致告警虽产生但无处可去。
- 看联系人点测试。在 Contact points 里点 Test 发一条测试消息,确认渠道本身通不通。如果测试成功但真实告警没发,问题基本出在路由,而不是渠道。
这里要特别提醒,Grafana 的联系人点测试,默认发送的是一条固定格式的测试消息,它不会走完整通知策略,只验证该联系人点的渠道配置。所以测试通过,千万不要以为整套链路已经验证完了。
5.2 页面提示 failed to upgrade legacy queries datasource was not found
这个错误是从哪些老版本升级上来之后很常见的。我遇到过几次,现象是打开某个 Dashboard 面板时,页面直接提示类似failed to upgrade legacy queries datasource xxxxxx was not found,整个面板查询失效,告警评估也跟着报错。
原因通常是面板 JSON 里保存的数据源引用还是旧的 UID,升级后 Grafana 在迁移老查询时找不到对应的数据源。处理思路并不复杂:
- 进入面板编辑模式,看查询编辑器的数据源选择框,如果显示为空或提示找不到数据源,就重新选择当前实例里实际存在的数据源。
- 如果面板是通过 Provisioning 方式管理的,检查 provisioning 文件里的数据源 UID 是否与目标数据源一致。比如
datasource字段填的应该是数据源的 UID,而不是名称。 - 修复后保存面板,再进入 Alert rules 里找到关联的规则,重新评估一次。正常情况错误提示会消失。
这个报错对告警的影响必须重视:老面板如果带了旧查询,升级后可能整体迁移失败,导致规则评估一直处于异常状态,而你在“规则状态”页看到的只是长时间的 NoData 或 Error。所以大版本升级 Grafana 之后,第一件事就是抽查几个绑定了告警规则的面板,确认查询还能跑通。
5.3 多实例聚合引发的漏报与误报
前面讲 Reduce 的时候提到过平均值的问题,这里再展开说一个典型场景。某个业务服务有多台实例,你写了一条查询统计请求错误率,然后直接在规则里用了类似avg by (service) (rate(http_requests_total{code="500"}[5m]))的表达式,想观察整个服务的平均错误率。
问题来了:如果只有一台实例故障,平均错误率可能只上升了几个百分点,远达不到设置的阈值,于是故障被平均掩盖了。正确的做法是保留实例维度,对所有实例分别判断,比如:
rate(http_requests_total{code="500"}[5m]) > 0.05这样任何一台实例的错误率异常都会触发。告警是给值班人看“哪里坏了”的,不是给老板看“整体健康度”的,聚合维度一定不能为了美观而牺牲可观测性。
5.4 其他高频问题速查表
| 现象 | 常见原因 | 处理建议 |
|---|---|---|
| 规则一直是 Pending,不转 Firing | For 设置太长,或查询结果间歇性不满足 | 临时把 For 设为 0s/5s 观察是否符合预期,再调回 |
| 测试联系人点成功,实际告警收不到 | 通知策略路由没匹配到目标联系人点 | 检查规则标签与子路由匹配表达式 |
| 告警刷屏,同样的消息一直发 | Repeat interval 设置太短 | 调大 repeat_interval,比如 4h |
| 收到告警,但恢复(Resolved)消息没来 | 规则条件恢复不了,或数据源无数据 | 查看评估日志,确认查询结果最终回到了 Normal |
| 面板出现 failed to upgrade legacy queries | 数据源 UID 在升级后失效 | 重新选择数据源并保存面板 |
| 告警消息里没有机器名等关键信息 | 规则的 annotations 模板没写完整 | 在 summary/description 里用$labels.instance等模板字段 |
有人可能会问,Resolved 通知到底是什么时候发的?这里补充一句:当规则状态从 Firing 变回 Normal 时,Grafana 会附带发送一条恢复通知。你可以在联系点集成里关闭“发送恢复通知”的选项,但建议保持开启——故障恢复不通知,值班人就要一直悬着心,不知道平台啥时候恢复。
5.5 关于时区和静默窗口的提醒
最后说一个偏冷门但容易影响判断的坑:时区。Grafana 告警的评估时间是按系统时区处理的,但通知模板里展示的时间戳通常带时区信息,如果你的告警规则是跨国或跨地域团队共用,静默时间窗口很容易踩到“我以为不是工作时间,其实国外团队正在上班”的雷。
我建议在配置 Mute Timing 或静默窗口前,先确认 Grafana 系统时区和业务所在时区,再完成配置。如果涉及跨时区值班,最好在告警消息模板里显式带上 UTC 时间和本地时间两个字段,避免大家在不同时区对不上时间线。
最后再分享一个实用的小技巧,是我在新建每组告警规则时都会做的:不要直接在生产环境上边配边等触发。先在测试面板上把 For 设为 5s,故意把阈值调到肯定触发的值,做完一条通知验证,再慢慢把阈值和等待时长调回真实值。这套流程跑通后,把规则打上team和severity标签,后续维护就非常轻松了。Grafana 页面告警看着只是点点点,真正花心思的地方其实在标签设计和路由语义上,这个做好以后,值班手机才能真正安静下来。