📝 术语别名
  • II-log: Incident-Indicating Log, 真正能告诉你故障在哪的那批 log;
  • Log clique: 一组高度相似 / 频繁共现的 log template, 是 Onion 聚类的产物;
  • Anomalous server: incident 时段触发了 alert 或 metric 异常的实例;
  • Normal server: 同服务下未受影响的同伴实例;
  • Bilateral: 双边对比, 这里指 anomalous 集 vs normal 集的对比;

前置: 为什么 raw log 不能直接喂给 RCA 系统

云服务一次 incident 的 log 量级通常是百万到亿条, 真正与故障有因果关系的可能只有几十条; 中间夹着大量噪声:

  • routine heartbeat;
  • 健康探针 (GET /health 200);
  • 周期性 batch / cron 任务的常规 log;
  • 跨实例都有的全局事件 (版本 reload, 集群配置 push);
  • 上下游服务的非关键 warning;

如果直接把全量 log 倒给下游 (人或者 LLM 或者经典 RCA model), 信号会被噪声淹没; 所以先做一道 incident-indicating log 过滤是 RCA pipeline 的刚需;

Onion 解决的就是这一步; 它不试图直接给出 root cause, 只回答一个更窄的问题:

“在这堆 log 里, 哪几十条是真正跟这次事故相关的?”

论文定位

Onion 是 Microsoft 内部生产部署的一个 log filter, 在 ESEC/FSE 2021 发出来; 它有几个工业系统 paper 的硬指标特征:

  • F1 = 0.95 (在 MS 真实事故数据上);
  • 百万级 log 几分钟跑完 (单机 CPU);
  • 不需要训练数据、不需要标注、没有 GPU 需求;

这三个数字组合直接告诉你: 它不是 DL, 不是 trained model, 是纯经典统计 + 图论 + 聚类; 这是它能在生产里活得下去的关键 — 部署门槛低, 在线开销低, 可解释性高;

Onion 的位置在 RCA pipeline 里非常清晰:

1
2
3
4
5
raw logs ──► [Onion] ──► incident-indicating logs ──► [downstream RCA]

├─► 人类 OCE
├─► RCACopilot 类 LLM
└─► 任何 root cause 分类器

它是前置过滤器, 不是 end-to-end RCA; 不要把它误读成"输入 log 输出 root cause";

论文解决的核心问题

具体回答的问题是:

  1. 怎么定义"跟 incident 相关"才能既精准又不依赖人工标注?
  2. 怎么把"判定相关"这件事做到既快又稳, 适合工业流量?
  3. 怎么处理"流量自然波动 / 周期任务 / 版本上线" 这些跟 incident 同时段但无关的噪声?

论文识别的两个 Technical Difficulty

paper 在 motivation 部分明确把"为什么这件事难"拆成两条, 这两条直接对应了后面三准则 + clique 设计的取舍, 值得单独拎出来:

Difficulty 1: 海量 + 多样 + 低信噪比的 log 数据

云服务的 log 同时具备三个让传统方法吃瘪的特征:

子属性 表现 为什么是技术难点
Volume (海量) 一次 incident 关联的 log 通常百万到亿级 任何需要 O(n2)O(n^2) 或更高复杂度的算法都直接不可行
Diversity (多样) 跨服务、跨组件、跨版本的 log 格式天然不一致 没法用一套硬编码规则去 match, 需要自适应的 representation
Overwhelming details (噪声压倒) 99%+ 是健康路径上的 routine log (heartbeat, success ack, monitor probe) 真正与故障相关的 log 比例极小, signal 被 noise 海量稀释
📝 这一难点直接催生了什么设计
  • Volume 难点 → 选统计加权 + 渐进聚类而非 DL/embedding, 保证百万 log 几分钟跑完;
  • Diversity 难点 → incident-aware representation, 不依赖固定 schema, 跨服务跨格式都通用;
  • Noise 难点 → 三个准则联合筛选 (Consistency + Impact + Bilateral-Diff), 单一指标过不了的噪声会被另一个滤掉;

Difficulty 2: Confounding events (混淆事件) 让朴素时间对比失效

这是 paper 的真正深度洞察, 也是最容易被忽略的难点:

incident 时段并不只有 incident 一件事在发生; 同时段往往叠加了:

  • 流量自然波动: 周一上午、月底结算、热点事件爆发引发的全局流量增长;
  • 周期性 batch / cron: 每小时备份、每日统计、每周 compaction 这种定时任务;
  • 版本 deployment: 灰度发布、配置 push、客户端强制升级;
  • 跨服务级联反应: 上游服务变更触发下游响应模式变化, 但不一定是 incident;

这些事件和 incident 在 log 上的"统计扰动"很相似 — 都会让某些 log template 出现频率突变, 都是"跟之前不一样"; 朴素的"incident 时段 vs baseline 时段"对比根本分不开:

