4. Cilium 数据面核心:eBPF Map 与内存消耗
Cilium 数据面的核心运转依赖于内核中的 eBPF Map 结构。这些 Map 是 eBPF 程序与用户空间、以及 eBPF 程序之间共享数据和状态的关键桥梁。在生产环境中,Map 的大小直接决定了系统的内存开销、并发处理能力以及故障恢复速度。本章深入剖析三种核心 Map:Policy Map、CT Map 和 Endpoint Map,并量化其大小与内存消耗的关系。
4.1 三大核心 eBPF Map 概述
在 Cilium 的数据路径中,每个网络包的处理都会经过多个 eBPF 程序的串联。这些程序通过特定的 Map 来查找策略、跟踪连接状态和定位端点信息。下表总结了这三种 Map 的核心差异:
| Map 名称 | Key 类型 | Value 类型 | 主要用途 | 默认最大条目 |
|---|---|---|---|---|
| Policy Map | Identity (uint32) | Policy Entry (包含 L4/L7 策略) | 基于安全标识的访问控制决策 | 16384 |
| CT Map | Tuple (5元组) | CT Entry (连接跟踪状态) | 跟踪 TCP/UDP/ICMP 连接状态 | 262144 (每CPU) |
| Endpoint Map | IP 地址 (uint32) | Endpoint Info (MAC, VNI, 标识等) | 将目标 IP 解析为本机端点信息 | 65535 |
4.2 Policy Map:安全策略的查找表
Policy Map 是一个 BPF_MAP_TYPE_HASH,用于存储从 安全标识 (Security Identity) 到 策略条目 (Policy Entry) 的映射。当 Cilium 收到一个数据包时,它会提取源端和目标端的 Security Identity,然后查询 Policy Map 来决定是否允许通信。
- Key 结构: 由源 Identity 和目标 Identity 组合而成,通常是一个 64 位整数。
- Value 结构: 包含允许的 L4 端口列表、L7 协议规则以及是否允许转发等标志位。
- 内存消耗公式:
总内存 ≈ (Key_Size + Value_Size + 哈希表开销) × 条目数。每个条目的哈希表开销约为 16-32 字节。
// 伪代码:Policy Map 条目结构
struct policy_key {
__u32 src_identity;
__u32 dst_identity;
};
struct policy_entry {
__u64 packets;
__u64 bytes;
__u8 deny:1;
__u8 l4_ports[16]; // 简化表示
// ... 其他策略字段
};
cilium bpf policy list 的输出,确保条目数不超过默认最大值的 70%,以避免哈希冲突导致的性能下降。
4.3 CT Map:连接跟踪的状态引擎
CT Map 是 Cilium 数据面中 内存消耗最大 的 Map。它是一个 BPF_MAP_TYPE_LRU_HASH(最近最少使用哈希表),用于跟踪所有经过节点的网络连接状态。每个连接在 CT Map 中占用一个条目,直到连接超时或被主动清理。
- Key 结构: 网络 5 元组(源 IP、目标 IP、源端口、目标端口、协议)。
- Value 结构: 包含连接状态(ESTABLISHED, TIME_WAIT 等)、序列号、标志位、以及反向路径的指针。
- 内存消耗公式:
总内存 ≈ (Key_Size + Value_Size + LRU 开销) × 条目数 × CPU 核心数。CT Map 是 per-CPU 的,因此内存消耗会随 CPU 核心数线性增长。
| 连接类型 | 典型条目大小 | 超时时间 | 内存影响 |
|---|---|---|---|
| TCP ESTABLISHED | ~168 字节 | 6 小时 (默认) | 高,长连接会长期占用内存 |
| TCP TIME_WAIT | ~168 字节 | 60 秒 | 中等,短时间大量连接会冲击内存 |
| UDP | ~88 字节 | 30 秒 | 低,但高并发场景仍需关注 |
| ICMP | ~72 字节 | 30 秒 | 低 |
bpf-ct-global-max 参数。
4.4 Endpoint Map:本地端点的地址簿
Endpoint Map 是一个 BPF_MAP_TYPE_HASH,用于将 IP 地址 映射到 本地端点信息。当数据包的目标 IP 是本机管理的 Pod 或主机时,Cilium 通过查询 Endpoint Map 来获取 MAC 地址、VXLAN VNI、Security Identity 等信息,从而完成最终的转发。
- Key 结构: 目标 IP 地址(32 位 IPv4 或 128 位 IPv6)。
- Value 结构: 包含端点标识、MAC 地址、LXC ID、以及策略相关的元数据。
- 内存消耗公式:
总内存 ≈ (Key_Size + Value_Size + 哈希表开销) × 本地 Pod 数量。该 Map 的大小与节点上运行的 Pod 数量成正比。
// 伪代码:Endpoint Map 条目结构
struct endpoint_key {
__u32 ip; // IPv4 地址
// 对于 IPv6,使用 __u8 ip[16]
};
struct endpoint_info {
__u32 sec_id; // 安全标识
__u8 mac[6]; // MAC 地址
__u32 vni; // VXLAN 网络标识
__u32 ifindex; // 宿主机网卡索引
// ... 其他元数据
};
4.5 Map 大小与内存消耗的量化关系
为了帮助您进行精确的资源规划,以下是一个基于默认配置的量化示例(假设节点为 32 核,运行 100 个 Pod,并发连接数 50 万):
4.6 内存优化与监控实践
针对上述 Map 的内存消耗特性,以下是具体的优化和监控建议:
- 调整 CT Map 超时时间: 对于 TCP 长连接,将
bpf-ct-tcp-max从默认的 6 小时缩短到 1 小时,可以显著降低内存峰值。 - 启用 CT Map GC 加速: 设置
bpf-ct-gc-interval=30s,加快过期连接的回收速度。 - 监控 Map 使用率: 使用
cilium bpf ct list和cilium bpf policy list定期检查条目数,并设置告警阈值(如 80%)。 - 使用 per-CPU 的 Map 变体: 对于 CT Map,Cilium 已经默认使用 per-CPU 的 LRU 哈希表,这减少了锁竞争,但增加了内存消耗。在内存敏感的场景下,可以评估是否使用全局 LRU 哈希表。
--bpf-ct-global-max 设置为 节点最大 Pod 数 × 每个 Pod 预期并发连接数 × 1.5。例如,100 Pod × 5000 连接/Pod × 1.5 = 750,000 条目/CPU。