尧图网络 高端网站定制 · 原创设计
免费咨询热线
400-888-6620
免费获取方案
eBPF 零侵入可观测性:无需改代码也能拿网络内核数据
eBPF 零侵入可观测性无需改代码也能拿网络内核数据一、你想知道 Pod 之间的真实延迟但不想在每个服务里加埋点代码传统可观测性三板斧都有侵入性日志需要log.Info()格式要统一Metrics需要引入 Prometheus client定义指标Tracing需要在请求链路里透传 trace-id每个中间件都要加改代码意味着改了几十个服务、发版、灰度、验证。如果一个服务是第三方镜像或者是别人团队维护的你根本改不了。eBPF 的思路我不改你的代码我在内核里挂个钩子你的网络包、系统调用、CPU 采样我全能看到。对应用进程透明。二、eBPF 可观测性的内核级架构eBPF 钩子分类钩子类型挂载点能抓到什么典型应用kprobe/kretprobe内核函数入口/出口系统调用参数、返回值文件 I/O 监控tracepoint内核静态追踪点网络、调度、内存事件TCP 重传监控uprobe/uretprobe用户态函数Go/Python 函数调用慢查询定位XDP网卡驱动层最原始的包数据DDoS 防护TC (Traffic Control)内核协议栈进出流量负载均衡socket filtersocket 层套接字数据连接级监控perf eventCPU PMUCPU 周期、缓存命中性能分析火焰图三、实际 eBPF 程序示例追踪 HTTP 请求延迟基于内核 kprobe// http_trace.bpf.c #include linux/bpf.h #include bpf/bpf_helpers.h #include bpf/bpf_tracing.h #include bpf/bpf_endian.h // 事件结构传给用户态的数据 struct http_event { __u64 timestamp_ns; // 请求开始时间 __u64 duration_ns; // 请求耗时 __u32 pid; // 进程 ID __u32 tid; // 线程 ID __u32 status_code; // HTTP 状态码 __u32 data_len; // 响应体长度 char method[8]; // GET/POST char path[128]; // 请求路径 char comm[16]; // 进程名 }; // BPF Map内核态→用户态环形缓冲区 struct { __uint(type, BPF_MAP_TYPE_RINGBUF); __uint(max_entries, 256 * 1024); } events SEC(.maps); // BPF Map记录请求开始时间keygoroutine_id struct { __uint(type, BPF_MAP_TYPE_HASH); __uint(max_entries, 10240); __type(key, __u64); // goroutine ptr __type(value, __u64); // start timestamp } start_time SEC(.maps); // kprobe挂载在 tcp_sendmsgGo 写 HTTP 响应最终调用这里 SEC(kprobe/tcp_sendmsg) int trace_tcp_sendmsg(struct pt_regs *ctx) { __u64 pid_tgid bpf_get_current_pid_tgid(); __u32 pid pid_tgid 32; __u64 goid get_goroutine_id(ctx); // 从 Go runtime 获取 // 只追踪目标进程 if (pid ! TARGET_PID) return 0; __u64 ts bpf_ktime_get_ns(); bpf_map_update_elem(start_time, goid, ts, BPF_ANY); return 0; } // kretprobetcp_sendmsg 返回时计算延迟 SEC(kretprobe/tcp_sendmsg) int trace_ret_tcp_sendmsg(struct pt_regs *ctx) { __u64 goid get_goroutine_id(ctx); __u64 *start_ts bpf_map_lookup_elem(start_time, goid); if (!start_ts) return 0; __u64 end_ts bpf_ktime_get_ns(); __u64 duration end_ts - *start_ts; bpf_map_delete_elem(start_time, goid); // 写入环形缓冲区给用户态读取 struct http_event *event; event bpf_ringbuf_reserve(events, sizeof(*event), 0); if (!event) return 0; event-timestamp_ns *start_ts; event-duration_ns duration; event-pid bpf_get_current_pid_tgid() 32; bpf_get_current_comm(event-comm, sizeof(event-comm)); bpf_ringbuf_submit(event, 0); return 0; } char LICENSE[] SEC(license) GPL;用户态 Go 程序读取 eBPF 事件并导出指标// main.go - 使用 cilium/ebpf 库 package main import ( bytes encoding/binary log net/http github.com/cilium/ebpf github.com/cilium/ebpf/link github.com/cilium/ebpf/ringbuf github.com/cilium/ebpf/rlimit github.com/prometheus/client_golang/prometheus github.com/prometheus/client_golang/prometheus/promhttp ) // HTTPEvent 对应 eBPF 中的 struct http_event type HTTPEvent struct { TimestampNs uint64 DurationNs uint64 PID uint32 TID uint32 StatusCode uint32 DataLen uint32 Method [8]byte Path [128]byte Comm [16]byte } var ( httpRequestDuration prometheus.NewHistogramVec( prometheus.HistogramOpts{ Name: ebpf_http_request_duration_seconds, Buckets: []float64{.005, .01, .025, .05, .1, .25, .5, 1, 2.5, 5}, }, []string{method, path, comm}, ) ) func main() { prometheus.MustRegister(httpRequestDuration) // 移除内存限制加载 eBPF 需要 if err : rlimit.RemoveMemlock(); err ! nil { log.Fatal(err) } // 加载编译好的 eBPF 字节码 objs : bpfObjects{} if err : loadBpfObjects(objs, nil); err ! nil { log.Fatal(loading eBPF objects:, err) } defer objs.Close() // 挂载 kprobe kp, err : link.Kprobe(tcp_sendmsg, objs.TraceTcpSendmsg, nil) if err ! nil { log.Fatal(attaching kprobe:, err) } defer kp.Close() krp, err : link.Kretprobe(tcp_sendmsg, objs.TraceRetTcpSendmsg, nil) if err ! nil { log.Fatal(attaching kretprobe:, err) } defer krp.Close() // 从 ring buffer 读取事件 rd, err : ringbuf.NewReader(objs.Events) if err ! nil { log.Fatal(creating ringbuf reader:, err) } defer rd.Close() log.Println(eBPF HTTP tracer started) // 事件处理循环 go func() { var event HTTPEvent for { record, err : rd.Read() if err ! nil { log.Printf(reading from ringbuf: %v, err) continue } if err : binary.Read( bytes.NewBuffer(record.RawSample), binary.LittleEndian, event, ); err ! nil { continue } method : cstring(event.Method[:]) path : cstring(event.Path[:]) comm : cstring(event.Comm[:]) duration : float64(event.DurationNs) / 1e9 httpRequestDuration.WithLabelValues( method, path, comm, ).Observe(duration) } }() // 暴露 Prometheus 指标 http.Handle(/metrics, promhttp.Handler()) log.Fatal(http.ListenAndServe(:2112, nil)) } func cstring(b []byte) string { if i : bytes.IndexByte(b, 0); i ! -1 { return string(b[:i]) } return string(b) }四、边界分析与架构权衡边界问题方案内核版本要求eBPF 需要 Linux 4.x检查内核版本降级使用 perf_eventGo 函数参数获取Go ABI 不标准使用 uretprobe 寄存器分析eBPF 程序大小限制最大 1M 指令5.2拆分多个 eBPF 程序HTTPS 流量无法看到加密内容在应用层用 uprobe 抓取容器网络命名空间eBPF 挂载需要 PID namespace在宿主机上挂载 cgroup/skb 级别Map 大小限制Ring buffer 满了丢数据加大 buffer采样降级Verifier 拒绝复杂逻辑可能通不过简化循环使用 bounded loops权衡eBPF vs 传统 APMeBPF 优势零代码改动最大的卖点覆盖所有应用包括第三方性能开销极低 1% CPU可以看到内核级数据TCP 重传、网络延迟等eBPF 劣势调试困难eBPF 程序在内核里崩了很难排查缺乏业务上下文只知道系统调用不知道业务含义语言绑定不完整不同语言的函数调用约定不同HTTPS 流量盲区需要应用层配合解密推荐组合eBPF 做网络/系统层监控 OpenTelemetry 做应用层 Tracing。一个看底层一个看业务互为补充。五、总结eBPF 零侵入可观测性不是银弹但它在不需要改代码这个维度上确实碾压传统方案。适合的场景已有服务不想动代码用 eBPF 快速建立可观测性第三方/开源组件你控制不了它的代码网络/存储问题排查需要内核级数据的场景安全审计记录所有系统调用和行为常用的 eBPF 可观测性工具Cilium Hubble网络、PixieK8s 全栈、Falco安全、bpftrace调试。一句话总结如果你还只在应用层加埋点你已经漏掉了 50% 的可用信息。
RELATED