1
2
3
4
5
6
7
朴素时间对比:
incident 时段 template T 频率: 0.85
baseline 时段 template T 频率: 0.20
→ "T 显著偏高, 一定是 incident 信号!"

实际可能:
这只是周一早高峰流量上来的常规反应, 跟 incident 毫无关系

这是 confounding events 给纯时间维度对比下的死结: 你想知道"是不是 incident 信号", 但你看到的统计变化既可能是 incident 也可能是上面任意一种 confounding event, 从单一时间序列里没法分离;

[!这一难点直接催生了 Bilateral-Difference]

Bilateral 用空间对比 (同时段不同实例: anomalous server vs normal server) 替代 / 补充 时间对比; confounding events 因为是全局事件, 会同时打在 anomalous 和 normal 实例上, 两边都涨, 差为零, 自然抵消; 而真正的 incident 信号是局部的 — 只在出问题的实例上密集出现, normal 实例上几乎没有, 空间差异显著; 这一招把 confounding 噪声从空间维度上滤掉, 是 Onion 整套方法论里最妙的一笔;

两个 Difficulty 怎么映射到三准则 + clique

把 Difficulty 和后面 design 的对应关系列出来:

Technical Difficulty 直接催生的设计
Diff 1 (Volume + Noise) Impact 准则 (用量级 + burst 度过滤低频次噪声) + 渐进聚类 (压缩 template 数)
Diff 1 (Diversity 跨服务) Incident-aware Representation (统计特征跨格式通用)
Diff 1 (Cross-incident 泛化) Consistency 准则 (跨历史 incident 的复现率)
Diff 2 (Confounding events) Bilateral-Difference 准则 (空间对比代替时间对比)
Diff 2 (单 template 不稳) Log Clique 聚合 (多个 template 一起算统计指标, ensemble 更稳)

这是一个非常完整的 design rationale: 每一个核心机制都对应一个明确的 technical difficulty, 没有为了 fancy 而 fancy 的部分;

核心机制 1: 三个 incident-indicating 准则 (核心 insight)

这是 Onion 最有价值的方法论贡献, 把"什么 log 才算 incident-indicating" 拆成三个互相正交、各自打不同噪声的统计指标:

Consistency (一致性)

同类 incident 反复出现时, 这个 log 是不是反复出现?

衡量: 一个 log template 在历史相似 incident 里的复现率;

防的是什么:

  • 偶发噪声: 某次 incident 凑巧出现一次的 log, Consistency 低, 不是真信号;
  • incident-specific quirks: 单次 incident 的特殊记录, 不能泛化;

形式上类似:

Consistency(t):=#{historical incidents 中含 template t}#{historical incidents 总数}\text{Consistency}(t) := \frac{\#\{\text{historical incidents 中含 template } t\}}{\#\{\text{historical incidents 总数}\}}

高 Consistency 的 log = “这种事故反复出现的指纹”;

Impact (影响力)

这个 log 的出现规模和时间集中度够不够 prominent?

衡量: log template 在 incident 时段的出现量级 × 时间集中程度;

防的是什么:

  • 低频偶发记录: 一次 incident 里只出现 2-3 次的 log, 即使 Consistency 高也大概率是噪声;
  • 时间扩散的 log: 在 incident 时段均匀分布、看不出 burst 的 log, 跟 incident 关联弱;

形式上像:

Impact(t):=count(t,incident window)burstiness(t)\text{Impact}(t) := \text{count}(t, \text{incident window}) \cdot \text{burstiness}(t)

burstiness 度量"这些 log 是不是集中在很短一段时间爆发", 高 burstiness 意味着事件性强;

高 Impact 的 log = “确实在 incident 时段被大量、集中触发”;

Bilateral-Difference (双边差异) ⭐

这个 log 在 anomalous 实例上和 normal 实例上的频率差距大吗?

衡量: 同一时段内, log template 在 anomalous server 集合上的频率 和在 normal server 集合上的频率 之间的差异;

形式上:

Bilateral-Diff(t):=freqanomalous(t)freqnormal(t)\text{Bilateral-Diff}(t) := |\text{freq}_{\text{anomalous}}(t) - \text{freq}_{\text{normal}}(t)|

防的是什么 (这是 Onion 最有威力的设计):

噪声源 为什么 Bilateral 能滤掉它
流量自然涨跌 周一上午全部实例 log 都涨, anomalous/normal 同步涨, 差为 0
batch / cron 任务 备份任务在所有实例上都跑, 抵消
版本上线 新格式日志在所有实例上都有, 抵消
全局配置 push 同样所有实例都有, 抵消

[!这就是 Bilateral 的精髓]

