大数跨境
0
0

eBPF 性能诊断实战:10 分钟定位 Linux 系统 CPU/IO/网络瓶颈

eBPF 性能诊断实战:10 分钟定位 Linux 系统 CPU/IO/网络瓶颈 lucky出海
2025-10-21
2

eBPF 性能诊断实战:10 分钟定位 Linux 系统 CPU/IO/网络瓶颈

适用场景 & 前置条件

适用场景:生产环境/测试环境下 CPU 飙升、内存泄漏、磁盘 IO 慢、网络丢包/重传等性能问题排查;适合中大规模业务(日 PV 百万级+)。

前置条件

  • • Linux 内核 4.9+(推荐 5.4+);生产环境建议 5.10+ LTS
  • • ROOT 权限或 CAP_BPF + CAP_PERFMON 能力(内核 5.8+)
  • • 2C4G 最低配置;生产环境建议 4C8G+
  • • 网络无限制(需安装软件包)
  • • 基础 Linux 系统调优经验(熟悉 top/iostat/ss 等工具)

环境与版本矩阵

组件
RHEL/CentOS 7/8/9
Ubuntu 20.04/22.04
最小规格
内核版本
4.18+ (EL8), 5.14+ (EL9)
5.4+ (20.04), 5.15+ (22.04)
4.9+ (推荐 5.10+)
BCC 工具
0.24+ (EPEL)
0.24+ (apt)
0.18+ 可用
bpftrace
0.12+ (EPEL)
0.14+ (apt)
0.9.4+ 可用
LLVM/Clang
11+ (编译需要)
11+ (编译需要)
9+ 最低
CPU/内存
2C4G 最低
2C4G 最低
生产推荐 4C8G+
权限
root / CAP_BPF+CAP_PERFMON
root / CAP_BPF+CAP_PERFMON
内核 5.8+ 可细粒度

测试环境:CentOS Stream 9 (内核 5.14.0), Ubuntu 22.04 (内核 5.15.0), BCC 0.28, bpftrace 0.17 | 测试于 2025-10


快速清单 (Checklist)

  1. 1. ✅ 检查内核版本与 eBPF 支持uname -r + /boot/config-* 验证 CONFIG_BPF)
  2. 2. ✅ 安装 BCC/bpftrace 工具链(区分 RHEL/Ubuntu 包管理器)
  3. 3. ✅ 验证工具可用性bpftrace -l 列出可用探针)
  4. 4. ✅ 诊断 CPU 瓶颈(profile 火焰图 + execsnoop 进程启动 + runqlat 调度延迟)
  5. 5. ✅ 诊断内存瓶颈(memleak 泄漏检测 + slabratetop 内核对象分配)
  6. 6. ✅ 诊断磁盘 IO 瓶颈(biolatency 延迟分布 + biotop 进程 IO 排名)
  7. 7. ✅ 诊断网络瓶颈(tcplife 连接生命周期 + tcpretrans 重传 + tcptop 流量排名)
  8. 8. ✅ 综合案例实战(MySQL 慢查询引发系统负载飙升的全链路诊断)
  9. 9. ✅ 配置监控告警(eBPF exporter + Prometheus 规则)
  10. 10. ✅ 制定回滚方案(安全卸载工具 + 内核参数恢复)

实施步骤

Step 1: 内核检查与 eBPF 支持验证

目标:确认当前内核版本与 eBPF 必需配置项已启用。

1.1 检查内核版本

uname -r
# 预期输出示例(CentOS Stream 9): 5.14.0-362.8.1.el9_3.x86_64
# 预期输出示例(Ubuntu 22.04): 5.15.0-91-generic

要求:版本 >= 4.9;建议 5.4+;生产环境推荐 5.10 LTS 或 5.15 LTS。

1.2 验证 eBPF 内核配置

# RHEL/CentOS
grep CONFIG_BPF /boot/config-$(uname -r)

# Ubuntu
grep CONFIG_BPF /boot/config-$(uname -r)

# 必需配置项输出示例:
# CONFIG_BPF=y
# CONFIG_BPF_SYSCALL=y
# CONFIG_BPF_JIT=y
# CONFIG_HAVE_EBPF_JIT=y
# CONFIG_BPF_EVENTS=y

验证要点

  • • CONFIG_BPF_SYSCALL=y:eBPF 系统调用支持(必需)
  • • CONFIG_BPF_JIT=y:JIT 编译加速(强烈推荐)
  • • CONFIG_BPF_EVENTS=y:事件跟踪支持(必需)

1.3 检查 debugfs/tracefs 挂载

mount | grep -E 'debugfs|tracefs'

# 预期输出:
# debugfs on /sys/kernel/debug type debugfs (rw,relatime)
# tracefs on /sys/kernel/tracing type tracefs (rw,relatime)