相关推荐

深入理解riscv-sodor:Chisel硬件设计语言入门教程

深入理解riscv-sodor:Chisel硬件设计语言入门教程

深入理解riscv-sodor:Chisel硬件设计语言入门教程 【免费下载链接】riscv-sodor educational microarchitectures for risc-v isa 项目地址: https://gitcode.com/gh_mirrors/ri/riscv-sodor riscv-sodor是一个基于RISC-V指令集架构的教育性微架构项目&#…

📅 2026/9/6 20:44:39
Moon高性能优化技巧:内存管理、协程池与零拷贝传输

Moon高性能优化技巧:内存管理、协程池与零拷贝传输

Moon高性能优化技巧:内存管理、协程池与零拷贝传输 【免费下载链接】moon A lightweight game server framework implemented with Actor Model 项目地址: https://gitcode.com/gh_mirrors/moon1/moon Moon是基于Actor模型的轻量级游戏服务器框架&#xff0c…

📅 2026/10/7 10:13:47
如何将LFM2.5-Embedding-350M-bf16集成到现有AI应用中:3个实用案例

如何将LFM2.5-Embedding-350M-bf16集成到现有AI应用中:3个实用案例

如何将LFM2.5-Embedding-350M-bf16集成到现有AI应用中:3个实用案例 【免费下载链接】LFM2.5-Embedding-350M-bf16 项目地址: https://ai.gitcode.com/hf_mirrors/mlx-community/LFM2.5-Embedding-350M-bf16 想要在现有AI应用中快速集成强大的多语言文本嵌入…

