本文深度解析通知告警系统的事件驱动架构、多渠道 Webhook、冷却机制与队列分发模型。
GitHub https://github.com/AneiangSoft/Aneiang.Yarp
Gitee https://gitee.com/aneiangsoft/aneiang-yarp
官方文档 https://yarp.aneiang.com
在线演示 https://yarp-test.aneiang.com/aneiang (账号
admin/demo123)

一、功能背景
没有告警的生产网关,等于没有哨兵的城堡。Aneiang.Yarp 2.3.0.20 的通知系统解决:把"被动发现"变成"主动推送"——当网关检测到安全攻击、服务故障或配置变更时,通过 Webhook 实时推送到 IM/告警平台。
二、事件驱动架构
事件源(分散在各模块)├── WafMiddleware → WAF 拦截├── CircuitBreakerMiddleware → 熔断器打开├── RequestRetryMiddleware → 重试耗尽├── YARP 代理层 → 代理 5xx├── RateLimitMiddleware → 限流触发└── ConfigChangeAuditLog → 配置变更│ 调用 NotifyXxx()(fire-and-forget)▼
ConfigChangeEventDispatcher (BackgroundService, 200ms 轮询)ConcurrentQueue<PendingNotification> ← readonly struct, 零堆分配│▼
NotificationService├── 匹配告警规则 → 匹配渠道 → 冷却检查 → 发送└── 记录 SQLite 通知历史
关键设计:事件源(中间件)调用 NotifyXxx() 后立即返回,不阻塞业务请求。分发器在后台异步处理。
三、六大事件类型
| 事件 | 触发条件 | 级别 | 典型场景 |
|---|---|---|---|
| CircuitBreakerOpen | 连续失败 > FailureThreshold | 严重 | 下游服务崩溃 |
| RetryExhausted | 全部重试仍失败 | 警告 | 间歇性网络故障 |
| WafBlock | WAF 规则命中 | 严重 | 恶意攻击 |
| ProxyError | 反向代理 5xx | 警告 | 目标服务异常 |
| RateLimitExceeded | 请求超速率限制 | 提示 | 流量突增 |
| ConfigChange | 路由/集群 CRUD | 信息 | 运维审计 |
四、多渠道 Webhook 配置
钉钉机器人
{"ChannelType": "DingTalk","WebhookUrl": "https://oapi.dingtalk.com/robot/send?access_token=xxx","TimeoutMs": 5000,"RetryCount": 3
}
推送 Markdown 格式,支持 @所有人。
通用 HTTP Webhook
{"ChannelType": "Http","WebhookUrl": "http://your-alert-manager:9093/api/v1/alerts","CustomHeaders": {"X-Alert-Source": "AneiangGateway","Authorization": "Bearer your-token"},"TimeoutMs": 10000,"RetryCount": 2
}
可对接 Prometheus AlertManager、企业微信、飞书、自定义告警平台。
渠道参数说明
| 参数 | 类型 | 默认值 | 说明 |
|---|---|---|---|
ChannelType |
enum |
— | DingTalk 或 Http |
WebhookUrl |
string |
— | Webhook 地址 |
CustomHeaders |
dict |
— | 自定义请求头 |
TimeoutMs |
int |
5000 |
发送超时(毫秒) |
RetryCount |
int |
0 |
失败重试次数 |
五、告警冷却机制
为什么需要冷却?
没有冷却:熔断打开 → 通知 → 熔断打开 → 通知 → ...(刷屏)有冷却(默认 300s):熔断打开 → 通知 → 冷却中(5min)... → 冷却结束再次熔断打开 → 通知
实现原理
每事件规则独立配置冷却时间。NotificationService 维护 ConcurrentDictionary<string, DateTime> 追踪最近发送时间,同类型事件在窗口内跳过发送。
| 配置项 | 默认值 | 说明 |
|---|---|---|
| 冷却时间 | 300 秒 | 同一事件两次通知的最小间隔 |
| 作用域 | 按事件类型 | 不同类型独立计算 |
六、通知历史持久化
所有发送记录写入 SQLite NotificationHistory 表,Dashboard 支持分页查询 + 按事件类型过滤 + 查看发送成功/失败状态。
-- 概念示意
NotificationHistory├── Id, EventType, ChannelId├── Title, Message├── IsSuccess, ErrorMessage└── Timestamp
七、配置变更自动通知
通知系统与审计日志深度集成:
用户修改路由 → ConfigChangeAuditLog 记录审计→ ConfigChangeEventDispatcher 入队通知事件→ NotificationService 匹配规则 → 发送通知
路由/集群的增删改、重命名、配置回滚,均自动产生通知,无需额外代码。
八、Dashboard 管理界面
通知设置页面提供三大管理区域:
| 区域 | 功能 |
|---|---|
| Webhook 渠道管理 | 添加/编辑/删除/测试渠道连通性 |
| 告警规则配置 | 6 种事件类型独立开关 + 冷却时间设置 |
| 高级设置 | 超时/重试/通知历史上限 |
九、启动预热
StartupWarmupService 启动时自动创建 11 种事件类型的默认通知规则(种子数据);NotificationWarmupService.PreloadAsync() 将渠道/规则/设置加载到内存缓存。预热失败不阻塞应用启动。
十、常见问题
| 问题 | 解答 |
|---|---|
| 通知不发 | 检查渠道连通性(Dashboard 有测试按钮)、检查告警规则开关、检查冷却窗口 |
| 延迟多久? | 200ms 轮询间隔 + HTTP 发送时间,通常 300-500ms |
| 支持哪些渠道? | 钉钉机器人 + 通用 HTTP Webhook(可对接 AlertManager/企业微信/飞书等) |
| 通知有重试吗? | 有,每渠道独立配置 RetryCount |
