目录

EKD · 基于 eBPF 的系统异常观测与根因定位工具

形态:一个 C++20 可执行文件(采集 + 检测 + 存储 + HTTP + 报告)+ 一个独立的 Python 因果分析服务 + 静态大屏 + 单文件 SQLite。 三条采集通路各自独立:常态化宏观指标、内核异常事件、阈值触发的深度快照。

设计主张

采集分三面,互不依赖——这是本项目与”一个窗口里什么都有”的传统监控最大的区别:

平面 做什么 触发判据 产出
指标 plane/metrics 常态化采集主机宏观量(26 项,纯 /proc) 固定节拍(默认 1 s) 内存环 + SQLite(原始点 + 滚动汇总)
事件 plane/events 内核异常事件发生的那一刻抓现场 各自独立的物理阈值(ns/字节/次) 逐事件记录(含内核栈、资源对象)
快照 plane/snapshot 阈值命中后短窗深度采集 各自独立的阈值 + 冷却 + 全局单飞 快照记录(火焰图/进程排行/阻塞栈/内存构成)

主机异常检测(detect/)只读指标面,产出 incident 时间窗——它回答”哪段时间不正常”, 不回答方向、不回答类型、不回答根因;也不触发任何快照(两条通路正交,有专门验收项钉这条)。 实现是绝缘参考 + 双通道累积和监视器:参考层(Huber 位置 + 有界影响尺度 + 日周期时段槽)给出”正常水平与正常波动”, 检测层用 EWMA(抓大阶跃)与 CUSUM 对(抓小而持续的位移)双通道判定, 门限由误报预算在启动时按 ARL 目标解出(M×2×T_week/ARL0 ≤ 1 次假主机事件/周),之后与数据彻底解耦。

因果分析(src/causal,独立 Python 服务,无写库权)不是常态跑,而是事件触发的一次分析: incident 闭合 → 执行器把它窗口内(前 60 s / 后 10 s)的全部已采集数据打成 ekd.panel.v1 数据包 → POST 给分析服务 → 结论作为一条 kCausal 记录落库 → 报告端点引用它(不复述、不改写)。 结论分三级(fact / temporal / hypothesis),只有拿到干预或结构机制证据才允许使用”因果”字样; 样本不足、无幸存变更、事件过稀疏、输入被截断 → 一律如实降级为 insufficient 并写出缺口码,root_causes 为空数组。

结构化报告(report/)把 incident 与窗口内的事件/快照装配成 anomaly_type / objects / key_metrics / window / evidence / suspected_cause / causal / basis / gaps。 suspected_cause 是规则推断(字段里明写 basis=rule_inference);causal 块只放分析服务的原样结论, 服务不可达时写 unavailable + 原因,并在 gaps 里明说”未经因果确认,不得据此认定根因”。

设计红线(违反即返工)

  1. 缺失 ≠ 0:任何数值都带 state(observed / no_events / warming_up / gated / degraded / unavailable / held)。 读不到不能填 0 冒充正常,也不能当成”没有异常”。检测器对”整段缺席”的指标按已知名册记账, 对”尺度估不出来”的指标不判定(不可评 ≠ 正常)。
  2. 阈值一律物理量(ns/字节/次),随记录一起落库,结论可复算;检测器阈值另附 ARL 口径与并集界。
  3. 跨口径禁比:轮询精确量 / 2^k 分桶 / 抽样估计三者不得直接比较。
  4. 任何丢弃都要有计数器并被读出:ringbuf 丢失、限流拒绝、落库队列丢弃、分析输入截断,一个都不许静默。
  5. 探针不碰存储与网络:一律经 RecordSink 入队,由唯一写线程落库。
  6. 检测不做因果;因果不编结论(服务不可达 → unavailable + 原因)。

目录