📅 2026/9/28 21:53:23
MORE NEWS

更多资讯

📰

蓝屏代码查询实战:STOP码、转储日志与驱动排障

简介:这份面向Windows桌面用户的蓝屏故障速查文档,聚焦系统崩溃时STOP停机码与故障检查信息的含义解读。内容从蓝屏画面的三段式信息讲起,说明停机码如何识别错误类型、括号内参数为何主要供驱动与系统开发者参考,并延伸至重启、排…

📰

银河麒麟源码编译Subversion 1.8.14与svnserve部署排障

简介:这份资源面向在银河麒麟(国产 Linux)系统上需要搭建版本控制服务的管理员与开发人员,围绕「从源码编译安装 SVN 环境」这一实际问题,给出一条可落地的完整安装路线。包中共 1 个 docx 文档,约 202KB&a…

📰

U9 ERP V2.5手册拆解:SOA架构下的实施价值与避坑要点

简介:用友U9 ERP V2.5手册是一份面向企业信息化管理者、ERP实施顾问以及财务、供应链、制造业务人员的官方发版说明文档。手册阐述其“实时企业、全球商务”的核心理念,以及多组织协同、业务灵活性、全球化管理的客户价值。资源包共1个docx文档&#xff…

📰

专升本计算机基础题库高频考点与易错题解析

简介:这份面向江西专升本考生的计算机基础试题题库,聚焦专升本计算机基础科目的客观题训练,覆盖计算机科学基本概念、冯诺依曼存储程序控制原理、电子计算机发展简史与四代划分、计算机体系结构与主要组成、应用领域、硬件软件系统及日常操作…

📰

MATLAB谷歌地图环境搭建:版本依赖对齐与避坑指南

简介:这份资源面向需要在MATLAB环境中调用谷歌地图的开发者与科研人员,聚焦地理数据可视化、路径规划与地图交互等实用场景,适合具备MATLAB基础、希望将地图能力嵌入分析流程的中级用户。压缩包共8个文件、约15KB,以m脚本与fig图形…

📰

Matlab双目立体视觉工程实践:从标定到点云重建完整链路

简介:本资源是面向计算机视觉初学者与Matlab实践者的双目立体视觉完整实现方案,聚焦三维重建核心流程,解决从图像采集到深度图生成的技术闭环问题。压缩包共10个文件,含4个核心Matlab脚本(实现相机标定、特征匹配、本质…

TODAY

今日更新

THIS WEEK

本周精选

THIS MONTH

本月热门

读完文章,想聊聊您的网站?

告诉我们您的行业与需求,资深顾问一对一梳理方案与报价,全程免费。

📞 💬