# 告警引擎设计文档 ## 一、设计原则 ### 1.1 核心原则 - **快**:错误发生后 1 分钟内触发告警 - **准**:减少误报,告警要有价值 - **全**:支持多种告警规则和通知渠道 - **轻**:不依赖复杂组件,轻量实现 ### 1.2 告警目标 - 错误突增:及时发现线上故障 - 新错误出现:第一时间感知新问题 - 错误率超标:质量红线监控 - 性能劣化:用户体验下降预警 --- ## 二、告警规则类型 ### 2.1 规则分类 | 类型 | 说明 | 实时性 | 复杂度 | |------|------|--------|--------| | **阈值告警** | 指标超过固定阈值 | 高 | 低 | | **突增告警** | 同比/环比增长超过阈值 | 中 | 中 | | **新错误告警** | 出现新的错误指纹 | 高 | 低 | | **错误率告警** | 错误率超过阈值 | 中 | 中 | | **质量分告警** | 性能/质量综合评分下降 | 低 | 高 | ### 2.2 内置规则模板 #### 1. 错误数量突增 ```yaml name: 错误数量突增 type: spike metric: error_count window: 5m # 检测窗口 compare: 1h_ago # 对比:1小时前 threshold: 200% # 增长 200% 触发 min_count: 10 # 最少 10 条才检测(避免噪音) level: warning ``` #### 2. 新错误出现 ```yaml name: 新错误出现 type: new_error metric: error_fingerprint window: 24h # 过去 24 小时没出现过 level: info ``` #### 3. JS 错误率过高 ```yaml name: JS 错误率过高 type: threshold metric: error_rate # 错误数 / PV window: 5m threshold: 5% # 错误率超过 5% level: critical ``` #### 4. 页面性能劣化 ```yaml name: LCP 性能劣化 type: threshold metric: lcp_p95 window: 15m threshold: 4000 # P95 LCP > 4s level: warning ``` #### 5. 接口错误率过高 ```yaml name: 接口错误率过高 type: threshold metric: api_error_rate window: 5m threshold: 10% level: critical ``` --- ## 三、告警引擎架构 ### 3.1 整体架构 ``` ┌──────────────────────────────────────────────────────┐ │ 事件流 │ │ 错误事件 ──→ 实时检测 ──→ 触发规则 ──→ 告警通知 │ │ (快路径) │ └──────────────────────────────────────────────────────┘ ┌──────────────────────────────────────────────────────┐ │ 定时任务 │ │ Loki/MySQL ──→ 指标计算 ──→ 规则匹配 ──→ 告警通知 │ │ (慢路径) │ └──────────────────────────────────────────────────────┘ ``` ### 3.2 双路径设计 #### 快路径:实时检测(秒级) 用于:新错误出现、错误数突增(粗粒度) ``` 事件入队 ↓ 实时规则引擎 ├─ 检查是否是新指纹(内存 BloomFilter) ├─ 检查 1 分钟错误数是否突增 └─ 触发 → 入告警队列 ↓ 告警收敛 + 去重 ↓ 通知 ``` #### 慢路径:定时检测(分钟级) 用于:复杂计算、分位数、错误率 ``` 定时任务(每 5 分钟) ↓ 从 Loki/MySQL 拉取指标 ↓ 计算同比、环比、分位数 ↓ 匹配告警规则 ↓ 触发 → 入告警队列 ↓ 告警收敛 + 去重 ↓ 通知 ``` --- ## 四、告警规则引擎 ### 4.1 规则数据结构 ```sql CREATE TABLE alert_rules ( id BIGINT PRIMARY KEY AUTO_INCREMENT, project_id VARCHAR(64) NOT NULL, name VARCHAR(128) NOT NULL, description TEXT, -- 规则类型 type VARCHAR(32) NOT NULL, -- threshold / spike / new_error / error_rate -- 规则配置(JSON) config JSON NOT NULL, /* { "metric": "error_count", "window": "5m", "threshold": 100, "compare": "1h_ago", "operator": ">" } */ -- 告警级别 level VARCHAR(32) NOT NULL, -- info / warning / critical -- 通知渠道 channels JSON NOT NULL, /* [ { "type": "webhook", "url": "https://..." }, { "type": "email", "to": ["a@b.com"] } ] */ -- 收敛配置 group_by VARCHAR(64), -- 按指纹/项目/页面分组 interval INT DEFAULT 300, -- 同组告警间隔(秒) max_count INT DEFAULT 10, -- 每小时最多告警次数 -- 状态 enabled TINYINT DEFAULT 1, created_at DATETIME, updated_at DATETIME, INDEX idx_project (project_id) ); ``` ### 4.2 规则匹配流程 ``` 新指标数据到达 ↓ 加载项目的所有启用规则 ↓ 逐条匹配 ├─ 类型匹配? ├─ 条件满足? └─ 未被静默? ↓ 触发告警 ↓ 告警去重 + 收敛 ↓ 发送通知 ``` ### 4.3 内置规则表达式 支持简单的表达式语法: ``` # 阈值比较 error_count > 100 error_rate > 0.05 lcp_p95 >= 4000 # 同比环比 error_count / error_count_1h_ago > 2 error_count > error_count_1d_ago * 1.5 ``` --- ## 五、告警收敛与降噪 ### 5.1 降噪策略 | 策略 | 说明 | 效果 | |------|------|------| | **同指纹去重** | 同一错误 5 分钟内只告警 1 次 | 减少 80% 重复告警 | | **分组收敛** | 按项目/级别聚合,合并发送 | 减少通知数量 | | **频率限制** | 每项目每小时最多 N 条 | 防止告警风暴 | | **静默期** | 已知问题可设置静默 | 忽略已知问题 | | **最小阈值** | 数量太少不告警 | 避免噪音 | ### 5.2 告警去重键 ``` 去重键 = project_id + rule_id + fingerprint + 时间窗口 ``` 同一去重键在 `interval` 时间内只发 1 次告警。 ### 5.3 告警升级 - 持续时间超过 30 分钟 → 级别升级(warning → critical) - 影响用户数超过阈值 → 级别升级 - 持续超过 2 小时 → 通知更多人 --- ## 六、通知渠道 ### 6.1 支持的渠道 | 渠道 | 说明 | 适用场景 | |------|------|----------| | **Webhook** | 通用 HTTP 回调 | 飞书、钉钉、企业微信、Slack | | **邮件** | SMTP 发送 | 正式通知、归档 | | **Server酱** | 微信推送 | 个人项目 | | **飞书机器人** | 专用适配 | 飞书团队 | | **钉钉机器人** | 专用适配 | 钉钉团队 | ### 6.2 Webhook 格式 ```json { "alert_id": "alert_abc123", "rule_id": 123, "rule_name": "错误数量突增", "level": "critical", "project_id": "1001", "project_name": "前端项目", "metric": "error_count", "value": 250, "threshold": 100, "window": "5m", "description": "5 分钟内错误数达到 250,超过阈值 100,增长 150%", "details": { "error_type": "TypeError", "top_errors": [ { "fingerprint": "a1b2c3", "message": "...", "count": 100 }, { "fingerprint": "d4e5f6", "message": "...", "count": 50 } ] }, "link": "https://log.example.com/manage/#/errors?project=1001", "timestamp": "2024-01-01T00:00:00Z" } ``` ### 6.3 飞书 / 钉钉适配 提供现成的模板,直接粘贴 Webhook URL 即可使用: - 飞书:使用富文本卡片,支持点击跳转 - 钉钉:使用 Markdown 格式,支持 @人 --- ## 七、告警事件存储 ### 7.1 告警历史表 ```sql CREATE TABLE alert_events ( id BIGINT PRIMARY KEY AUTO_INCREMENT, project_id VARCHAR(64) NOT NULL, rule_id BIGINT NOT NULL, rule_name VARCHAR(128), level VARCHAR(32), -- 告警数据 metric VARCHAR(64), value DOUBLE, threshold DOUBLE, description TEXT, details JSON, -- 状态 status VARCHAR(32) DEFAULT 'firing', -- firing / resolved / acknowledged -- 时间 started_at DATETIME, resolved_at DATETIME NULL, duration INT, -- 持续时间(秒) created_at DATETIME, updated_at DATETIME, INDEX idx_project_time (project_id, started_at), INDEX idx_status (status) ); ``` ### 7.2 状态流转 ``` firing ──→ acknowledged ──→ resolved │ ↑ └───────────────────────────┘ 自动恢复(指标降下来) ``` --- ## 八、实现方案 ### 8.1 轻量实现(v1) **技术栈**:Node.js + 内存定时器 + MySQL ``` API Server 进程内 ├─ 事件消费时同步检测(快路径) │ ├─ 新错误检测(BloomFilter) │ └─ 简单计数(1min 滑动窗口) │ └─ 定时任务(慢路径) └─ 每 5 分钟跑一次复杂规则 ``` **优点**:无额外组件,部署简单 **缺点**:单进程,无法水平扩展 ### 8.2 独立服务(v2) **技术栈**:独立的 Alert Worker 进程 + Redis ``` API Server → Redis Stream → Alert Worker → 规则匹配 → 告警收敛 → 通知发送 ``` **优点**:可独立扩展,不影响接入性能 **缺点**:多一个组件 --- ## 九、静默与抑制 ### 9.1 静默规则 用户可以设置静默期,暂时忽略某些告警: ```yaml - project_id: 1001 fingerprint: a1b2c3d4 reason: "已知问题,下个版本修复" start_time: 2024-01-01 00:00:00 end_time: 2024-01-03 00:00:00 created_by: user1 ``` ### 9.2 抑制规则 高优先级告警抑制低优先级: - critical 级别的错误告警触发后,同指纹的 warning 级告警被抑制 - 项目级别的大故障告警触发后,该项目的其他告警被抑制 --- ## 十、与现有系统集成 ### 10.1 当前状态 - 有 Loki 存原始数据 → 可用于慢路径查询 - 有 MySQL(待加聚合层)→ 可存规则和告警历史 - 有管理后台 → 可加告警管理页面 ### 10.2 落地步骤 **v1(最小可用)**: 1. 新增 alert_rules 和 alert_events 表 2. 实现新错误检测(快路径,内存 BloomFilter) 3. 实现 Webhook 通知 4. 管理后台加告警规则配置页面 **v2(增强)**: 1. 实现定时规则引擎(慢路径) 2. 增加突增检测、错误率检测 3. 支持飞书/钉钉专用模板 4. 告警收敛和静默功能 **v3(完善)**: 1. 独立 Alert Worker 服务 2. Redis 队列 + 分布式锁 3. 更复杂的规则表达式 4. 告警抑制和升级