4. 资源模型概述:定义 eBPF 租户隔离中的核心资源模型

在 eBPF 租户隔离架构中,资源模型是控制平面与数据平面交互的语义基础。每个租户的隔离边界由一组可量化的资源配额构成,控制平面通过统一的资源描述符向 eBPF 程序下发策略。本章定义 CPU、内存、网络、文件系统四大核心资源的抽象模型,并给出对应的 eBPF 数据结构映射。

4.1 资源模型设计原则

资源模型遵循三条核心原则:

  • 统一描述:所有资源使用相同的元数据结构(类型、ID、配额、统计),便于控制平面统一编排。
  • 可观测性:每个资源实例附带计数器与时间戳,支持实时监控与审计。
  • 可执行性:资源模型直接映射为 eBPF map 中的键值对,数据平面无需额外解析。
原则 说明 eBPF 实现载体
统一描述 资源类型枚举 + 租户 ID + 配额上限 struct resource_quota
可观测性 当前用量、峰值、最后更新时间 struct resource_stats
可执行性 键值对直接用于 eBPF map 查找与更新 BPF_MAP_TYPE_HASH
设计提示:资源模型应保持扁平化,避免嵌套结构。eBPF 验证器对栈深度和循环次数有限制,扁平键值对能显著降低验证失败风险。

4.2 CPU 资源模型

CPU 资源模型以 时间片配额 和 并发执行上限 两个维度定义租户的 CPU 使用边界。控制平面将配额写入 eBPF map,eBPF 程序在调度点(如 sched/sched_switch)执行检查。

  • 时间片配额:每毫秒可使用的 CPU 微秒数(μs/ms),例如 500 μs/ms 表示占用 50% 单核。
  • 并发上限:同一时刻允许运行的任务数,防止租户通过多线程抢占。
  • 统计字段:累计使用时间、被节流次数、最后调度时间戳。
// CPU 资源配额结构
struct cpu_quota {
    __u32 tenant_id;        // 租户标识
    __u64 quota_us_per_ms;  // 每毫秒配额(微秒)
    __u32 max_concurrency;  // 最大并发任务数
};

// CPU 运行时统计
struct cpu_stats {
    __u64 used_us;          // 累计使用微秒
    __u64 throttled_count;  // 被节流次数
    __u64 last_update_ns;   // 最后更新时间(纳秒)
};
关键约束:CPU 配额检查必须在 sched/sched_switch 或 sched/sched_process_exec 等低开销挂载点执行,避免在热路径中引入高延迟。

4.3 内存资源模型

内存资源模型覆盖 物理内存上限 和 内存分配速率 两个维度。eBPF 程序通过跟踪 kmem_cache_alloc、mmap 等内核函数实现配额控制。

维度 描述 eBPF 挂载点
物理内存上限 租户可使用的最大 RSS(常驻内存)字节数 kmem_cache_alloc、mmap
分配速率 每秒允许分配的内存页数,防止内存暴涨 page_fault_user、page_fault_kernel
// 内存资源配额结构
struct mem_quota {
    __u32 tenant_id;
    __u64 rss_limit_bytes;   // RSS 上限(字节)
    __u32 page_rate_limit;   // 每秒允许分配的页数
};

// 内存运行时统计
struct mem_stats {
    __u64 current_rss_bytes; // 当前 RSS
    __u32 page_alloc_count;  // 当前秒已分配页数
    __u64 last_reset_ns;     // 速率计数器重置时间
};
注意事项:内存统计需要处理 cgroup 事件与 eBPF 程序的同步问题。建议使用 BPF_MAP_TYPE_PERCPU_HASH 减少锁竞争,并在用户态定期聚合。

4.4 网络资源模型

网络资源模型以 带宽、连接数、包速率 三个指标定义租户的网络边界。eBPF 程序在 tc 入口/出口或 XDP 点执行流量整形与限速。

  • 带宽:每秒允许通过的字节数(bps),支持入站与出站独立配置。
  • 连接数:租户可同时建立的 TCP/UDP 连接数上限。
  • 包速率:每秒允许处理的数据包数量(pps),防止小包攻击。
