夜莺和 prometheus 告警流程比照剖析
prometheus 告警流程剖析
以 sum(rate(coredns_dns_requests_total[1m])) > 100 为例
- alert 和 record 复用大部分逻辑
- prometheus 依据配置文件中拿到规定
- 解析规定查问本地存储或远端存储(带触发条件),trigger 在存储端
- 返回一组以后点后果集,返回多少个对应多少条告警
- 依据内存中的历史数据判断告警持续时间 (for 1 min) 有没有达到
- 发送告警 event 给 alertmanager
- 由 alertmanager 做告警的发送、静默、分组路由、关联、回调
夜莺告警流程剖析
- monapi 定时从 db 同步策略,judge 依据本人的 ident 拿到属于本人的策略
- transfer 依据存活的 judge 拿到所有策略,将策略的 judge 地址填好
-
transfer 收到 agent push 的数据后,算 hash 拿到策略列表
- 依据策略拿到 judge 地址,依据缓存拿到对应的队列,将数据塞入队列中
- judge 收到策略后,依据策略中的 fun 做触发
- 依据策略中配置实现 发送工夫、告警降级、回调等
两边本质区别
零碎 | 阈值判断 | 是否反对多 series 告警 | 触发条件 | 组合条件 | nodata |
---|---|---|---|---|---|
夜莺 v4 push 代表 | 由 judge 接收点触发判断,查问本地数据 | 不反对,每个策略针对繁多 series 对应 judge 中内存列表 只能用预聚合解决 |
将 happen、all、any 等和聚合 avg max min 等揉在一起 | 需做 pull | 需做 pull |
prometheus pull 代表 | 由 promql 查问存储 | promql 间接反对 查问到一个就是一条,多个就是多条 |
prometheus 触发条件只反对 持续时间,其余的全副为聚合 func | promql and 反对 | promql absent 反对 |
告警 push 模式的性能晋升问题
总结就是相比于性能损耗 pull 模型带来的灵活性是微小的
- push 型的告警模式无疑会带来性能晋升
- 因为 pull 模型须要每次查问存储,尽管是以后点,但也有些损耗
-
然而
- 古代的 tsdb 有倒排索引 + 布隆过滤器的加持,告警查问损耗能够降到很低 - pull 模型带来的是非常灵活的触发表达式,从这点看,性能损耗能够疏忽不急 - 而且当初告警触发时都须要带上一些聚合的办法,这点 push 模型做不到
告警 push 模式能够工作在查问存储挂掉的 case
因为 push 本地内存中有响应的数据,然而我感觉这是个伪劣势
在夜莺中引入 pull 的问题
- 最大的能源是否是相中了 promql
- 存储和采集不反对 promql
- 触发和聚合混在一起
代码剖析
夜莺 v4 代码问题
- 策略太多双层 map reinit 耗时长
- 全局变量满天飞
-
syncStras
全副更新,耗时长,db read 高- 每个 judge 实例拿到的还是全局数据,而且没有抢锁设计,导致多个 judge 实例同时全表读 db - 除非 db 那里做分片,分 region
- judge push 模型报警很难将 pull 模式融入进来
prometheus 告警代码剖析
- update 加载配置文件,增量更新告警 / 聚合 group
-
group.Eval 计算组里的规定
- `// Eval runs a single evaluation cycle in which all rules are evaluated sequentially.` - `vector, err := rule.Eval(ctx, ts, g.opts.QueryFunc, g.opts.ExternalURL)` - 返回的是 vector `type Vector []Sample` 代表享有对立时刻的一堆 point - rule.Eval 分为规定和聚合 `alert/record` - 调用 EngineQueryFunc,外部调 instance_query - `// EngineQueryFunc returns a new query function that executes instant queries against// the given engine.` - 如果没取到数据,证实没达到触发条件则,只解决历史的 alert,看看持续时间到了没 - 如果 rule 是 alert 则走发送逻辑 ` if ar, ok := rule.(*AlertingRule); ok {ar.sendAlerts(ctx, ts, g.opts.ResendDelay, g.interval, g.opts.NotifyFunc)}` - alert 存在 headblock 中,record 写入存储中?
夜莺 v4 告警代码 剖析
-
judge 依据本人的 ident 拿到属于本人的策略
stras := cache.StraCache.GetByNode(node)
- 更新本地 `cache.NodataStra` 和 `cache.Strategy`
-
monapi 定时从 db 同步策略
syncStras
- 分设施相干 or 设施无关 - 依据策略的 id 算哈希,生成 `strasMap [judge_ip_port][]*stra` - 全量更新 `cache.StraCache`
-
transfer 依据存活的 judge 拿到所有策略
stras := cache.StraCache.GetAll()
,将策略的 judge 地址填好- 依据所有策略的 metrics 算哈希 - 哈希前两位作为 map 的第一层 key - 外部 map key 为 哈希值,value 为 策略列表 - `straMap := make(map[string]map[string][]*models.Stra)` - `cache.StraMap.ReInit(straMap)`
-
transfer 收到 agent push 的数据后,算 hash 拿到策略列表
- 遍历策略列表 匹配 tag - 依据策略拿到 judge 地址,依据缓存拿到对应的队列,将数据塞入队列中
- judge rpc send 中
go judge.ToJudge(cache.HistoryBigMap[pk[0:2]], pk, item, now)