十年匠心定制 · 商业建站与技术教学双线并行 咨询热线:400-886-1026 service@lmnt.cn
ARTICLE DETAIL

资讯详情

深耕网站建设与运营推广的一线实战洞察。

Nightingale 告警订阅不生效排查全链路指南:匹配链、行为语义与验证方法

Nightingale 告警订阅不生效排查全链路指南:匹配链、行为语义与验证方法 Nightingale 告警订阅不生效排查全链路指南匹配链、行为语义与验证方法【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale本文以 Nightingale 内置技能文档alert-subscribe-copilot/troubleshooting.md为骨架结合告警订阅的源码实现alert/dispatch/dispatch.go、models/alert_subscribe.go、alert/common/key.go、memsto/alert_subscribe_cache.go深入讲解当我订阅了却什么都没收到时应该如何按序排查订阅克隆事件与原始告警通知之间的行为语义以及通过 HTTP 接口和真实触发两种方式验证订阅是否生效。读完本文你将能独立定位绝大多数订阅失效问题并准确回答订阅是否会重复通知恢复事件是否也会订阅等高频疑问。一、理解订阅匹配的主链路handleSubNightingale 的告警订阅在告警事件进入派发Dispatch阶段时被处理。事件经过告警规则自身的通知路径之后会进入订阅匹配逻辑核心入口为 alert/dispatch/dispatch.go 中的handleSubs/handleSubfunc (e *Dispatch) handleSubs(event *models.AlertCurEvent) { for _, sub : range e.collectSubscribes(event) { e.handleSub(sub, *event) } }从源码结构看订阅收集分两条路见collectSubscribes规则维度订阅e.alertSubscribeCache.Get(event.RuleId)即只订阅了某条具体告警规则的订阅全局订阅e.alertSubscribeCache.Get(0)即rule_ids为空的全局订阅。两者共同构成候选集合随后对每条订阅依次执行subMatches进行逐项过滤全部通过才会克隆事件并转发alert/dispatch/dispatch.goif sub.ForDuration (event.TriggerTime - event.FirstTriggerTime) { return false } ... sub.ModifyEvent(event) event.SubRuleId sub.Id e.HandleEventNotify(event, true)关键点在于任意一个匹配门gate失败这条订阅就会被跳过。因此排查问题的最有效手段就是按照下面给出的匹配门顺序表逐一核对。二、我订阅了但什么都没收到排查链引擎匹配链的权威定义见alert/dispatch/dispatch.go的subMatches其判定顺序与下面的排查表一致。任何一环失败都会导致该条订阅被跳过请按顺序检查#检查项常见失败原因0缓存同步刚改完规则内存缓存最长滞后9 秒1disabled规则被禁用disabled1在缓存层即被过滤2数据源datasource_ids不是 all且事件的datasource_id不在列表中3prodprod非空且与事件的 RuleProd 不相等注意是精确匹配4cate填了host但事件不是主机类型其他取值不会造成不匹配5标签 Tags多个tags是AND关系in的值用逗号分隔会失配必须空格分隔6业务组名busi_groups匹配的是事件的业务组名称——按名称硬绑定的条件在业务组重命名后会失去目标正则未覆盖全名也会失配7持续时间for_duration大于事件已持续时长trigger_time - first_trigger_time——告警刚触发时必然不匹配必须等事件持续足够久后下一次通知周期才可能命中8级别severities未包含事件的级别9下游出口以上全部通过且克隆事件已产出但notify_rule_ids指向的通知规则本身配置不正确渠道/接收人/适用属性不匹配→ 转交 notify-rule-copilot 排查另外务必确认源头原始告警事件必须真的产生了——订阅不会无中生有如果事件在评估阶段被静默mute拦截它根本不会走到订阅这一步。2.1 缓存滞后最长 9 秒订阅规则常驻内存缓存。从 memsto/alert_subscribe_cache.go 可以看到同步循环duration : time.Duration(9000) * time.Millisecond for { time.Sleep(duration) if err : c.syncAlertSubscribes(); err ! nil { ... } }即缓存每 9 秒轮询一次数据库修改订阅后最长 9 秒生效无需重启。若刚保存就立刻验证请先等一个同步周期。2.2 各匹配门背后的源码依据disabledsubMatches开头即if sub.IsDisabled() { return false }对应 models/alert_subscribe.go 的IsDisabled()disabled1直接短路。数据源MatchClustermodels/alert_subscribe.go逻辑为——订阅未配置数据源列表为空或事件无数据源dsId0时视为匹配否则要求事件数据源 id 在列表中或列表中含00代表全部。prodMatchProdmodels/alert_subscribe.go——prod为空即不过滤非空则精确匹配事件的RuleProd。注意这是精确匹配填写metric就不会匹配RuleProd为其他值的规则。cateMatchCatemodels/alert_subscribe.go——当前实现里只有host具备真实过滤效果仅匹配主机事件历史遗留的prometheus值会被视为不过滤。这与排查表第 4 行完全一致。TagsMatchTagsalert/common/key.go对每个标签过滤器逐一比对全部通过才算匹配AND 语义。matchTag中in/not in走filter.Vset[value]的集合查询集合元素由空格分隔的字符串切分而来——这就是逗号分隔必然失配的原因。业务组名MatchGroupsNamealert/common/key.go直接拿事件的GroupName与过滤条件做字符串/正则匹配。因此按业务组名硬绑定的订阅在业务组重命名后会立刻失配改用~正则或同步更新订阅才是稳妥做法。持续时间sub.ForDuration (event.TriggerTime - event.FirstTriggerTime)不成立才通过。事件首次触发时差值恒为 0for_duration 0时必然不匹配必须等事件跨过阈值后的下一轮通知才可能被转发见下文升级escalation语义。级别severities与事件级别做包含判断且0视为通配alert/dispatch/dispatch.go。三、行为语义回答用户疑问时的权威依据以下语义均可在源码与配置层面得到印证回答用户疑问时可以直接引用行为语义订阅会替换原始通知吗不会。原始事件照常走自己的通知路径订阅只是克隆一份并额外转发。如果同一个人同时配置在两条链路上会收到两次——这是设计使然会再次触发回调webhook吗不会。克隆事件的 callbacks 默认被清空models/alert_subscribe.go:ModifyEvent只有显式设置redefine_webhooks1的旧版本才会携带订阅自身的 webhooks订阅范围受 group_id 限制吗不受。group_id只是管理归属权限订阅本身天然接收所有业务组的事件靠busi_groups/rule_ids/tags收窄for_duration如何生效比较事件的trigger_time - first_trigger_time。首次触发时差值为 0 必然不匹配只有告警反复通知到第 N 次、差值超过阈值后该事件的克隆才会被转发——所以升级依赖告警规则自身配置了重复通知新版本能改写级别/渠道吗不能。notify_version1时 Verify 会清空 redefine_* 字段级别/渠道路由请在通知规则层做恢复事件也会被订阅吗恢复事件走同一条匹配链是否发送恢复通知取决于下游通知规则的配置如is_recovered属性过滤修改后多久生效缓存每 9 秒轮询最长 9 秒无需重启如何判断事件是否被订阅转发克隆事件携带sub_rule_id订阅规则 ID在通知记录/事件详情中可见3.1 克隆事件如何被改写ModifyEvent订阅命中后handleSub调用 models/alert_subscribe.go 的ModifyEvent改写事件副本if s.RedefineWebhooks 1 { event.Callbacks s.Webhooks event.CallbacksJSON s.WebhooksJson } else { // 将 callback 重置为空防止事件被订阅之后再次将事件发送给回调地址 event.Callbacks event.CallbacksJSON []string{} } if len(s.NotifyRuleIds) 0 { event.NotifyRuleIds s.NotifyRuleIds }这段代码直接解释了上表的两个关键语义默认清空 callbacks避免克隆事件再次命中原回调地址、用notify_rule_ids改写下游出口。随后event.SubRuleId sub.Id打上订阅标记最后以isSubscribetrue走HandleEventNotify。3.2 新版本字段清理Verify新版本notify_version1的校验逻辑见 models/alert_subscribe.go会强制要求notify_rule_ids非空并主动清空user_group_ids、redefine_channels/new_channels、redefine_webhooks/webhooks、redefine_severity/new_severity等旧版本字段。因此保存后 redefine 字段全没了是预期行为而非数据丢失——改写级别/渠道是旧版本能力新版本请在通知规则层做路由。四、其他易踩的坑现象原因处理创建报severities is required新旧版本都必填至少填[1,2,3]创建报no notify rules selectednotify_version1但notify_rule_ids为空先用list_notify_rules取 ID若没有先创建通知规则创建报new_channels is required旧版本指定了user_group_ids但未填new_channels补充new_channels或切换为新版本保存后 redefine 字段全没了新版本 Verify 主动清空旧版本字段预期行为非数据丢失升级订阅永远不触发告警规则未配置重复通知notify_repeat_step0事件不会来第二次让用户检查告警规则的重复通知间隔全局订阅事件量爆炸rule_ids/tags/busi_groups全空 复制所有事件至少加一层过滤或在下游通知规则收窄业务组重命名后订阅失去目标busi_groups按名称匹配改用~正则或重命名时同步订阅4.1 告警级别对照订阅过滤与事件级别相关的取值如下与排查表第 8 行对应值含义1一级告警Critical2二级告警Warning3三级告警Info五、验证方法5.1 应用内验证get_alert_subscribe_detail核对订阅字段get_notify_rule_detail核对下游出口通知规则配置。5.2 HTTP 试运行tryrunPOST /api/n9e/alert-subscribe/alert-subscribes-tryrun用一条历史事件 ID 订阅草稿做试运行会逐步展示在哪一步匹配失败新版本甚至会对通知规则执行真实测试发送。路由定义见 center/router/router.go。请求体格式{event_id: 历史事件ID, config: { ...订阅草稿... }}建议流程编辑后先 tryrun再保存。完整的订阅 HTTP API列表/详情/创建/更新/删除/试运行见alert-subscribe-copilot技能的 http-api.md注意外部 A2A Agent 走Authorization: Bearer token而应用内 AI 助手应使用内置 FC 工具而非这些端点。5.3 真实链路验证触发一条匹配的告警然后到历史告警 → 详情查看是否出现携带sub_rule_id的克隆事件及其通知记录。注意给缓存留出最长 9 秒的同步时间并确认原始告警事件确实产生未被静默。六、订阅规则配置速览排查时的字段对照排查链中的每个字段都对应models/alert_subscribe.go:AlertSubscribe数据模型。核心字段速记name/note名称与备注name必填disabled0启用默认1禁用禁用订阅在缓存层即被过滤group_id管理归属业务组权限不参与事件匹配prod非空时对事件 RuleProd 精确匹配常见metric/logging/hostcate当前实现只有host有真实过滤效果datasource_ids数据源 ID 列表空数组或含0表示全部rule_ids订阅的告警规则 ID 列表空 全局订阅所有规则severities必填[1,2,3]表示全部for_duration持续秒数用于升级转发0不限tags事件标签过滤多项 AND元素结构{key:标签名,func:操作符,value:匹配值}busi_groups按事件业务组名过滤元素约定{key:groups,func:~,value:production.*}notify_version1新版本经通知规则转发推荐0旧版本直接填用户组渠道notify_rule_ids新版本必填克隆事件的下游出口。tags/busi_groups的匹配操作符支持精确、!不等、~正则匹配、!~正则不匹配、in列表内空格分隔、not in列表外完整实现见 alert/common/key.go。完整可复制的配置示例含全部 Critical 告警转发给值班通知规则按 ident 标签订阅 web 集群for_duration 升级按业务组名跨组订阅转发工单系统等 5 个典型场景以及新旧版本字段完整对照见同目录的 reference.md。总结一套可复用的排查动作确认事件存在原始告警事件是否真的产生、是否被静默拦截确认缓存已同步改动后等待最长 9 秒按序核对匹配门disabled → datasource_ids → prod → cate → tags → busi_groups → for_duration → severities核对下游出口notify_rule_ids指向的通知规则本身是否配置正确渠道/接收人/适用属性用 tryrun 定位alert-subscribes-tryrun会精确告诉你在哪一步失配真实触发复验到历史告警详情确认携带sub_rule_id的克隆事件与通知记录是否出现。【免费下载链接】nightingaleNightingale is to monitoring and alerting what Grafana is to visualization.项目地址: https://gitcode.com/GitHub_Trending/ni/nightingale创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考
返回列表