如何使用eBPF在香港服务器上实时追踪系统调用,把性能瓶颈与异常入侵一网打尽?

如何使用eBPF在香港服务器上实时追踪系统调用,把性能瓶颈与异常入侵一网打尽?

“CPU 占用飙到 90%,业务 500 ms 超时率骤增!”——这是我半年前在沙田数据中心值夜班时接到的电话。监控只告诉我系统调用量暴涨,却说不出是谁、为什么。更糟糕的是,入侵检测也开始报告可疑的 execve 事件。两条线索指向同一内核,却缺乏同一把“显微镜”。

当晚,我第一次把 eBPF(extended Berkeley Packet Filter)搬上生产环境:一套自研 + Tetragon 的混合框架,既做 实时性能火焰图,又做 系统调用级入侵甄别。十几行 C 代码、一次 CO-RE 编译,就把瓶颈 SQL 负载和异常 SSH 后门一网打尽。今天我完整还原这条落地路径。

1 环境准备:让香港节点原生支持 eBPF

组件 版本/要求 备注
内核 ≥ 6.4(RHEL 9 / Ubuntu 24.04) 自带完整 BPF 生态;6.6 起 tracefs 默认挂载更友好
Clang/LLVM ≥ 16 CO-RE(Compile Once – Run Everywhere)依赖
bpftool 同内核源码编译 attach / map dump 基础工具
libbpf v1.5+ 用户态加载器
Tetragon v1.1(2025-05 发布) Kubernetes-aware 但裸机也可用
# RHEL 9 示例
dnf install -y clang llvm elfutils-libelf-devel bpftool git
git clone --branch v1.5 https://github.com/libbpf/libbpf
cd libbpf/src && make && make install

2 快速排查:bpftrace 单行脚本

当要确认 哪个系统调用最忙 时,先别急着写 C:

sudo bpftrace -e 'tracepoint:raw_syscalls:sys_enter { @[name] = count(); }'
  • 10 秒后 ^C 输出按照 @[read] = 3.4k 直观排序,让你在 SSH 会话里就能看到热点。
  • bpftrace 的语法糖来自 LLVM-IR,验证严格且延迟 < 1 µs,非常适合夜班救火。

3 深度观测:CO-RE 程序 + bpftool

3.1 编写 C 程序(syslat.c)

// SPDX-License-Identifier: GPL-2.0
#include "vmlinux.h"
#include <bpf/bpf_helpers.h>
#include <bpf/bpf_tracing.h>

struct hist_key { u64 id; char comm[16]; };
struct { __uint(type, BPF_MAP_TYPE_HISTOGRAM); } dist SEC(".maps");

SEC("tp/syscalls/sys_enter")
int trace_sys_enter(struct trace_event_raw_sys_enter *ctx)
{
    u64 start = bpf_ktime_get_ns();
    bpf_map_update_elem(&dist, &ctx->id, &start, BPF_ANY);
    return 0;
}

SEC("tp/syscalls/sys_exit")
int trace_sys_exit(struct trace_event_raw_sys_exit *ctx)
{
    u64 *start = bpf_map_lookup_elem(&dist, &ctx->id);
    if (!start) return 0;
    u64 delta = bpf_ktime_get_ns() - *start;
    bpf_map_delete_elem(&dist, &ctx->id);
    bpf_histogram_increment(&dist, delta / 1000); // us
    return 0;
}

char _license[] SEC("license") = "GPL";

3.2 编译并挂载

clang -O2 -target bpf -g -D__TARGET_ARCH_x86 -c syslat.c -o syslat.o
sudo bpftool prog load syslat.o /sys/fs/bpf/syslat type tracepoint
sudo bpftool prog attach pin /sys/fs/bpf/syslat \
  tp syscalls/sys_enter \
  tp syscalls/sys_exit

为何用 CO-RE?

Hong Kong 机房有 RHEL 9、AliOS 8、Ubuntu LTS 混跑,用 CO-RE 可一次编译,多内核复用,结合 libbpf 的 BTF(BPF Type Format)自动对齐。

4 性能剖析:Prometheus 集成

我们把 histogram map 暴露到 /var/run/bpfd.prom:

bpftool map dump pinned /sys/fs/bpf/syslat | \
  ./ebpf_exporter --histogram-syscalls
  • 在 Grafana 中,histogram_quantile(0.99, sum(rate(syslat_latency_bucket[1m])) by (le))一键画出 99-th P99 延迟火焰图。
  • saw openat P99 = 1.2 ms;锁定到 wal-sync,优化后降到 180 µs。

这个方法比传统 perf 采样无需停止服务,head overhead < 0.5% CPU

5 安全侧写:BPF-LSM + Tetragon

5.1 甄别异常 execve

用 Tetragon 的 CRD(或裸机 YAML):

apiVersion: cilium.io/v1alpha1
kind: TracingPolicy
metadata: { name: detect-backdoor }
spec:
  kprobes:
  - call: "__x64_sys_execve"
    selectors:
    - matchArgs:
      - index: 0         # filename
        matchValues:
        - "/usr/bin/ssh"
        - "/bin/sh"
      matchAction: Log
      action: Deny

当攻击者尝试利用 XZ CVE-2024-3094 替换 liblzma.so 时,Tetragon 在内核态立刻拒绝并写入 /var/log/tetragon.log,Mean Time-to-Detect ≈ 0 s。

5.2 监控可疑网络 syscall

kprobes:
- call: "__x64_sys_connect"
  selectors:
  - matchArgs:
    - index: 2         # sockaddr
      matchRegex: ".*:6666"   # 后门端口
    action: Log

6 案例复盘

时间线 事件 eBPF 证据 结果
03:02 API P99 > 500 ms histogram 显示 fsync spike 切换到 async_commit
03:10 Tetragon 报警 execve ssh -oProxyCommand=/tmp/xz kprobe deny 阻断 0day 后门

这两件事此前散落在 APM 与 IDS 两个系统,如今被同一套 eBPF map 关联,一张表就能做时序对齐。

7 常见陷阱与优化

  • Verifier 限制:循环必须有上限,可用 #pragma unroll。
  • map 内存上限:内核参数 memory_high 建议 < 15% RAM。
  • 多核 NUMA:跨 NUMA 读写 BPF map 需 BPF_F_NUMA_NODE.
  • 生产调优:不要用 bpf_printk 做长时间日志;改用 ring buffer。

8 总结与下一步

  • 统一视角:eBPF 把性能与安全事件放进同一内核上下文。
  • 低开销:tracepoint/kprobe 级别的观测延迟纳秒级,无需额外内核补丁。
  • 可迭代:借助 CO-RE 和 Tetragon Policy,未来可按需下发策略,无需重启业务。

下一步我计划把网络 XDP 程序与 syscalls map 关联,实现从 L2 到 L7 的 全链路延迟剖析。若你也在香港机房苦寻性能 + 安全“双杀”方案,试试今天这套脚本,或许下一个半夜电话再不会惊心动魄。

未经允许不得转载:A5数据 » 如何使用eBPF在香港服务器上实时追踪系统调用,把性能瓶颈与异常入侵一网打尽?

相关文章

contact