Onion 用空间维度的对比 (同时段不同实例) 替代 / 补充 时间维度的对比 (同实例不同时段); 大量噪声会同时打在所有实例上, 空间对比让它们天然抵消, 留下来的差异才是 incident-specific 真信号;

三个准则的分工

这是为什么 Onion 用三个不是一个的核心:

准则 防什么噪声 单独够用吗
Consistency 偶发的 single-incident 噪声 不够, 高频但跟事故无关的 log 也能高 Consistency
Impact 低频 / 时间扩散的非事件性 log 不够, 周期性高频 log (cron) 也能高 Impact
Bilateral-Diff 同时段所有实例都有的全局噪声 不够, 单实例独有的偶发 log 也能高 Bilateral

三者 AND 起来才能锁定真信号; 任何单一准则都有它打不到的噪声死角, 三者互补才能拿到 0.95 F1;

核心机制 2: Incident-aware Representation

这是 Onion 把 log 变成数值向量的方式, 关键判断: 不是 word2vec, 不是学到的 embedding, 不需要训练;

它本质上是带权 TF-IDF 类的统计向量, 但权重是 incident-aware 的;

朴素 TF-IDF 不够用

如果直接用 TF-IDF, 每个 log template 的权重只反映它在所有 log 里的"罕见度"; 这跟 incident 没关系 — 一些极罕见但跟事故无关的 log (例如某种 admin command 偶尔出现) 反而会被推到高权重;

Incident-aware 的权重设计

Onion 的"incident-aware"体现在权重项里显式带入了 incident 上下文, 大致包含这些维度:

  • 在 anomalous server 上的频率;
  • 在 normal server 上的频率;
  • 在 baseline (历史正常时段) 的频率;
  • 这些频率的相对比值 / 差值;
  • 可能再加 token 级别的 TF-IDF 风格分量;

把这些组合成每个 template 的向量分量, 这个向量自然就对 incident-relevant 信号敏感, 对全局噪声 (在 anomalous 和 normal 上都高频的) 不敏感;

📝 关键直觉

这套表示的关键不在用了什么 fancy 模型, 而在特征工程层面就把 incident 上下文编码进去; 所以下游聚类不需要再"学" incident 是什么, 它直接在已经"incident-aware"的空间里做几何运算就够;

跟 word2vec / sentence-bert 的对比

维度 word2vec / SBERT Onion incident-aware repr
是否需要训练 需要 不需要
表示语义 通用语义 incident 相关性
维度 100-768 可以很低 (~10-30 个统计特征)
跨服务迁移 好 (语义通用) 好 (统计准则通用)
推理速度 慢 (向量计算 + ANN) 快 (统计特征)

Onion 选这条路是工业生产的合理判断: 准确率不亚于 (在 RCA-relevant 任务上甚至更优), 但部署成本低一个数量级;

核心机制 3: Progressive Log Clique Algorithm

最后一步是把"打分了的 template" 聚类成有意义的事件单元;

为什么不直接 top-K template

直接对所有 template 按三准则打分排序取 top-K 也能产出结果, 但有几个问题:

  • 同一个故障会触发一组相关 log (例如 connection pool exhausted 会同时引发"wait for connection", “request timeout”, “pool size N reached”), 把它们当独立 entry 报给下游会重复占 token;
  • 单个 template 看起来 prominent, 跟它共现的其它 template 才能给出完整的故障故事;

所以 Onion 把"相关 template"打包成 log clique 再处理;

什么是 log clique

clique 是图论术语, 意思是一组两两都相邻的节点 — 在 Onion 里它意味着一组互相高度相关 / 频繁共现的 log template; 直觉上一个 clique 对应一个故障的 log 表现模式;

渐进式聚类怎么做

Onion 的"progressive log clustering"大概是这样的算法 (基于 paper 的描述推断):

1
2
3
4
5
6
7
8
9
10
11
12
13
初始状态: 每个 log template 自成一个单点 clique


迭代:
1. 计算所有 clique 两两之间的相似度
(基于 incident-aware repr 向量距离 + 共现关系)
2. 找最相似的两个 clique, 合并
3. 检查合并后的 clique 是否仍满足"clique" 性质
(内部所有 template 仍互相强相关)
4. 若满足且代价低于阈值, 则合并; 否则停止扩张


输出: 若干个稳定的 log clique

这是经典的 agglomerative hierarchical clustering, 加了 clique 性质约束作为停止条件; 整个过程不需要预设 K (cluster 数), 这是它叫 “progressive” 的来源 — 自适应增长, 直到自然收敛;

Contrast Analysis on Cliques

clique 形成后, 在 clique 这个粒度上重新计算三个准则, 而不是 template 粒度:

  • 一个 clique 的 Consistency = 这一组 template 在历史 incident 里整体一致的程度;
  • Impact = clique 内 template 总量 + 集中度;
  • Bilateral-Diff = clique 在 anomalous vs normal server 上的整体差异;

