第277篇:Cilium eBPF 数据面与网络性能
关键词
Cilium、eBPF、XDP、TC hook、eBPF Map、身份标识、套接字级路由、Hubble、高性能网络
一、eBPF 技术基础
1.1 eBPF 是什么
eBPF(extended Berkeley Packet Filter)是一种在内核中安全运行沙箱程序的技术:
eBPF 架构:
| 用户态 Cilium Agent bpftool | ── 加载 eBPF 程序 ──┐ |
|---|---|
| ▼ | |
| 内核态 ┌──────────────┐ └──────────────┘ ┌──────────────┐ └──────────────┘ ┌─── eBPF Map ──────────────────────┐ └───────────────────────────────────┘ ┌─── eBPF Hook 点 ──────────────────┐ | eBPF Verifier JIT Compiler Pod 标识映射 策略规则 连接跟踪 XDP(网卡驱动层) TC(网络栈) cgroup(套接字) tracepoint |
| --- | --- |
eBPF 的关键特性: 1. 安全——Verifier 检查所有程序确保不会崩溃内核 2. 高性能——JIT 编译为本地代码,无解释执行 3. 动态加载——不重启内核或重启系统 4. 可编程——按需加载卸载
1.2 eBPF Hook 点
Cilium 使用的 eBPF Hook 点:
| 网卡硬件 XDP (eXpress Data Path) ┌────────────────────────────────┐ └────────────────────────────────┘ TC (Traffic Control) ingress/egress ┌────────────────────────────────┐ └────────────────────────────────┘ cgroup/sock ┌────────────────────────────────┐ | 在网卡驱动层,SKB 分配之前 处理后直接决定: - XDP_PASS:送到内核协议栈 - XDP_DROP:直接丢弃(最快) - XDP_TX:从原端口发回 在内核协议栈中,SKB 分配后 可以修改数据包内容 可以做路由和转发决策 在套接字层(connect/bind/send) 实现套接字级路由和策略 | |
|---|---|---|
性能对比(PPS): XDP:20M+ pps(不分配 SKB,最轻量) TC:15M pps(分配 SKB,但无 iptables 遍历) iptables:5M pps(规则链遍历)
二、Cilium eBPF 数据面
2.1 数据包路径
Cilium eBPF 数据面——Pod 到 Pod 的数据包路径:
同节点 Pod 通信:
PodA ──► vethA ──► TC ingress(eth0入口)
│
├─ 查找 eBPF Map:目标 identity
├─ 策略检查:允许?
├─ 查找转发信息:目标 MAC
│
└─ TC egress(vethB出口)
└─► PodB
无 iptables!2 次 eBPF 程序完成全部处理
跨节点 Pod 通信:
PodA ──► vethA ──► TC ingress
│
├─ 查找 eBPF Map
├─ 策略检查
├─ 封装 VXLAN/Geneve(或直接路由)
│
└─ XDP / TC(物理网卡出口)
└─► 物理网络 ──► 目标节点
封装开销仅一次
不需要经过 iptables PREROUTING/FORWARD/POSTROUTING 链
2.2 身份标识(Identity)
Cilium 使用基于标签的身份标识(Security Identity)替代 IP 地址做策略:
传统 iptables 策略:
-A FORWARD -s 10.1.1.0/24 -d 10.1.2.0/24 -j ACCEPT
问题:Pod IP 变化时需要更新规则
规则随 Pod 数量线性增长
Cilium Identity:
每个 Pod 根据标签分配一个身份标识(24-bit ID)
PodA:app=web, env=prod → Identity: 1001
PodB:app=db, env=prod → Identity: 1002
eBPF Map 中的策略:
Identity 1001 → 可以访问 1002:3306
Identity 1002 → 可以接受来自 1001 的 3306
数据包处理:
从 veth 进入后,提取 Pod 的 Identity
查 eBPF Map:srcID=1001, dstID=1002, port=3306 → ALLOW
优势:
Pod IP 变化不影响策略
策略不随 Pod 数量增长
支持 L7 策略(HTTP 方法、路径等)
2.3 eBPF Map
Cilium 使用 eBPF Map 存储网络状态(替代内核 conntrack 和路由表):
核心 eBPF Maps:
| Map 名称 | 存储内容 |
|---|---|
| cilium_lxc cilium_ct4 cilium_ct6 cilium_policy cilium_ipcache cilium_tunnel_map cilium_lb_services cilium_lb_backends | 本地 Pod 的 MAC/IP/Identity 连接跟踪表(IPv4) 连接跟踪表(IPv6) 策略规则(Identity → 规则) IP 到 Identity 映射 隧道端点映射 Service 负载均衡表 后端 Pod 列表 |
eBPF Map 的优势: 1. 内核空间——查找无需切换到用户态 2. 哈希表——O(1) 查找 3. 原子操作——无锁并发访问 4. 可观测——bpftool map dump 可读
查看 eBPF Maps: bpftool map show bpftool map dump id 123
三、Cilium 网络性能
3.1 性能提升的关键
Cilium eBPF 提升网络性能的六个关键点:
1. 绕过 iptables
传统:数据包遍历 5 个 hook × N 条规则
Cilium:2 次 eBPF 程序查找(入口 + 出口)
2. 绕过 conntrack
传统:内核 conntrack 维护连接状态(大量锁竞争)
Cilium:eBPF Map 存储(无锁或 Per-CPU)
3. 套接字级负载均衡
Cilium 的 kube-proxy 替代:
在 connect() 系统调用时直接选择后端
无需 DNAT → 避免 conntrack
减少 50% 延迟
4. XDP 早期丢包
不需要的包在网卡驱动层丢弃
不分配 SKB → 零内存开销
5. Per-CPU 数据结构
eBPF Map 使用 Per-CPU 布局
无锁竞争 → 多核线性扩展
6. 编译为本地代码
JIT 编译 → 与内核代码相同性能
无解释开销
3.2 性能测试数据
Cilium eBPF vs iptables 性能对比(Intel Xeon 100G NIC):
测试 1:Pod-to-Pod 吞吐(TCP 双向)
| 包大小 | iptables | Cilium | 提升 |
|---|---|---|---|
| 64B 256B 1024B 9000B | 5 Gbps 18 Gbps 45 Gbps 85 Gbps | 18 Gbps 40 Gbps 70 Gbps 94 Gbps | 260% 122% 55% 10% |
小包场景提升最明显(iptables 的规则遍历开销占比大)
测试 2:每秒新建连接数
iptables:30K conntrack Cilium eBPF:200K+ 提升:6x
原因:conntrack 锁竞争被 eBPF Per-CPU Map 消除
测试 3:Service(Cluster IP)延迟
iptables kube-proxy: 数据包经过 PREROUTING → DNAT → FORWARD → POSTROUTING 延迟:~60μs
Cilium eBPF 套接字级: connect() 系统调用时直接确定后端 延迟:~10μs
提升:80%
3.3 Hubble 可观测性
Hubble——Cilium 的网络可观测性组件:
核心能力:
1. 服务地图(Service Map)
自动发现服务间依赖关系
可视化微服务通信拓扑
2. 流量监控
实时每秒/每分钟流量指标
按 Pod/Service/Namespace 分类
3. 延迟分析
每跳延迟分布(P50/P90/P99)
识别慢路径
4. 策略审计
哪些策略被触发
哪些流量被拒绝(Drop 原因)
# 使用 Hubble CLI
hubble observe --from-pod default/web-xxx --to-pod default/db-yyy
hubble observe --verdict DROPPED # 查看被拒绝的流量
# 实时监控
hubble status
hubble metrics --match "http_requests_total" --match "drop_total"
四、Cilium Service 替代
4.1 eBPF kube-proxy 替代
Cilium 可以完全替代 kube-proxy(性能更好):
传统 kube-proxy iptables 模式:
客户端 Pod → 10.96.0.10:80
┌─ PREROUTING: DNAT 10.96.0.10 → 10.1.1.2
├─ FORWARD: 检查
├─ POSTROUTING: SNAT(如果需要)
└─ 发送到 10.1.1.2:8080
延迟:~60μs
Cilium eBPF 套接字级:
客户端 Pod 调用 connect("10.96.0.10", 80)
┌─ cgroup/sock eBPF 程序
├─ 查 eBPF Map:Service 10.96.0.10 → 后端列表
├─ 选择后端:10.1.1.2:8080
├─ 修改 sock 结构体:目标改为 10.1.1.2:8080
└─ 后续数据包直接发到 10.1.1.2:8080
延迟:~10μs(减少 80%)
无需 DNAT → 无需 conntrack
五、总结
| 知识点 | 核心要点 |
|---|---|
| eBPF | 内核沙箱,安全运行用户加载的程序 |
| XDP | 网卡驱动层 hook,早期丢包/转发,PPS 最高 |
| TC hook | 网络栈中 hook,可修改数据包 |
| 身份标识 | 基于标签的 Security Identity,替代 IP 做策略 |
| eBPF Map | 内核哈希表存储状态,O(1) 查找,无锁 |
| 性能提升 | 绕 iptables、绕 conntrack、套接字级 LB |
| Hubble | 可观测性,服务地图、延迟分析、策略审计 |
| Service 替代 | eBPF 套接字级 LB,延迟降低 80% |
六、思考
- eBPF 程序在内核中是如何安全运行的?Verifier 检查哪些方面?
- XDP 和 TC hook 的区别是什么?什么场景应该用 XDP,什么场景用 TC?
- Cilium 的 Security Identity 相比 IP 地址做策略有什么优势?Identity 是如何分配的?
- Cilium 如何实现 kube-proxy 替代?套接字级负载均衡相比 iptables DNAT 为什么性能更好?
- 如果发现某个 Pod 的网络延迟异常高(P99 > 100ms),如何使用 Hubble 定位问题?
下篇预告:第278篇《K8s Ingress 与 Service Mesh 网络》——从 Ingress Controller 到 Service Mesh,K8s 流量入口管理的发展与 Istio/Linkerd 的 sidecar 代理原理。