src/
├── ekd/                     C++20 单二进制
│   ├── include/ekd/         对外契约(唯一事实源):contracts / platform / probe / record / config / store
│   ├── src/
│   │   ├── core/            时钟、日志、契约的 JSON 序列化(字段名的唯一来源)
│   │   ├── config/          JSON 配置(支持 // 注释)解析 + 语义校验
│   │   ├── probe/           框架:单注册表 + 三角色 + 每探针一线程
│   │   ├── bpf/             加载·挂载·ringbuf·perf 采样器·符号化;prog/ 每探针一个 BPF 对象
│   │   ├── collect/         /proc 读取器、cgroup v2 解析、进程扫描、差分器
│   │   ├── plane/metrics/   26 项指标 + 内存环 + 滚动汇总
│   │   ├── plane/events/    8 类内核异常事件
│   │   ├── plane/snapshot/  6 类深度快照 + 触发闸(冷却/单飞/并发)
│   │   ├── detect/          ir_dcm(检测器本体)+ detect_runner(接线层)
│   │   ├── store/           SQLite(WAL) 单写路径
│   │   ├── api/             HTTP + SSE(只服务自制大屏)
│   │   ├── report/          结构化报告 · Panel 组装 · 因果服务客户端 · 因果执行器
│   │   └── main.cpp         组合根:有序启动步骤 + 逆序清理
│   ├── web/index.html       自制大屏(单文件、零外部依赖、离线可用)
│   ├── tools/               逐阶段验收脚本(s1..s7)· arl_check.py · perf_check.sh
│   └── docs/                REFACTOR_PLAN.md(设计权威)· ACCEPTANCE.md(验收留档)
└── causal/                  因果分析服务(Python:仅 numpy + scipy + stdlib)
    ├── service.py           POST /analyze · GET /health
    ├── cli.py               离线跑同一流水线(复核用)
    ├── panel.py audit.py engine.py falsify.py route.py
    └── tests/               合成数据用例(含扫描零校准回归)

构建与运行

# 构建(依赖全部随源码内置:spdlog / nlohmann-json / cpp-httplib / libbpf 1.8)
cmake -S src/ekd -B src/ekd/build -G Ninja && ninja -C src/ekd/build

# 单元测试(含检测器 54 项断言)
ctest --test-dir src/ekd/build

# 配置自检
src/ekd/build/ekd --check-config --config src/ekd/ekd.json

# 只跑指标面与检测面(不需要 root)
src/ekd/build/ekd --config src/ekd/ekd.json --port 8899

# 全量(事件面与快照面需 root 或 CAP_BPF)
sudo src/ekd/build/ekd --config src/ekd/ekd.json --port 8899

# 因果分析服务(默认不接线:ekd.json 里 causal.port = 0)
python3 src/causal/service.py --port 9400
#   接线:把 causal.port 改成 9400(或任何已监听端口)后重启 ekd
#   离线复核:python3 src/causal/cli.py analyze --panel <panel.json>

# 大屏
#   浏览器打开 http://127.0.0.1:8899/ ;点击 incident 行查看结构化报告(含因果结论)

验收

逐阶段脚本,每项都判 PASS/FAIL/SKIP 并打印证据(数字、命令行、返回体),需要 root 的项自动提权:

bash src/ekd/tools/s1_accept.sh   # 框架 + 1 指标 + 1 事件 + 1 快照 + SQLite + 大屏取数
bash src/ekd/tools/s2_accept.sh   # 26 项指标 + 滚动汇总
bash src/ekd/tools/s3_accept.sh   # 8 类内核事件
bash src/ekd/tools/s4_accept.sh   # 6 类深度快照
bash src/ekd/tools/s5_accept.sh   # 检测 → incident 时间窗(含"检测不触发快照")
bash src/ekd/tools/s6_accept.sh   # 结构化报告
bash src/ekd/tools/s7_accept.sh   # 因果端到端(含服务不可达负例与重启幂等)

# 阈值口径的独立复算(两套独立机制互证:马尔可夫链网格解 vs 蒙特卡洛)
python3 src/ekd/tools/arl_check.py --solve --metrics 26
# 开销实测(检测面开/关对照)
bash src/ekd/tools/perf_check.sh 120

当前实测状态与未完成项见 src/ekd/docs/ACCEPTANCE.md (七个阶段全绿;多架构 QEMU 未执行,方案见 REFACTOR_PLAN.md §10)。

环境

  • 目标:openKylin / 内核 ≥ 6.6(x86_64 已验证),需 root 或 CAP_BPF/CAP_PERFMON/CAP_SYS_ADMIN (仅事件面与快照面需要;指标面与检测面读 /proc 即可,可非 root 运行)。
  • 因果分析服务:Python 3 + numpy + scipy(不引入其它依赖);未接线时检测/报告链路不受影响。
  • 依赖版本锚点见 src/ekd/docs/REFACTOR_PLAN.md。
  • 多架构(ARM64/RISC-V)方案见 REFACTOR_PLAN.md §10(未执行)。
关于
209.7 MB
邀请码
    Gitlink(确实开源)
  • 加入我们
  • 官网邮箱:gitlink@ccf.org.cn
  • QQ群
  • QQ群
  • 公众号
  • 公众号

版权所有:中国计算机学会技术支持:开源发展技术委员会
京ICP备13000930号-9 京公网安备 11010802047560号