最后取 top-K cliques (K 通常 5-10), 这些 clique 内部的所有 template 就是输出的 incident-indicating logs;

[!为什么 clique 比 template 更稳]

单个 template 的统计可能因为采样波动而不稳, 一个 clique 包含多个 template, 统计 ensemble 更稳健, 假阳性率显著低; 这是为什么 Onion 选择"在 clique 上做 contrast" 而不是"在 template 上做 contrast";

完整 pipeline 走一遍

把三个核心机制串起来:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
incident 时段所有 raw logs + anomalous/normal server 划分


Step 1: Log Parsing (Drain 之类, paper 没特别强调这步)
→ templates + 参数


Step 2: Incident-aware Representation
→ 每个 template 一个 incident-context-aware 向量


Step 3: Progressive Log Clique Construction
→ 渐进式聚类得到若干稳定 clique


Step 4: Three-criteria Contrast Analysis on Cliques
→ 算 Consistency / Impact / Bilateral-Diff


Step 5: Top-K Cliques 输出
→ clique 内部所有 template = incident-indicating logs


交给下游 RCA 系统 (LLM / OCE / classifier)

整条 pipeline 没有任何 trained model, 没有 LLM, 没有 GPU 依赖;

跟下游 RCA 的衔接

Onion 的输出怎么进下游, 三种典型用法:

下游 衔接方式
人类 OCE top-K clique 直接展示在 dashboard, OCE 看几条 log 就能起诊断假设
RCACopilot 类 LLM clique 输出 + metric + trace 拼成 prompt, LLM 推根因类别
传统 ML classifier clique 的统计向量当 feature 喂给 SVM / Random Forest, 直接做分类

我们设计的 single-call RCA pipeline 就属于第二种 — Layer 2a 的 Onion-style 过滤直接对接 LLM 的 prompt;

一些值得讨论的局限

对 anomalous/normal split 的强依赖

bilateral-diff 准则成立的前提是有可信的实例划分; 几个边界情形:

  • 全军覆没: 所有实例都坏了, 没有 normal 集做对比, bilateral 退化, 只能靠 Consistency + Impact;
  • 单实例服务: 没有同伴可比, bilateral 完全失效;
  • 划分错了: 把一个 normal 实例当 anomalous (或反之), bilateral 计算被污染;

paper 没特别讨论这些边界情形怎么 fallback;

对 Consistency 的历史依赖

Consistency 需要历史相似 incident 的 corpus, 冷启动时 (新部署系统 / 新故障类型) 用不了; 退化为只剩 Impact + Bilateral;

Log Parsing 的质量上限

整套依赖前置的 log template 提取; 如果 Drain 把本该不同的 log 合并成同一个 template (under-clustering), 或者反过来 (over-clustering), Onion 后面再聪明也救不回来;

纯静态特征的局限

Onion 的特征是手工统计指标, 一些需要语义理解的细微差别它抓不到; 例如两条 log “Failed to connect to db1” 和 “Failed to connect to db2”, token 级别看起来都是同一类, 但实际上分别指向两个不同后端 — 学到的 embedding 能区分, Onion 的 TF-IDF 类表示可能不能;

没有 trace 信号

Onion 只看 log, 不利用 metric 也不利用 trace; 在多模态 RCA 时代这是一个明显遗漏 — 它要求自己单一信号源就解决问题, 给后续工作留了空间 (LLMRCA, GALA 都补上了多模态);

📝 论文主流观点总结

把 Onion 浓缩成几句, 它的主流观点可以总结为:

  1. 云事故 RCA 的瓶颈不是"找根因模型", 而是"在百万 log 里先把噪声滤掉" — 这个步骤独立成方法论值得做;
  2. 三个互相正交的统计准则 (Consistency / Impact / Bilateral-Difference) 联合判断 incident-indicating, 任何单一准则都有死角, 三者 AND 起来覆盖率才够;
  3. Bilateral-Difference 是最大的工程创新: 用同时段不同实例的空间对比, 替代易被流量波动 / 周期任务 / 版本上线干扰的纯时间对比;
  4. 表示层用incident-aware 加权统计, 不用 word2vec 等学到的 embedding, 牺牲一点语义换巨大的部署优势 (零训练成本 + 单机 CPU 跑百万 log 几分钟);
  5. 聚类层用 progressive agglomerative + clique 约束, 把单 template 的不稳统计 ensemble 成 clique 粒度, 假阳性大幅下降;
  6. Onion 是 filter 不是 classifier, 输出 incident-indicating logs 而非 root cause label, 跟下游任何 RCA 系统都好衔接 — 这是它能成为流水线中可复用模块的关键;