一条 Kibana 告警规则要经历周期执行、条件判定和 Connector 动作三个阶段。Rule 与 Action 的契约负责业务语义;规则本身保存在 .kibana,而真正生成出来的 alert 文档会遵循 Alerts as Data schema 写到 .alerts-* alias。后台调度由 Task Manager 承担;调度器的内部机制留到第 12 篇集中展开。本篇先沿着一次规则执行观察状态如何产生、持久化并触发外部动作。

Alerting 框架总览

Kibana Alerting 把告警拆成三个可独立替换的契约:

1
2
3
4
5
6
7
Rule                  Connector              Action
────────────────── ──────────────────── ────────────────────
定义条件 + 调度周期 定义外部系统连接参数 定义向该系统发送的
(what/when to check) (where to send) 消息模板
│ │ │
└──────── Alert Instance 触发后 ──────────────┘
ActionExecution

三者在 .kibana 索引中各自存为 Saved Object,类型分别是 alert(rule)、action(connector)、规则内嵌的 action 引用。这种分离意味着同一个 Slack connector 可以被数十个 Rule 复用,修改 Slack token 只需改一处。

Task Manager 调度模型

Rule 的执行不由 cron 守护进程驱动,而是由 Kibana 内置的 Task Manager 调度。

1
2
3
4
5
6
7
8
9
10
11
12
Kibana 实例 A                Kibana 实例 B
┌──────────────────────┐ ┌──────────────────────┐
│ Task Manager worker │ │ Task Manager worker │
│ poll .kibana_task_ │ │ poll .kibana_task_ │
│ _manager index │ │ _manager index
│ → claim (optimistic │ │ → claim (optimistic │
│ locking via ES │ │ locking via ES │
update + version) │ │ update + version) │
└──────────────────────┘ └──────────────────────┘
│ │
└──────── Elasticsearch ─────┘
.kibana_task_manager

每个 Rule 对应 .kibana_task_manager 中的一条 task 文档,字段 runAt 表示下次执行时间。Task Manager 以短轮询(默认 3 秒)从索引中 claim 到期任务,通过 Elasticsearch 的乐观锁(version check update)保证同一任务不会被两个 Kibana 实例同时执行。

Rule 执行后 Task Manager 更新 runAt = now + schedule_interval,形成循环。

Rule 的执行流程

1
2
3
4
5
6
7
8
9
10
Task Manager 触发 executeRule()


RuleExecutor.run()
├── fetchRuleState() ← 读取上次 alert instances
├── RuleType.executor() ← 实际检查逻辑(ES query / threshold)
│ └── return { state, alertsToSchedule }
├── diffAlertInstances() ← 新增 / 持续 / 恢复 对比
├── scheduleActions() ← 生成 ActionExecution 记录
└── saveRuleState() ← 写回 .kibana Saved Object

RuleType.executor() 是规则类型的扩展点。Kibana 的 alert type 在 server 侧注册,UI 侧通过 alerts/actions 相关的注册表呈现;执行阶段写入 alert payload 的当前主路径是 alertsClient.report()。官方提供的类型包括:

  • metrics.alert.threshold:指标阈值告警
  • .es-query:自定义 ES 查询,结果行数超过阈值触发
  • logs.alert.document.count:日志计数告警
  • xpack.ml.anomaly_detection_alert:ML 异常检测告警

插件通过 alerting / actions 的注册点接入自定义 Rule Type;当前主线写入 alert payload 的路径是 alertsClient.report()

Alert Instance 的状态机

1
2
3
4
5
6
7
8
(new)
first execution meets condition

ACTIVE ──────────── condition no longer met ──────────── RECOVERED
│ │
│ muted / snoozed │ re-triggers
▼ │
MUTED ──────────────────────────────────────────────────── ACTIVE

每个 Alert Instance 对应一个具体触发实体(例如某个 host.name 的值)。实例进入 ACTIVE 后,Action 根据 notifyWhen 策略决定是否发送通知:

  • onActionGroupChange:状态组变化时发送
  • onActiveAlert:每次执行时发送
  • onThrottleInterval:在节流间隔内最多一次