// 网络资源配额结构
struct net_quota {
    __u32 tenant_id;
    __u64 ingress_bps;       // 入站带宽(字节/秒)
    __u64 egress_bps;        // 出站带宽(字节/秒)
    __u32 max_connections;   // 最大连接数
    __u32 max_pps;           // 最大包速率
};

// 网络运行时统计
struct net_stats {
    __u64 ingress_bytes;     // 累计入站字节
    __u64 egress_bytes;      // 累计出站字节
    __u32 active_connections;// 当前活跃连接数
    __u32 pps_count;         // 当前秒包数
};
性能建议:网络资源检查应优先在 XDP 层完成,避免数据包进入协议栈后再丢弃。XDP 的包丢弃延迟比 tc 低 2-3 个数量级。

4.5 文件系统资源模型

文件系统资源模型管理 磁盘空间、inode 数量 和 IOPS。eBPF 程序通过跟踪 vfs_write、vfs_read、ext4_* 等文件系统操作实现配额控制。

维度 描述 eBPF 挂载点
磁盘空间 租户可使用的磁盘字节数上限 vfs_write、ext4_write_begin
inode 数量 租户可创建的文件/目录数量上限 vfs_create、vfs_mkdir
IOPS 每秒允许的读写操作次数 block_rq_issue、block_rq_complete
// 文件系统资源配额结构
struct fs_quota {
    __u32 tenant_id;
    __u64 disk_limit_bytes;  // 磁盘空间上限
    __u32 inode_limit;       // inode 上限
    __u32 iops_limit;        // IOPS 上限
};

// 文件系统运行时统计
struct fs_stats {
    __u64 used_bytes;        // 已用磁盘空间
    __u32 used_inodes;       // 已用 inode 数
    __u32 iops_count;        // 当前秒 IOPS
    __u64 last_reset_ns;     // IOPS 计数器重置时间
};
实现要点:文件系统配额需要与内核的 dquot(磁盘配额)机制协同。eBPF 程序负责实时拦截与计数,而 dquot 负责持久化配额状态。两者通过共享 eBPF map 交换数据。

4.6 资源模型统一视图

下图展示四大资源模型在 eBPF 租户隔离架构中的统一视图。控制平面通过统一的资源描述符下发配额,eBPF 数据平面在各自挂载点执行检查与统计。

eBPF 租户隔离资源模型统一视图 控制平面(统一资源描述符) 资源模型层 CPU 配额 | 内存配额 | 网络配额 | 文件系统配额 eBPF 数据平面 sched/sched_switch | kmem_cache_alloc | tc/XDP | vfs_write 内核资源层 CPU 调度器 | 内存管理 | 网络协议栈 | 文件系统 说明 控制平面下发统一资源描述符 → 资源模型层映射为具体配额结构 → eBPF 数据平面在各挂载点执行检查 → 内核资源层执行实际调度与限制

4.7 资源模型与控制平面的接口映射

控制平面通过统一的 资源描述符 与 eBPF 数据平面交互。描述符包含资源类型、租户 ID、操作类型(查询/更新/删除)和配额数据。eBPF 程序通过 bpf_map_lookup_elem 和 bpf_map_update_elem 操作对应的资源 map。

// 统一资源描述符
struct resource_descriptor {
    __u32 tenant_id;
    enum resource_type type;  // CPU, MEM, NET, FS
    enum op_type op;          // QUERY, UPDATE, DELETE
    union {
        struct cpu_quota cpu;
        struct mem_quota mem;
        struct net_quota net;
        struct fs_quota fs;
    } quota;
};

// eBPF map 定义
struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, __u32);           // tenant_id
    __type(value, struct resource_descriptor);
} resource_map SEC(".maps");
接口设计要点:控制平面与 eBPF 数据平面之间使用共享 map 通信,避免系统调用开销。控制平面通过 bpf() 系统调用更新 map,eBPF 程序在挂载点读取 map 执行策略。建议为每个资源类型创建独立的 map,减少锁竞争。