抓包不如“开天眼”:用 eBPF 搭一条实时流量取样与可视化流水线
抓包不如“开天眼”:用 eBPF 搭一条实时流量取样与可视化流水线
作者:Echo_Wish
很多做运维的兄弟,排查问题第一反应是什么?
tcpdump 走起。
然后抓一堆包,导到 Wireshark,CPU 飙升,磁盘爆满,线上同事盯着你:“哥,别搞了行不行?”
说句实在话,传统抓包是“事后诸葛亮”。
我们真正需要的是——
实时、低开销、可持续运行的流量观测能力。
这几年让我彻底改观的技术,就是:
eBPF
它让我们不用改内核,不用重启机器,就能在内核里插“探针”。
不是抓全量,而是聪明地取样。
今天我带你搭一条完整的实时流量取样 + 可视化流水线:
eBPF 程序 → 用户态收集 → 流式聚合 → 可视化展示
我们一步步拆。
一、为什么不是 tcpdump,而是 eBPF?
传统抓包:
- 全量抓
- 高 I/O
- 高 CPU
- 不适合长期运行
而 eBPF:
- 在内核层过滤
- 只上传关键数据
- 取样可控
- 性能开销极低
你可以把它理解成:
在内核里装了一个“聪明的流量筛子”。
二、核心思路:内核只做取样,不做重活
我们先写一个简单的 eBPF 程序,挂载在 tc ingress 点,做流量采样。
使用 Python 的 bcc 框架(底层也是基于 eBPF):
from bcc import BPF
program = """
#include <uapi/linux/ptrace.h>
#include <linux/skbuff.h>
BPF_HASH(packet_cnt, u32, u64);
int count_packets(struct __sk_buff *skb) {
u32 key = 0;
// 简单采样:1/100 概率
if (bpf_get_prandom_u32() % 100 != 0) {
return TC_ACT_OK;
}
u64 *val, zero = 0;
val = packet_cnt.lookup_or_init(&key, &zero);
(*val)++;
return TC_ACT_OK;
}
"""
b = BPF(text=program)
fn = b.load_func("count_packets", BPF.SCHED_CLS)
注意这里的逻辑:
bpf_get_prandom_u32() % 100
这就是采样控制点。
不是抓 100%,
而是 1%。
这意味着什么?
如果你的机器 10Gbps 流量,
你只处理 100Mbps 的元数据。
这就是性能差距。
三、别在内核里做复杂分析
很多人第一次写 eBPF,会忍不住想:
- 统计 RTT
- 解析 HTTP
- 计算延迟分布
我劝一句:别。
内核只负责采样与计数。
真正的分析放在用户态。
我们可以在用户态读取 map:
import time
while True:
time.sleep(1)
for k, v in b["packet_cnt"].items():
print("sampled packets:", v.value)
这一步,你就已经实现了:
- 实时采样
- 每秒输出统计
- 几乎无性能影响
四、升级:按源IP聚合
我们改造一下,让它按源 IP 统计。
BPF_HASH(ip_cnt, u32, u64);
int count_packets(struct __sk_buff *skb) {
if (bpf_get_prandom_u32() % 100 != 0) {
return TC_ACT_OK;
}
u32 src_ip = skb->remote_ip4;
u64 *val, zero = 0;
val = ip_cnt.lookup_or_init(&src_ip, &zero);
(*val)++;
return TC_ACT_OK;
}
然后在用户态做聚合:
for k, v in b["ip_cnt"].items():
print("IP:", k.value, "count:", v.value)
这时候你已经拥有:
实时 Top IP 监控能力。
比起传统流量分析工具,
它的优势是:
- 无需 sidecar
- 不侵入应用
- 内核级可见性
五、把数据推入可视化流水线
观测不是为了打印日志。
我们要画图。
推荐两种方案:
- 推送到 Prometheus
- 或发给 Apache Kafka
例如,推到 Prometheus:
from prometheus_client import Gauge, start_http_server
g = Gauge('sampled_packets', 'Sampled packets per second')
start_http_server(8000)
while True:
total = 0
for k, v in b["packet_cnt"].items():
total += v.value
g.set(total)
time.sleep(1)
然后用:
Grafana
画出实时流量趋势图。
这就是完整流水线:
eBPF → Python exporter → Prometheus → Grafana
六、真实生产场景怎么玩?
场景一:防止流量突增
采样统计 QPS,如果瞬间翻倍:
- 自动触发告警
- 自动扩容
- 或启用限流策略
场景二:检测异常 IP
通过 Top N 分析:
- 发现 DDoS 早期征兆
- 识别异常扫描行为
场景三:流量画像
- 内部服务调用关系
- TCP 重传率
- 延迟分布
eBPF 能挂的点非常多:
- kprobe
- tracepoint
- tc
- XDP
真正牛的团队,是把它当成“内核观测操作系统”。
七、性能对比的真实感受
我做过一次测试:
- tcpdump 全量抓:CPU 40%
- eBPF 1% 采样:CPU 3%
差距不是一点点。
而且 eBPF 程序运行在内核安全沙箱里,不会崩机器。
这就是它的恐怖之处。
八、别走偏:eBPF 不是银弹
我要泼点冷水。
eBPF 很强,但:
- 调试难度高
- 版本依赖多
- 内核差异坑不少
如果只是偶尔排查问题,
你不一定非要上它。
但如果你在做:
- 高并发系统
- 金融级稳定性要求
- 边缘节点监控
那它几乎是必备能力。
九、一个更成熟的架构
如果你想进阶,可以参考:
Cilium
Pixie
这些系统本质上都是:
eBPF + 流式处理 + 可视化平台
它们已经帮你封装好了复杂逻辑。
最后的思考
运维的本质,不是救火。
是让系统“自我可见”。
以前我们是:
出事了再抓包。
现在我们应该是:
实时看到趋势,提前干预。
eBPF 给我们的不是工具。
- 点赞
- 收藏
- 关注作者
评论(0)