实例状态以 JSON 形式存在 alert Saved Object 的 executionStatusalertInstances 字段里。

Alerts as Data

规则本身继续存在 .kibana 里,但执行后的 alert 文档会写入 .alerts-{{context}}.alerts-{{space-id}} 这类 alias。Elastic 官方文档建议查询 .alerts-* alias,而不要直接把 backing index 当成稳定 API。

Connector 类型

Connector 封装了外部系统的连接参数。8.x 内置连接器包括:

Connector Type 用途
.email SMTP 邮件
.slack Slack incoming webhook
.pagerduty PagerDuty Events API
.webhook 通用 HTTP POST
.jira Jira issue 创建
.servicenow ServiceNow incident
xpack.ibm_resilient IBM Resilient

Connector 的敏感参数(密码、token)通过 Kibana 的 xpack.encryptedSavedObjects.encryptionKey 加密后存入 Saved Object,读取时自动解密但不暴露给 API 返回值。

实验:通过 API 创建并触发 Threshold Rule

以下实验在 Kibana 8.x + Elasticsearch 8.x 环境进行。假设已有 filebeat-* 索引,且 Kibana 配置了加密 key。

第一步:创建 Webhook Connector

1
2
3
4
5
6
7
8
9
10
POST kbn:/api/actions/connector
{
"name": "local-test-webhook",
"connector_type_id": ".webhook",
"config": {
"url": "https://httpbin.org/post",
"method": "post"
},
"secrets": {}
}

记录返回的 id,例如 connector_id = "abc-123"

第二步:创建 ES Query Rule(每 1 分钟检查一次)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
POST kbn:/api/alerting/rule
{
"name": "test-es-query-rule",
"rule_type_id": ".es-query",
"schedule": { "interval": "1m" },
"params": {
"index": ["filebeat-*"],
"timeField": "@timestamp",
"esQuery": "{\"query\":{\"match_all\":{}}}",
"size": 100,
"threshold": [1],
"thresholdComparator": ">",
"timeWindowSize": 5,
"timeWindowUnit": "m"
},
"actions": [
{
"id": "abc-123",
"group": "query matched",
"params": {
"body": "Rule {{rule.name}} fired: {{context.value}} hits"
}
}
]
}

第三步:观察执行日志

1
GET kbn:/api/alerting/rule/<rule_id>/_execution_log?date_start=now-1h

返回的 execution_log 数组中每条记录包含 status(succeeded / failed)、duration_msschedule_delay_ms(任务被 claim 的延迟,用于衡量 Task Manager 压力)。

第四步:查看告警状态

1
GET kbn:/api/alerting/rule/<rule_id>

executionStatus.status 值可能为 okactiveerrorpendingalertInstances 字段(内部)可通过 Elasticsearch 直查 .kibana 索引获得:

1
2
3
4
5
6
7
8
9
10
11
GET .kibana/_search
{
"query": {
"bool": {
"filter": [
{ "term": { "type": "alert" } },
{ "term": { "alert.name": "test-es-query-rule" } }
]
}
}
}

alert.alertInstances 字段记录每个实例的 statemeta.lastScheduledActions 等信息。

映射到内部对象

实验观测 内部对象
Rule 定期执行 .kibana_task_manager 中 type=alerting:.<rule_type> 的 task
执行日志 .kibana-event-log-* 索引中的 event 文档
告警状态 .kibana 中 type=alert 的 Saved Object
生成的 alert 文档 .alerts-* alias / .internal.alerts-* backing index,遵循 Alerts as Data schema
Connector 配置 .kibana 中 type=action 的 Saved Object(含加密字段)
Action 发送记录 .kibana-event-log-* 中 event.action=execute-action

模式提炼