如未挂载则手动挂载

mount -t debugfs debugfs /sys/kernel/debug
mount -t tracefs tracefs /sys/kernel/tracing

幂等性保障:写入 /etc/fstab 永久生效

echo"debugfs /sys/kernel/debug debugfs defaults 0 0" >> /etc/fstab
echo"tracefs /sys/kernel/tracing tracefs defaults 0 0" >> /etc/fstab

Step 2: 安装 BCC/bpftrace 工具链

2.1 RHEL/CentOS 安装(通过 EPEL)

# CentOS Stream 8/9 或 RHEL 8/9
dnf install -y epel-release
dnf install -y bcc-tools python3-bcc bpftrace

# 验证安装路径
ls /usr/share/bcc/tools/  # BCC 工具集
which bpftrace            # /usr/bin/bpftrace

可选编译安装(需要最新特性时):

dnf install -y cmake make gcc-c++ llvm-devel clang-devel elfutils-libelf-devel
git clone https://github.com/iovisor/bcc.git && cd bcc
mkdir build && cd build
cmake .. -DCMAKE_INSTALL_PREFIX=/usr
make -j$(nproc) && make install

2.2 Ubuntu/Debian 安装

# Ubuntu 20.04/22.04
apt update
apt install -y bpfcc-tools linux-headers-$(uname -r) bpftrace

