10 KiB
10 KiB
告警引擎设计文档
一、设计原则
1.1 核心原则
- 快:错误发生后 1 分钟内触发告警
- 准:减少误报,告警要有价值
- 全:支持多种告警规则和通知渠道
- 轻:不依赖复杂组件,轻量实现
1.2 告警目标
- 错误突增:及时发现线上故障
- 新错误出现:第一时间感知新问题
- 错误率超标:质量红线监控
- 性能劣化:用户体验下降预警
二、告警规则类型
2.1 规则分类
| 类型 | 说明 | 实时性 | 复杂度 |
|---|---|---|---|
| 阈值告警 | 指标超过固定阈值 | 高 | 低 |
| 突增告警 | 同比/环比增长超过阈值 | 中 | 中 |
| 新错误告警 | 出现新的错误指纹 | 高 | 低 |
| 错误率告警 | 错误率超过阈值 | 中 | 中 |
| 质量分告警 | 性能/质量综合评分下降 | 低 | 高 |
2.2 内置规则模板
1. 错误数量突增
name: 错误数量突增
type: spike
metric: error_count
window: 5m # 检测窗口
compare: 1h_ago # 对比:1小时前
threshold: 200% # 增长 200% 触发
min_count: 10 # 最少 10 条才检测(避免噪音)
level: warning
2. 新错误出现
name: 新错误出现
type: new_error
metric: error_fingerprint
window: 24h # 过去 24 小时没出现过
level: info
3. JS 错误率过高
name: JS 错误率过高
type: threshold
metric: error_rate # 错误数 / PV
window: 5m
threshold: 5% # 错误率超过 5%
level: critical
4. 页面性能劣化
name: LCP 性能劣化
type: threshold
metric: lcp_p95
window: 15m
threshold: 4000 # P95 LCP > 4s
level: warning
5. 接口错误率过高
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 规则数据结构
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 格式
{
"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 告警历史表
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 静默规则
用户可以设置静默期,暂时忽略某些告警:
- 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(最小可用):
- 新增 alert_rules 和 alert_events 表
- 实现新错误检测(快路径,内存 BloomFilter)
- 实现 Webhook 通知
- 管理后台加告警规则配置页面
v2(增强):
- 实现定时规则引擎(慢路径)
- 增加突增检测、错误率检测
- 支持飞书/钉钉专用模板
- 告警收敛和静默功能
v3(完善):
- 独立 Alert Worker 服务
- Redis 队列 + 分布式锁
- 更复杂的规则表达式
- 告警抑制和升级