eBPF 服务网格能取代 sidecar 吗?聊聊实际对比
先说结论:短期内不会。过去半年我在一个日请求量上千万的金融项目里同时跑过两套服务网格:一套继续用 Istio + sidecar,另一套在非生产环境切换到了 Cilium 的 eBPF mesh。我的预期中 eBPF 会全面胜出,但实际排障和功能细节让我改变了判断。这篇不是 CNCF 的调研报告,只把真正的差距和踩过的坑说清楚。
原理上它们根本不是一类东西
传统 sidecar 模式的本质是把代理放进业务 Pod 的 network namespace。Istio 默认通过 istio-init 注入 iptables 规则,把进出容器的流量透明劫持到 Envoy 的 15006/15001 端口。也就是说,每一个业务实例都会多出一个共享同生命周期、共享 CPU 的 Envoy 进程。而 Cilium 的做法完全不同,它把 datapath 放进了内核 BPF hook 点,通过 socket-level 的 BPF 程序直接分发流量,不需要在容器里设置一堆 NAT 规则。这里最直观的差异是:sidecar 模式每新建一个 Pod 都要多付一份 Envoy 内存,基线大约 30-50MB,并发一上来就轻松突破 200MB。eBPF 模式下节点上只有一个 cilium-agent 和按需启用的节点级 Envoy,每个连接在 BPF map 里的记录开销通常在 1-2KB 量级。不过别高兴得太早,这只说明内存小,并不代表你不需要 Envoy,当 Cilium 要处理 L7 策略时,它仍然会在节点级拉起 Envoy,只是不再每个 Pod 一个而已。
性能差距集中在长尾,而不是平均延迟
很多人喜欢拿 p99 延迟说事。我用 wrk 和 ghz 做过一轮链路对比,服务网格只做全链路 mTLS 加路由转发,HTTP 1.1、1KB payload。纯 Pod-to-Pod 基线 p99 大概 1.05ms,Istio + sidecar 在同一批机器上是 1.38ms,Cilium eBPF 是 1.21ms。也就是说 sidecar 比基线慢 31%,eBPF 只慢 15%,提升是客观的,但绝对值只有 0.17ms。如果你的业务 QPS 是万级,这点延迟基本可忽略;但如果是网关、广告竞价这类单服务百万 QPS,0.17ms 乘以每跳的 NodePort DNAT 就会被放大,此时 eBPF 的价值才能体现。真正让我意外的是 CPU。连接保持性的长连接场景,eBPF 模式比 sidecar 省掉差不多 20% 的节点 CPU,因为少了用户态代理的 context switch。但对于短连接高频突发,eBPF 的优势会被 BPF map 的 lock contention 拉回去,并不像宣传中那么神。
最被低估的是排障复杂度,不是资源
我见过社区里有很多“迁移后省了多少机器”的总结,但几乎没人会告诉你:当 Cilium 的流量路径出错时,你要怎么找问题?sidecar 里的 Envoy access log 会明确告诉你 route 叫什么、upstream cluster 是哪一个、直接返回 5xx 还是连接失败。Istio 的故障注入、流量镜像、VirtualService 改写这些操作都是面向普通业务研发的。而 eBPF 的问题就像是内核网络栈的一个黑盒,你带着 cilium monitor、bpftool map dump -j 去找,却不一定能把它映射到业务概念。我在测试环境遇到过一次部分 Pod 一直无法建立与数据库的长连接,最终居然是 conntrack GC 把连接杀了,当时配套的 Grafana 面板根本没有表示 GC 触发的图。这种内核级调试经验不是每个运维都具备的。
什么情况下我会真正推荐 eBPF service mesh
我的建议很具体。如果你们团队满足以下三个前提,可以认真考虑 Cilium mesh:第一,Kubernetes 集群内核版本能长期保持 5.15 以上,并且能接受特权容器运行 agent,普遍的企业安全审计可能会阻挡这个;第二,核心服务属于长连接或高吞吐 RPC,资源密度已经到了靠增加 pod 副本数缓解的地步;第三,你们至少有一个人能看懂 bpftool prog list 的输出。否则没必要为了 30% 的 p99 延迟去给运维埋雷。Istio sidecar 模式除了内存基线高,剩下都相对透明。如果你现在问我下一套系统怎么设计,我会说:小团队继续 sidecar,核心链路用 eBPF 做 Service Mesh 的边缘转发,外层 API Gateway 保持 Istio,这反而可能比“all in eBPF”更稳。