# 工具路径
ls /usr/sbin/*-bpfcc  # BCC 工具(带 -bpfcc 后缀)
which bpftrace        # /usr/bin/bpftrace

Ubuntu 注意事项:BCC 工具命名带 -bpfcc 后缀(如 execsnoop-bpfcc),建议创建软链接:

cd /usr/local/bin
for tool in /usr/sbin/*-bpfcc; do
ln -sf $tool $(basename$tool -bpfcc);
done

2.3 验证工具可用性

# 列出可用内核探针(kprobe/tracepoint)
bpftrace -l | head -20

# 预期输出示例(部分):
# kprobe:tcp_sendmsg
# kprobe:tcp_recvmsg
# tracepoint:syscalls:sys_enter_read
# tracepoint:sched:sched_switch

# 快速测试 BCC 工具
/usr/share/bcc/tools/execsnoop -h  # RHEL 路径
execsnoop-bpfcc -h                 # Ubuntu 路径

前后对比验证

# 安装前
bpftrace -l | wc -l
# 输出: bash: bpftrace: command not found

# 安装后
bpftrace -l | wc -l
# 输出: 5000+ (具体数量取决于内核版本)

Step 3: CPU 瓶颈诊断

3.1 采样 CPU 火焰图(profile)

场景:定位高 CPU 占用的函数调用链。

# 采样 60 秒,频率 99Hz(避免与常见定时器共振)
/usr/share/bcc/tools/profile -adf 99 60 > profile.txt

# 关键参数:
# -a : 采样所有 CPU
# -d : 显示进程/线程 ID
# -f : 显示完整调用栈(含用户态+内核态)
# 99 : 采样频率 Hz
# 60 : 持续时间秒

输出示例(简化):

PID    COMM             FUNC
2345   mysqld           [k] __lock_acquire
                        [k] mutex_lock
                        [u] pthread_mutex_lock
                        [u] my_hash_search
                        [u] open_table  (12345 samples, 23%)

分析要点

  • • [k]:内核态函数,[u]:用户态函数
  • • 百分比高的调用链即为热点
  • • 配合 FlameGraph 工具生成 SVG 火焰图
# 生成火焰图(需安装 FlameGraph)
git clone https://github.com/brendangregg/FlameGraph
./FlameGraph/flamegraph.pl profile.txt > cpu-flamegraph.svg

3.2 跟踪进程启动(execsnoop)

场景:排查频繁 fork/exec 导致 CPU 抖动。

# 实时监控所有新进程启动
/usr/share/bcc/tools/execsnoop

# 预期输出(示例):
# PCOMM            PID    PPID   RET ARGS
# sh               12345  1234   0   /bin/sh -c /usr/local/bin/check.sh
# python3          12346  12345  0   /usr/bin/python3 /opt/app/monitor.py

关键字段解释

  • • PCOMM:父进程名称
  • • PID/PPID:进程 ID 与父进程 ID
  • • RET:exec 系统调用返回值(0 成功)
  • • ARGS:完整命令行参数

故障案例:如发现某脚本每秒启动数十次 → 检查 crontab/systemd timer 配置错误。

3.3 测量调度延迟(runqlat)

场景:CPU 利用率不高但响应慢,可能是调度队列等待时间长。

# 统计 10 秒内调度延迟分布(微秒级直方图)
/usr/share/bcc/tools/runqlat 10 1

# 输出示例:
#      usecs               : count     distribution
#          0 -> 1          : 1234     |*********                       |
#          2 -> 3          : 5678     |****************************************|
#          4 -> 7          : 2345     |*****************                |
#          8 -> 15         : 890      |******                           |
#         16 -> 31         : 234      |**                               |
#         32 -> 63         : 67       |                                 |
#         64 -> 127        : 12       |                                 |

分析要点

  • • 延迟中位数(P50)应 < 10µs;P99 应 < 100µs
  • • 若大量任务延迟 > 1ms → 检查 CPU 核数/超线程/中断绑定
  • • 配合 mpstat -P ALL 1 验证各核负载是否均衡

Step 4: 内存瓶颈诊断

4.1 检测内存泄漏(memleak)

场景:应用程序内存持续增长且不释放。

# 跟踪 PID 12345 的内存分配/释放,每 5 秒统计一次
/usr/share/bcc/tools/memleak -p 12345 5

# 输出示例:
# 8192 bytes in 64 allocations from stack
#     malloc+0x28 [libc.so.6]
#     _Znwm+0x1c [libstdc++.so.6]
#     app::BufferPool::allocate+0x45 [myapp]
#     app::handleRequest+0x123 [myapp]

关键参数

  • • -p PID:指定进程(不指定则跟踪整个系统)
  • • -t:显示线程 ID
  • • -a:显示每次分配详情(数据量大,慎用)

验证前后

# 观察前
ps aux | awk 'NR==1 || /myapp/ {print $6}'
# 输出: 204800 (RSS KB)

# 运行 memleak 5 分钟后再次观察
# 输出: 307200 (RSS KB, 增长 100MB)

# memleak 输出显示某函数未释放 → 修复代码后重启应用
# 修复后观察: 205000 (RSS KB, 稳定)

4.2 内核内存分配热点(slabratetop)

场景:内核 slab 内存增长快,排查内核对象泄漏。

# 实时显示 slab 分配速率(每秒刷新)
/usr/share/bcc/tools/slabratetop 1

# 输出示例:
# CACHE                     ALLOCS      BYTES
# kmalloc-512               123456      63234048
# inode_cache               45678       29393920
# dentry                    34567       8863744

分析要点

  • • ALLOCS 持续增长无回落 → 可能泄漏
  • • 对比 slabtop 静态视图确认总量
  • • 重点关注 kmalloc-*(通用分配)和 dentry/inode_cache(文件系统)

Step 5: 磁盘 IO 瓶颈诊断

5.1 IO 延迟分布(biolatency)

场景:磁盘 IO 慢,定位是设备层面还是应用层面。

# 统计 10 秒内块 IO 延迟(毫秒级直方图)
/usr/share/bcc/tools/biolatency -m 10 1

# 输出示例(-m 表示毫秒单位):
#      msecs               : count     distribution
#          0 -> 1          : 12345    |****************************************|
#          2 -> 3          : 3456     |***********                             |
#          4 -> 7          : 890      |***                                     |
#          8 -> 15         : 234      |*                                       |
#         16 -> 31         : 67       |                                        |
#         32 -> 63         : 12       |                                        |

关键指标

  • • SSD 应 < 5ms (P99);HDD 应 < 20ms (P99)
  • • 若大量 IO > 100ms → 检查磁盘健康度(smartctl)或队列深度

前后对比验证

# 优化前(RAID 5 机械盘)
# P99 延迟: 64-127ms

# 优化后(换 SSD + 调整 IO 调度器为 none)
echo none > /sys/block/nvme0n1/queue/scheduler
# P99 延迟: 2-3ms

5.2 进程 IO 排名(biotop)

场景:定位哪个进程产生大量 IO。

# 每 5 秒刷新一次,显示 Top 10 进程
/usr/share/bcc/tools/biotop 5

# 输出示例:
# PID    COMM             D MAJ MIN  DISK       I/O  Kbytes  AVGms
# 12345  mysqld           R 259 0    nvme0n1    8912 356480  2.3
# 23456  rsync            W 8   0    sda        4567 912340  18.7

关键字段

  • • D:方向(R 读/W 写)
  • • I/O:操作次数
  • • Kbytes:总数据量
  • • AVGms:平均延迟

故障案例:发现某日志进程每秒写入 100MB → 调整日志级别或异步刷盘。

5.3 IO 大小分布(bitesize)

场景:分析 IO 请求大小是否合理(小 IO 频繁 vs 大 IO 稀疏)。

/usr/share/bcc/tools/bitesize
# 输出(简化):
# Process Name = mysqld
# Kbytes              : count     distribution
#     0 -> 1          : 0        |                                        |
#     2 -> 3          : 0        |                                        |
#     4 -> 7          : 1234     |***********                             |
#     8 -> 15         : 3456     |*********************************       |
#    16 -> 31         : 4567     |****************************************|

优化建议

  • • 大量 4KB 小 IO → 考虑启用 Readahead 或增大应用 buffer
  • • 全是 16KB IO → 检查 InnoDB 页大小或文件系统块大小配置

Step 6: 网络瓶颈诊断

6.1 TCP 连接生命周期(tcplife)

场景:排查短连接过多或连接异常关闭。

/usr/share/bcc/tools/tcplife

# 输出示例:
# PID   COMM       LADDR           LPORT RADDR           RPORT TX_KB RX_KB MS
# 1234  nginx      192.168.1.10    80    192.168.1.100   54321 12    456   1234
# 2345  curl       192.168.1.10    54322 8.8.8.8         443   0.5   2.3   89

关键字段

  • • TX_KB/RX_KB:发送/接收流量
  • • MS:连接持续时间(毫秒)
  • • MS < 100 且大量出现 → 短连接风暴,建议连接池/长连接

验证前后

# 优化前(PHP-FPM 短连接 MySQL)
# MS 平均 50ms,每秒 500 条新连接

# 优化后(启用持久连接)
# MS 平均 30000ms(30秒),每秒 20 条新连接

6.2 TCP 重传监控(tcpretrans)

场景:网络质量差或拥塞导致丢包重传。

/usr/share/bcc/tools/tcpretrans

# 输出示例:
# TIME     PID    IP LADDR:LPORT          T> RADDR:RPORT          STATE
# 12:34:56 1234   4  192.168.1.10:80      R> 192.168.1.100:54321  ESTABLISHED
# 12:34:58 1234   4  192.168.1.10:80      R> 192.168.1.100:54321  ESTABLISHED

关键标识

  • • T> 后面的 R 表示重传
  • • 高频出现 → 检查网络链路(mtr/ethtool -S 查看丢包)、拥塞窗口、MTU

配合验证

# 查看网卡错误统计
ethtool -S eth0 | grep -E 'tx_errors|rx_errors|retrans'

# 查看 TCP 重传计数器
netstat -s | grep -i retrans
# 优化前: 12345 segments retransmitted
# 优化后: 123 segments retransmitted (降低 100 倍)

6.3 TCP 流量排名(tcptop)

场景:定位哪些连接/进程占用带宽。

/usr/share/bcc/tools/tcptop 5

# 输出示例(每 5 秒刷新):
# PID    COMM         LADDR           LPORT RADDR           RPORT RX_KB  TX_KB
# 12345  nginx        192.168.1.10    80    192.168.1.100   54321 12340  4567
# 23456  python3      192.168.1.10    8080  10.0.0.5        9000  890    23450

分析要点

  • • 单连接占用 > 网卡带宽 50% → 考虑 QoS 限流
  • • 进程 TX_KB 远大于 RX_KB → 上传型服务(备份/CDN 回源)

Step 7: 综合案例 - MySQL 慢查询引发系统负载飙升

故障现象

  • • 系统 Load Average 从 2 飙升至 50+
  • • MySQL 响应时间 P99 从 10ms 增至 5000ms
  • • CPU iowait 从 5% 升至 40%

诊断流程(5 步定位根因)

7.1 确认 CPU 瓶颈来源

# 采样火焰图
/usr/share/bcc/tools/profile -p $(pidof mysqld) -f 30 > mysql-profile.txt

# 发现热点: InnoDB 行锁等待(row_lock_wait)占比 60%

7.2 检查磁盘 IO 是否饱和

/usr/share/bcc/tools/biotop 5

# 输出显示 mysqld 每秒读取 50000 IOPS,延迟 P99 = 120ms
# 磁盘: SATA SSD,理论 IOPS 上限 80000(接近饱和)

7.3 定位慢查询 SQL

# 使用 MySQL 慢查询日志(非 eBPF,配合使用)
tail -f /var/log/mysql/slow.log

# 发现: SELECT * FROM orders WHERE status='pending' (全表扫描 500 万行)

7.4 跟踪锁等待调用链

# 自定义 bpftrace 脚本跟踪 InnoDB mutex
bpftrace -e '
kprobe:mutex_lock /comm == "mysqld"/ {
  @start[tid] = nsecs;
}
kretprobe:mutex_lock /comm == "mysqld" && @start[tid]/ {
  $lat = nsecs - @start[tid];
  if ($lat > 10000000) {  // > 10ms
    printf("TID %d lock latency: %d ms\n", tid, $lat/1000000);
  }
  delete(@start[tid]);
}
'


# 输出: 大量线程锁等待 > 100ms

7.5 验证索引优化效果

# 前: 无索引,全表扫描
EXPLAIN SELECT * FROM orders WHERE status='pending'\G
# rows: 5000000, Extra: Using where

# 添加索引
ALTER TABLE orders ADD INDEX idx_status (status);

# 后: 索引扫描
# rows: 12340, Extra: Using index condition

# 再次观察 biolatency
/usr/share/bcc/tools/biolatency -m 10 1
# P99 延迟降至 8ms(优化前 120ms)

效果对比

指标
优化前
优化后
Load Average
50+
2.5
MySQL P99 RT
5000ms
15ms
CPU iowait
40%
5%
磁盘 IOPS
50000
1200

Step 8: 数据导出与可视化(Prometheus + Grafana)

8.1 安装 eBPF Exporter

# 下载二进制(示例版本 v2.3.0)
wget https://github.com/cloudflare/ebpf_exporter/releases/download/v2.3.0/ebpf_exporter-2.3.0.linux-amd64.tar.gz
tar xf ebpf_exporter-2.3.0.linux-amd64.tar.gz
cp ebpf_exporter /usr/local/bin/

# 创建配置文件 /etc/ebpf_exporter/config.yaml
mkdir -p /etc/ebpf_exporter
cat > /etc/ebpf_exporter/config.yaml <<'EOF'
programs:
  - name: biolatency
    metrics:
      histograms:
        - name: bio_latency_seconds
help: Block I/O latency histogram
          table: dist
          bucket_type: exp2
          bucket_multiplier: 0.000001  # 转换为秒
          labels:
            - name: device
              size: 32
              decoders:
                - name: string
    kprobes:
      blk_account_io_done: trace_block_io_done
    code: |
      // 简化示例,完整代码见官方仓库
      BPF_HISTOGRAM(dist, u64);
EOF

# 启动服务(监听 9435 端口)
ebpf_exporter --config.file=/etc/ebpf_exporter/config.yaml &

8.2 Prometheus 抓取配置

# prometheus.yml 新增 scrape_configs
scrape_configs:
-job_name:'ebpf'
static_configs:
-targets: ['localhost:9435']
labels:
instance:'prod-server-01'

8.3 Grafana 面板示例查询

# 磁盘 IO P99 延迟(毫秒)
histogram_quantile(0.99,
  sum(rate(bio_latency_seconds_bucket[5m])) by (le, device)
) * 1000

# TCP 重传率(每秒)
rate(tcpretrans_total[5m])

# 内存泄漏趋势(堆内存未释放 MB)
sum(memleak_bytes{pid="12345"}) / 1024 / 1024

Grafana 面板建议

  • • Panel 1: 磁盘 IO 延迟热力图(Heatmap)
  • • Panel 2: TCP 重传/连接数时序图(Graph)
  • • Panel 3: CPU 火焰图集成(需插件 grafana-piechart-panel

监控与告警

Prometheus 告警规则示例

groups:
-name:ebpf_alerts
interval:30s
rules:
# 磁盘 IO P99 延迟 > 100ms
-alert:HighDiskLatency
expr:|
          histogram_quantile(0.99,
            sum(rate(bio_latency_seconds_bucket[5m])) by (le, device)
          ) > 0.1
for:2m
labels:
severity:warning
annotations:
summary:"磁盘 {{ $labels.device }} 延迟过高"
description:"P99 延迟 {{ $value | humanizeDuration }}"

# TCP 重传率 > 1%
-alert:HighTCPRetrans
expr:|
          rate(tcpretrans_total[5m]) / rate(tcp_segments_sent[5m]) > 0.01
for:5m
labels:
severity:critical
annotations:
summary:"TCP 重传率异常"

# 内存泄漏检测(进程 RSS 持续增长 > 10% /小时)
-alert:MemoryLeak
expr:|
          (process_resident_memory_bytes - process_resident_memory_bytes offset 1h)
          / process_resident_memory_bytes offset 1h > 0.1
for:30m
labels:
severity:warning

原生命令监控(无 Prometheus)

# 每分钟记录磁盘 IO 延迟到日志
whiletruedo
  /usr/share/bcc/tools/biolatency -m 10 1 | grep -A20 'msecs' >> /var/log/biolatency.log
sleep 60
done &

# 定时检查 TCP 重传
watch -n 10 'netstat -s | grep retrans'

性能与容量

eBPF 工具开销基准测试

测试环境:4C8G 虚拟机,CentOS Stream 9,无业务负载

工具
CPU 开销
内存开销
适用采样频率
生产建议
profile
1-3%
20MB
49-99 Hz
≤ 99Hz
biolatency
0.5-1%
10MB
持续
可常驻
tcplife
0.2-0.5%
5MB
持续
可常驻
memleak
5-10%
50MB
按需
仅故障时
execsnoop
0.1-0.3%
2MB
持续
可常驻

容量规划建议

  • • 单机同时运行 ≤ 5 个 eBPF 工具
  • • profile/memleak 仅在故障排查时启用(开销大)
  • • 采样频率折中选择(99Hz vs 999Hz,性能 vs 精度)
  • • 日志轮转:eBPF 输出重定向时需配置 logrotate

生产环境限流策略

# 限制 profile 仅采样 10 秒(避免长时间占用)
timeout 10s /usr/share/bcc/tools/profile -f 99 > profile.txt

# 限制 memleak 仅跟踪特定内存分配大小(过滤噪音)
/usr/share/bcc/tools/memleak -p 12345 -o 1048576  # 仅跟踪 ≥1MB 分配

# cgroup 限制 eBPF 工具 CPU 使用(内核 5.x+)
cgcreate -g cpu:/ebpf_tools
cgset -r cpu.cfs_quota_us=50000 ebpf_tools  # 限制 50% 单核
cgexec -g cpu:ebpf_tools /usr/share/bcc/tools/profile -f 99 60

安全与合规

权限最小化(内核 5.8+ 推荐)

# 传统方式: 需要 root(风险大)
sudo /usr/share/bcc/tools/execsnoop

# 细粒度权限(推荐): 仅授予 CAP_BPF + CAP_PERFMON
setcap cap_bpf,cap_perfmon=ep /usr/share/bcc/tools/execsnoop
# 普通用户即可运行
/usr/share/bcc/tools/execsnoop

验证权限

getcap /usr/share/bcc/tools/execsnoop
# 输出: cap_bpf,cap_perfmon=ep

审计日志记录

# 记录所有 eBPF 程序加载事件(需 auditd)
auditctl -a always,exit -F arch=b64 -S bpf -k ebpf_load

# 查看审计日志
ausearch -k ebpf_load
# 输出示例:
# type=SYSCALL msg=audit(1697123456.789:12345): arch=c000003e syscall=321 success=yes pid=23456 comm="bpftrace"

内核兼容性矩阵

特性
内核版本要求
说明
基础 eBPF
4.4+
kprobe/uprobe 支持
BPF maps
4.9+
用户态/内核态数据交换
bpf() syscall
4.1+
程序加载系统调用
BTF (CO-RE)
5.2+
一次编译到处运行
CAP_BPF
5.8+
细粒度权限控制
bpf_trace_printk
4.1+
调试输出
bpf_get_stackid
4.6+
调用栈跟踪

兼容性测试命令

# 检查 BTF 支持(CO-RE 依赖)
ls /sys/kernel/btf/vmlinux
# 存在则支持;不存在则需编译时启用 CONFIG_DEBUG_INFO_BTF

# 检查 bpf() syscall
strace -e bpf bpftrace -e 'BEGIN { exit(); }' 2>&1 | grep 'bpf('
# 输出包含 'bpf(' 则支持

常见故障与排错

症状
诊断命令
可能根因
快速修复
永久修复
bpftrace -l
 无输出
`dmesg
grep -i bpf`
内核未启用 CONFIG_BPF
更换内核或重新编译
Failed to attach kprobe ls /sys/kernel/debug/tracing
debugfs 未挂载
mount -t debugfs debugfs /sys/kernel/debug
写入 /etc/fstab
Cannot allocate memory ulimit -l
locked memory 限制过小
ulimit -l unlimited
 (临时)
修改 /etc/security/limits.conf
工具输出乱码/截断
`dmesg
tail`
内核日志缓冲区满
dmesg -c
 清空缓冲区
CO-RE: failed to find BTF ls /sys/kernel/btf/vmlinux
内核未生成 BTF 信息
使用非 CO-RE 版本工具
内核编译启用 CONFIG_DEBUG_INFO_BTF
execsnoop 无输出
strace -e bpf execsnoop 2>&1 | grep EPERM
权限不足
sudo execsnoop
 或授予 CAP_BPF
使用细粒度权限 setcap
profile 火焰图全是 [unknown]
perf probe -l
符号表缺失
安装 debuginfo 包
编译时保留符号表 -g
biotop 显示磁盘名错误
lsblk
设备号变更或虚拟设备
手动映射 MAJ:MIN 到设备名
使用 udev 规则固定设备名

关键错误码速查

# EPERM (Operation not permitted)
# 原因: 权限不足
# 解决: sudo 或 setcap cap_bpf,cap_perfmon=ep

# ENOSPC (No space left on device)
# 原因: BPF map 空间耗尽
# 解决: 调整 map 大小或增大 RLIMIT_MEMLOCK

# EINVAL (Invalid argument)
# 原因: 内核版本不支持某 BPF 特性
# 解决: 升级内核或使用兼容版本工具

变更与回滚剧本

维护窗口建议

  • • 测试环境:无限制,可随时安装/卸载
  • • 生产环境:建议在业务低峰期(凌晨 2-6 点)首次部署;常驻工具(execsnoop/biolatency)可在线启用

灰度策略

# 阶段 1: 单台测试服务器验证 7 天
# 阶段 2: 10% 生产节点部署(监控 CPU/内存开销)
# 阶段 3: 全量部署(保留 1-2 台回滚对照组)

健康检查脚本

#!/bin/bash
# ebpf_health_check.sh

# 检查工具是否正常响应
timeout 5s bpftrace -e 'BEGIN { exit(); }' || exit 1

# 检查内核日志无 BPF 错误
dmesg | tail -100 | grep -i 'bpf.*error' && exit 1

# 检查 CPU 开销 < 5%
ebpf_cpu=$(ps aux | grep -E 'bpftrace|bcc' | awk '{sum+=$3} END {print sum}')
(( $(echo "$ebpf_cpu > 5" | bc -l) )) && exit 1

echo"eBPF tools healthy"
exit 0

回滚条件与命令

触发条件

  • • CPU 开销 > 10% 持续 5 分钟
  • • 内核日志出现 BPF verifier error
  • • 业务监控指标(P99 延迟/错误率)突增 > 20%

立即回滚

# 停止所有 eBPF 工具进程
pkill -9 bpftrace
pkill -9 python3  # BCC 工具是 Python 脚本
killall profile execsnoop biolatency

# 卸载 eBPF exporter
systemctl stop ebpf_exporter
systemctl disable ebpf_exporter

# 验证无残留 BPF 程序
bpftool prog show | wc -l
# 输出应为 0 或仅剩系统默认程序

数据/配置备份

# 备份配置
tar czf /backup/ebpf-config-$(date +%F).tar.gz \
  /etc/ebpf_exporter/ \
  /usr/local/bin/ebpf_exporter \
  /etc/systemd/system/ebpf_exporter.service

# 恢复配置
tar xzf /backup/ebpf-config-2025-10-20.tar.gz -C /

最佳实践

  1. 1. 采样频率权衡:profile 使用 49/99 Hz(避免与 100 Hz 定时器共振);生产环境避免 > 999 Hz
  2. 2. 工具组合原则:CPU 瓶颈用 profile + runqlat;IO 瓶颈用 biolatency + biotop;内存用 memleak + slabratetop
  3. 3. 符号表必备:安装 debuginfo 包(debuginfo-install RHEL / apt install *-dbgsym Ubuntu)
  4. 4. CO-RE 优先:内核 5.2+ 使用 libbpf-tools(一次编译到处运行),避免每台机器装内核头文件
  5. 5. 权限最小化:生产环境使用 CAP_BPF + CAP_PERFMON 替代 root(内核 5.8+)
  6. 6. 日志轮转:eBPF 输出重定向时配置 logrotate(避免磁盘占满)
  7. 7. 限流保护:memleak/profile 使用 timeout 限制运行时间;cgroup 限制 CPU 使用
  8. 8. 监控工具本身:通过 ps aux | grep bpf 定期检查工具 CPU/内存占用
  9. 9. 内核版本统一:生产环境统一使用 LTS 内核(5.10/5.15),避免工具兼容性问题
  10. 10. 回滚预案:保留 1-2 台未部署 eBPF 的对照服务器;准备一键停止脚本

附录

A. BCC 工具速查表(Top 20)

工具
用途
典型命令
profile
CPU 火焰图
profile -f 99 60
execsnoop
进程启动跟踪
execsnoop
runqlat
调度延迟
runqlat 10 1
memleak
内存泄漏
memleak -p PID 5
slabratetop
内核内存分配
slabratetop 1
biolatency
磁盘 IO 延迟
biolatency -m 10 1
biotop
进程 IO 排名
biotop 5
bitesize
IO 大小分布
bitesize
tcplife
TCP 连接生命周期
tcplife
tcpretrans
TCP 重传
tcpretrans
tcptop
TCP 流量排名
tcptop 5
opensnoop
文件打开跟踪
opensnoop
ext4slower
ext4 慢操作(> 10ms)
ext4slower 10
funccount
函数调用计数
funccount 'vfs_*'
trace
自定义内核/用户态函数跟踪
trace 'do_sys_open "%s", arg1'
argdist
参数/返回值分布
argdist -H 'r::vfs_read()'
cpudist
CPU 运行时间分布
cpudist 10 1
hardirqs
硬中断延迟
hardirqs 10 1
offcputime
非 CPU 时间(阻塞/等待)
offcputime -f 30
stackcount
调用栈统计
stackcount -p PID tcp_sendmsg

B. bpftrace 一行脚本集合

# 跟踪所有 TCP 连接建立
bpftrace -e 'kprobe:tcp_connect { printf("%s -> %s\n", comm, ntop(2, ((struct sock *)arg0)->__sk_common.skc_daddr)); }'

# 统计系统调用耗时 Top 10
bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @start[tid] = nsecs; } tracepoint:raw_syscalls:sys_exit /@start[tid]/ { @[comm] = hist(nsecs - @start[tid]); delete(@start[tid]); }'

# 跟踪文件删除操作
bpftrace -e 'kprobe:vfs_unlink { printf("%s deleted %s\n", comm, str(((struct dentry *)arg1)->d_name.name)); }'

# 统计内存页分配来源
bpftrace -e 'kprobe:__alloc_pages_nodemask { @[kstack] = count(); }'

# 监控 MySQL 查询(需编译时保留符号)
bpftrace -e 'usdt:/usr/sbin/mysqld:mysql:query__start { printf("%s\n", str(arg0)); }'

C. Prometheus eBPF Exporter 完整配置示例

# /etc/ebpf_exporter/config.yaml
programs:
-name:bio_latency
metrics:
histograms:
-name:bio_latency_seconds
help:BlockI/Olatencyhistogram
table:dist
bucket_type:exp2
bucket_min:0
bucket_max:100
bucket_multiplier:0.000001
labels:
-name:device
size:32
decoders:
-name:string
-name:operation
size:8
decoders:
-name:uint
-name:bucket
size:8
decoders:
-name:uint
kprobes:
blk_account_io_done:trace_done
code:|
      #include <linux/blkdev.h>
      BPF_HISTOGRAM(dist, struct hist_key, 512);
      struct hist_key {
        char device[32];
        u64 slot;
      };
      int trace_done(struct pt_regs *ctx, struct request *req) {
        struct hist_key key = {};
        bpf_probe_read_kernel_str(&key.device, sizeof(key.device), req->rq_disk->disk_name);
        u64 delta = bpf_ktime_get_ns() - req->start_time_ns;
        key.slot = bpf_log2l(delta / 1000);
        dist.increment(key);
        return 0;
      }

-name:tcp_retrans
metrics:
counters:
-name:tcp_retrans_total
help:TCPretransmitcount
table:counts
labels:
-name:saddr
size:4
decoders:
-name:inet_ip
-name:daddr
size:4
decoders:
-name:inet_ip
kprobes:
tcp_retransmit_skb:trace_retrans
code:|
      BPF_HASH(counts, u64);
      int trace_retrans(struct pt_regs *ctx, struct sock *sk) {
        u64 key = sk->__sk_common.skc_daddr;
        counts.increment(key);
        return 0;
      }

D. Nginx/MySQL 典型配置与 eBPF 集成

Nginx 访问日志关联 eBPF

# nginx.conf
log_format ebpf_trace '$remote_addr - $remote_user [$time_local] "$request" '
'$status$body_bytes_sent "$http_referer" '
'"$http_user_agent" rt=$request_time pid=$pid';
access_log /var/log/nginx/access.log ebpf_trace;

配合 bpftrace 跟踪高延迟请求:

bpftrace -e '
tracepoint:syscalls:sys_exit_write /comm == "nginx"/ {
  $lat = (nsecs - @start[tid]) / 1000000;
  if ($lat > 100) {  // > 100ms
    printf("PID %d slow write: %d ms\n", pid, $lat);
  }
}
'

MySQL 慢查询与 biolatency 联动

-- my.cnf
[mysqld]
slow_query_log =1
slow_query_log_file =/var/log/mysql/slow.log
long_query_time =0.1  # 100ms

实时关联分析:

# 终端 1: 监控磁盘 IO
/usr/share/bcc/tools/biolatency -m 1

# 终端 2: 解析慢查询日志
tail -f /var/log/mysql/slow.log | grep 'Query_time'

# 关联发现: 慢查询峰值时刻,biolatency P99 从 5ms 升至 80ms

文档版本:v1.0 | 测试环境:RHEL 9 (5.14), Ubuntu 22.04 (5.15), BCC 0.28, bpftrace 0.17 | 更新日期:2025-10

文末福利


网络监控是保障网络系统和数据安全的重要手段,能够帮助运维人员及时发现并应对各种问题,及时发现并解决,从而确保网络的顺畅运行。

谢谢一路支持,给大家分享6款开源免费的网络监控工具,并准备了对应的资料文档,建议运维工程师收藏(文末一键领取)。

图片
备注:【监控合集】

图片

100%免费领取


一、zabbix

图片
图片

二、Prometheus


图片

内容较多,6款常用网络监控工具(zabbix、Prometheus、Cacti、Grafana、OpenNMS、Nagios不再一一介绍, 需要的朋友扫码备注【监控合集】,即可100%免费领取。

图片

 以上所有资料获取请扫码

备注:【监控合集】

图片

100%免费领取

(后台不再回复,扫码一键领取)


【声明】内容源于网络
0
0
lucky出海
跨境分享圈 | 每天分享跨境干货
内容 44188
粉丝 1
lucky出海 跨境分享圈 | 每天分享跨境干货
总阅读235.0k
粉丝1
内容44.2k