eBPF 诊断工具
本目录包含用于监控和诊断 agent_runner 及其子进程性能的 eBPF 工具。
📊 监控架构总览
┌─────────────────────────────────────────────────────────────────────────┐
│ 进程性能监控完整方案 │
├─────────────────────────────────────────────────────────────────────────┤
│ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ CPU 性能监控(持续) │ │
│ │ │ │
│ │ Grafana Alloy (eBPF) → Pyroscope Server → Web UI (4040) │ │
│ │ - 97 Hz 采样率 │ │
│ │ - 每 15 秒发送数据 │ │
│ │ - 自动发现进程 │ │
│ │ - 支持历史查询 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 进程指标监控(持续) │ │
│ │ │ │
│ │ Alloy Process Exporter → Prometheus → Grafana Dashboard │ │
│ │ - CPU、内存、I/O、FD、线程数 │ │
│ │ - 15 秒采集间隔 │ │
│ │ - 时序数据存储 │ │
│ │ - Dashboard 可视化 (3000) │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ Off-CPU 阻塞监控(定期) │ │
│ │ │ │
│ │ offcputime-bpfcc → SVG 火焰图文件 │ │
│ │ - 每 60 秒生成一次 │ │
│ │ - 显示阻塞堆栈 │ │
│ │ - 识别 I/O、锁、等待等阻塞 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 系统调用监控(持续) │ │
│ │ │ │
│ │ syscount-bpfcc → 统计文件 │ │
│ │ execsnoop-bpfcc → 进程创建日志 │ │
│ │ opensnoop-bpfcc → 文件访问日志 │ │
│ │ - 每 60 秒统计一次 │ │
│ │ - 持续追踪进程和文件访问 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ ↓ │
│ ┌─────────────────────────────────────────────────────────────────┐ │
│ │ 手动诊断工具(按需使用) │ │
│ │ │ │
│ │ diag-tool.sh - 综合诊断工具 │ │
│ │ auto-flamegraph.sh - 自动火焰图生成 │ │
│ └─────────────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────────────┘
目录结构
ebpf-tools/
├── README.md # 本文档
├── alloy-config.alloy # Grafana Alloy 配置(CPU 监控 + 进程指标导出)
├── diag-tool.sh # 手动诊断工具
├── auto-flamegraph.sh # 自动火焰图生成
├── offcpu-monitor.sh # Off-CPU 阻塞监控
└── syscall-monitor.sh # 系统调用监控
🔧 工具详解
1. alloy-config.alloy - Grafana Alloy 配置
用途: 持续 CPU 性能监控 + 进程指标导出
工作原理:
- 使用 eBPF 自动发现
agent_runner及其子进程 - 以 97 Hz 频率采样 CPU 性能数据,发送到 Pyroscope
- 采集进程指标(CPU、内存、I/O、FD、线程数),发送到 Prometheus
- 在 Web UI 中实时查看:Pyroscope (4040) + Grafana (3000)
采集的指标:
| 指标类别 | 指标名称 | 说明 |
|---|---|---|
| CPU | process_cpu_seconds_total |
CPU 时间(累计) |
| 内存 | process_resident_memory_bytes |
常驻内存(RSS) |
| 内存 | process_virtual_memory_bytes |
虚拟内存(VSZ) |
| FD | process_open_fds |
打开的文件描述符 |
| I/O | process_read_bytes_total |
读取字节数 |
| I/O | process_write_bytes_total |
写入字节数 |
| 线程 | process_num_threads |
线程数量 |
| 上下文切换 | process_context_switches_total |
上下文切换次数 |
进程标签:
process_pid: 进程 PIDprocess_name: 进程名称process_exe: 完整执行路径parent_pid: 父进程 PIDproject_id: 项目 IDcontainer_id: 容器 ID
环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
ENABLE_ALLOY |
- | 是否启用(由 ebpf-debug feature 控制) |
PYROSCOPE_URL |
http://pyroscope:4040 | Pyroscope Server 地址 |
PROMETHEUS_URL |
http://prometheus:9090/api/v1/write | Prometheus 写入地址 |
查看数据:
# 1. Pyroscope Web UI (CPU 性能)
open http://localhost:4040
# 2. Grafana Dashboard (进程指标)
open http://localhost:3000
# 登录: admin / admin
# 查找: "Agent Runner 进程监控"
2. offcpu-monitor.sh - Off-CPU 阻塞监控
用途: 定期生成 Off-CPU 阻塞火焰图,分析进程阻塞原因
工作原理:
- 每 60 秒自动运行一次(可配置)
- 对
agent_runner及其所有子进程进行采样 - 使用
offcputime-bpfcc捕获阻塞堆栈 - 生成 SVG 火焰图文件,自动清理旧文件(最多保留 50 个)
环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
ENABLE_OFFCPUTIME |
- | 是否启用(由 ebpf-debug feature 控制) |
OFFCPU_DURATION |
30 | 每次采样时长(秒) |
OFFCPU_INTERVAL |
60 | 生成间隔(秒) |
MAX_OFFCPU_FILES |
50 | 最多保留文件数量 |
输出文件:
/app/container-logs/diag/
├── offcpu-monitor.log # 监控日志
├── offcpu-agent_runner-1-20250111_143025.svg # 主进程阻塞火焰图
└── offcpu-claude-code-acp-123-*.svg # 子进程阻塞火焰图
3. syscall-monitor.sh - 系统调用监控
用途: 监控进程的系统调用活动,包括进程创建、文件访问和系统调用统计
工作原理:
- 每 60 秒统计一次系统调用(可配置)
- 后台持续追踪进程创建 (
execsnoop-bpfcc) - 后台持续追踪文件访问 (
opensnoop-bpfcc) - 定期生成系统调用统计报告
采集的数据:
| 工具 | 数据 | 说明 |
|---|---|---|
syscount-bpfcc |
系统调用统计 | 每个系统调用的次数和耗时 |
execsnoop-bpfcc |
进程创建日志 | 新进程的创建时间和命令行 |
opensnoop-bpfcc |
文件访问日志 | 文件打开/关闭操作 |
环境变量:
| 变量 | 默认值 | 说明 |
|---|---|---|
ENABLE_SYSCALL_MONITOR |
- | 是否启用(由 ebpf-debug feature 控制) |
SAMPLE_DURATION |
30 | 每次采样时长(秒) |
GENERATE_INTERVAL |
60 | 生成间隔(秒) |
输出文件:
/app/container-logs/diag/
├── syscall-monitor.log # 监控日志
├── syscall-count-agent_runner-1-*.txt # 系统调用统计
├── execsnoop-*.log # 进程创建日志
└── opensnoop-*.log # 文件访问日志
日志说明:
- 控制台输出: 每次采样只输出一行汇总日志
- 文件日志: 详细日志写入
syscall-monitor.log
4. diag-tool.sh - 手动诊断工具
手动触发的 eBPF 诊断工具,用于在怀疑有性能问题时主动采集数据。
用法:
diag-tool.sh {offcpu|flame|profile|all} <pid> [duration]
命令:
| 命令 | 说明 |
|---|---|
offcpu <pid> [duration] |
分析 off-cpu 堆栈,默认 30 秒 |
flame <pid> [duration] |
生成火焰图,默认 30 秒 |
profile <pid> [duration] |
CPU 性能分析,默认 30 秒 |
all <pid> |
综合诊断(包含所有分析) |
快捷命令:
e-offcpu- 等同于diag-tool.sh offcpue-flame- 等同于diag-tool.sh flamee-profile- 等同于diag-tool.sh profilee-all- 等同于diag-tool.sh all
5. auto-flamegraph.sh - 自动火焰图生成
持续在后台运行的火焰图生成工具,自动监控 agent_runner 及其所有子进程。
工作原理:
- 自动检测
agent_runner进程 PID - 递归获取所有子进程 PID
- 使用 bpftrace 采样性能数据(默认 30 秒)
- 生成火焰图 SVG 文件
- 每 60 秒重复一次
🎯 使用场景
场景 1: 持续监控 CPU 性能
目标: 在 Web UI 中实时查看 agent_runner 性能数据
步骤:
- 确保容器已启动(Alloy 自动运行)
- 打开 http://localhost:4040 (Pyroscope)
- 选择应用
agent_runner - 按需过滤标签(如
process_name="agent_runner") - 查看火焰图、时序数据、Top 函数
适用问题:
- CPU 使用率异常
- 函数调用热点分析
- 性能回归检测
场景 2: 查看进程指标趋势
目标: 监控内存、I/O、FD 等进程指标的趋势
步骤:
- 打开 http://localhost:3000 (Grafana)
- 登录(admin / admin)
- 查找 "Agent Runner 进程监控" Dashboard
- 选择
project_id、instance、process_name过滤 - 查看各面板数据
可用面板:
- 概览: RSS/VSZ 内存、CPU 使用率、文件描述符
- 内存趋势: RSS 和 VSZ 的时间序列图
- I/O 监控: 读取/写入速率
- 上下文切换: 自愿/非自愿切换速率
- 线程详情: 线程数量、FD 使用率
- 缺页错误: 次要/主要缺页错误速率
场景 3: 分析进程阻塞问题
目标: 找出进程为什么被阻塞(等待 I/O、锁等)
步骤:
- 等待 offcpu-monitor 自动生成火焰图(或手动触发)
- 导出 SVG 文件到本地
- 在浏览器中打开火焰图
- 查找宽的阻塞堆栈
# 导出最新的 Off-CPU 火焰图
docker cp <container>:/app/container-logs/diag/offcpu-*.svg ./
open offcpu-*.svg
适用问题:
new_session超时- 进程响应缓慢
- I/O 阻塞
- 锁竞争
场景 4: 分析系统调用模式
目标: 了解进程的系统调用行为,找出系统调用热点
步骤:
- 查看系统调用统计日志
- 分析哪些系统调用最频繁
- 查看 execsnoop/opensnoop 日志了解进程和文件访问
# 查看系统调用统计
docker exec <container> cat /app/container-logs/diag/syscall-count-*.txt | head -20
# 查看进程创建日志
docker exec <container> tail -f /app/container-logs/diag/execsnoop-*.log
场景 5: 手动诊断已知问题
# 进入容器
docker exec -it <container> bash
# 诊断 agent_runner
e-all $(pgrep agent_runner)
# 导出结果
docker cp <container>:/app/container-logs/diag ./diag-results
📈 火焰图分析
CPU 火焰图(Alloy + Pyroscope)
如何阅读:
- 横轴: CPU 时间占比(越宽表示占用越多)
- 纵轴: 调用堆栈(从上到下是调用关系)
- 颜色: 暖色调表示热点函数
典型问题识别:
| 现象 | 可能原因 |
|---|---|
| 某个函数占据大部分宽度 | CPU 密集型计算 |
| 深层函数很宽 | 递归调用或深层嵌套 |
出现 syscall 大量时间 |
系统调用开销 |
出现 sleep/usleep |
主动休眠或等待 |
Off-CPU 火焰图(offcputime-bpfcc)
如何阅读:
- 横轴: 阻塞时间占比(越宽表示阻塞越久)
- 纵轴: 阻塞时的调用堆栈
- 颜色: 暖色调表示阻塞热点
典型问题识别:
| 现象 | 可能原因 |
|---|---|
schedule() 占据大量时间 |
进程被调度出去(CPU 竞争) |
do_wait()/wait_event() |
等待事件或信号 |
__sock_sendmsg()/__sock_recvmsg() |
网络 I/O 阻塞 |
blk_mq_submit_bio() |
磁盘 I/O 阻塞 |
futex_wait() |
锁等待(互斥锁) |
🔍 故障排查
Grafana Dashboard 显示 "No Data"
# 1. 检查 Prometheus 中是否有数据
curl -s 'http://localhost:9091/api/v1/query?query=process_resident_memory_bytes'
# 2. 检查标签值
curl -s 'http://localhost:9091/api/v1/label/project_id/values'
# 3. 确认 agent_runner 容器正在运行
docker ps | grep agent_runner
变量下拉框为空
# 检查标签值是否存在
curl -s 'http://localhost:9091/api/v1/label/project_id/values'
# 如果没有数据,说明没有 agent_runner 容器在运行
# 启动一个 agent_runner 容器后再检查
Pyroscope Web UI 无数据
# 1. 检查 Pyroscope Server
docker ps | grep pyroscope
docker logs rcoder-pyroscope
# 2. 检查 Alloy 是否发送数据
docker exec <container> grep "collected profiles" /app/container-logs/diag/alloy.log
# 3. 检查网络连接
docker exec <container> curl http://pyroscope:4040
Off-CPU 火焰图未生成
# 1. 检查 offcputime-bpfcc 是否可用
docker exec <container> which offcputime-bpfcc
# 2. 检查监控进程
docker exec <container> ps aux | grep offcpu-monitor
# 3. 查看监控日志
docker exec <container> tail -f /app/container-logs/diag/offcpu-monitor.log
系统调用监控无输出
# 1. 检查 syscount-bpfcc 是否可用
docker exec <container> which syscount-bpfcc
# 2. 检查监控脚本是否运行
docker exec <container> ps aux | grep syscall-monitor
# 3. 查看监控日志
docker exec <container> tail -f /app/container-logs/diag/syscall-monitor.log
⚠️ 安全注意事项
⚠️ eBPF 工具需要容器特权模式运行,仅在受信任的调试环境使用!
生产环境请使用 make docker-build-agent-production 构建无 eBPF 工具的镜像。