Kibana Alerting 框架的三段契约本质是关注点分离:Rule 只负责"什么条件触发",Connector 只负责"向哪里发",Action 只负责"发什么内容"。这种设计让同一 Rule 可以并联多个 Action(例如同时发 Slack 和 PagerDuty),也让 Connector 复用跨越多个 Rule 而无需重复配置认证信息。

Task Manager 的乐观锁 claim 机制将调度状态转移到 Elasticsearch,天然支持多 Kibana 实例水平扩展,无需外部消息队列。

工程迁移表

场景 Kibana 8.x 做法
指标超阈值告警 Rule Type: metrics.alert.threshold,配合 metrics-* 索引
日志错误率告警 Rule Type: logs.alert.document.count
自定义复杂查询告警 Rule Type: .es-query,params.esQuery 传 JSON 字符串
告警发送到多渠道 在 Rule 的 actions 数组中添加多个不同 connector_id
防止告警风暴 action.frequency.throttle 设置节流间隔(例如 1h
静音特定实例 Rule._muted_alert_instances 数组,或 UI Mute Instance
批量暂停告警 Rule.enabled=false(停止 Task Manager 调度该 Rule)

常见误解

Rule 每次执行不意味着每次发送通知。notifyWhen: onActionGroupChange 模式下,只有 Alert Instance 的状态组(例如从 warning 变为 critical)才会触发 Action;实例持续 active 但组不变时不发送。混淆"Rule 执行"与"Action 触发"是告警被忽视或轰炸的常见原因。

.es-query Rule Type 的 esQuery 参数接受 JSON 字符串而非对象,直接传对象会导致参数校验失败,错误信息不够清晰。

加密 Saved Object 配置(xpack.encryptedSavedObjects.encryptionKey)未设置或在多 Kibana 实例间不一致时,Connector 会无法解密,表现为 action execute 报 Unable to decrypt attribute 错误。

Connector 的 secrets 字段在 GET 响应中永远为空对象,不能用 GET 返回值直接 PUT 回去更新,必须在 secrets 中重新填写完整值。

练习

  1. 创建一个 .es-query Rule,thresholdComparator 设为 between,观察 thresholdComparator between 需要 threshold 数组有两个元素的约束。
  2. 修改 Rule 的 schedule.interval30s,通过 .kibana_task_manager 索引查看 runAt 字段的更新频率。
  3. 在 Rule 触发后,调用 mute instance API,观察 .kibanaalert.mutedInstanceIds 字段的变化。
  4. 配置两个 Action(Webhook 和 email),分别属于不同的 action group(query matchedrecovered),验证 recovery 时只有 recovered group 的 Action 被触发。

系列导航

篇目 主题
00 导读:Kibana 的状态存在 Elasticsearch 里
01 架构:浏览器、Node.js server 与 New Platform
02 Saved Object:一切状态的统一模型
03 Data View:查询之前的字段抽象
04 Search Source 与查询翻译
05 Discover:交互式检索的执行模型
06 聚合式可视化:Visualize 与 bucket/metric
07 Lens:拖拽背后的自动聚合推断
08 TSVB、Timelion 与 Vega
09 Dashboard 与 Embeddable
10 Alerting:Rule、Connector 与 Action
11 Reporting:从 Dashboard 到 PDF/PNG
12 Task Manager:分布式任务调度
13 Spaces 与安全:RBAC、Feature Controls 与多租户
14 插件体系:setup/start 生命周期
15 性能模型:bundle、bootstrap 与异步搜索会话
16 Kibana vs Grafana:两种平台的设计取舍
17 演进:从纯前端到 Platform 再到 Serverless

参考资料

  1. Elastic 官方文档,Kibana Alerting - Kibana Alerting
  2. Elastic 官方文档,Alerting API Reference - Alerting API Reference
  3. Elastic 博客,“Kibana Alerting: How it Works” - Kibana Alerting: How it Works
  4. Kibana API 文档,Alerting - Alerting
  5. Kibana 官方文档,Query alert indices - Query alert indices
  6. Kibana 官方文档,Alert schema - Alert schema
  7. Kibana Alerts and Actions UI 源码 README - Kibana source