3. 资源模型设计原则:面向租户的CPU、内存、网络带宽资源抽象

在多租户云原生环境中,eBPF网络观测系统必须建立一套清晰的资源模型,将底层物理资源抽象为租户可感知、可配额、可审计的逻辑单元。本章定义面向租户的CPU、内存、网络带宽三大资源的抽象原则,为后续准入控制与调度策略奠定基础。

3.1 资源抽象的三层架构

资源模型采用“物理资源 → 虚拟资源池 → 租户视图”的三层抽象架构,每一层解决不同的关注点:

抽象层 关注点 典型对象 eBPF观测点
物理资源层 节点容量、硬件拓扑 CPU核心、NUMA节点、内存条、网卡 perf_event、kprobe/sched_switch
虚拟资源池层 资源切片、隔离域 cgroup、CPU份额、内存上限、带宽限速 cgroup BPF、tc BPF
租户视图层 配额管理、用量计量 租户ID、资源预留、突发上限 BPF map(租户维度聚合)
设计原则:每一层只关注本层职责,下层向上层提供标准化接口。eBPF程序在物理层和虚拟资源池层采集原始数据,在租户视图层完成聚合与记账。

3.2 CPU资源抽象原则

CPU资源抽象的核心目标是:按租户分配计算时间片,并确保观测开销不干扰业务负载。

  • 时间片配额(CPU Quota):基于CFS调度器的cpu.cfs_quota_us与cpu.cfs_period_us,为每个租户设定周期内可使用的CPU时间上限。eBPF通过sched_switch tracepoint采集实际运行时间,与配额对比生成告警。
  • 权重分配(CPU Shares):使用cpu.shares实现弹性竞争,权重高的租户在资源争抢时获得更多时间片。eBPF观测sched_wakeup事件,统计各租户的唤醒延迟。
  • 核心绑定(CPU Pinning):对延迟敏感型租户,允许将特定CPU核心独占绑定。eBPF通过sched_migrate_task跟踪任务迁移,确保绑定策略不被违反。
// eBPF CPU时间采集核心逻辑(伪代码)
struct cpu_account {
    u64 runtime_ns;
    u64 period_ns;
    u64 quota_ns;
};

struct {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 1024);
    __type(key, u32);   // 租户ID
    __type(value, struct cpu_account);
} tenant_cpu_map SEC(".maps");

SEC("tracepoint/sched/sched_switch")
int trace_sched_switch(struct trace_event_raw_sched_switch *ctx) {
    u32 tenant_id = get_current_tenant_id();
    struct cpu_account *acc = bpf_map_lookup_elem(&tenant_cpu_map, &tenant_id);
    if (acc) {
        u64 now = bpf_ktime_get_ns();
        acc->runtime_ns += now - prev_runtime;  // 累加运行时间
    }
    return 0;
}

3.3 内存资源抽象原则

内存资源抽象强调硬限制与软限制结合,避免OOM影响跨租户稳定性。

抽象维度 cgroup参数 eBPF观测事件 租户视图指标
物理内存上限 memory.max cgroup_oom、mm_page_alloc 当前用量、OOM次数
内存+交换上限 memory.swap.max vmscan_* 回收事件 交换使用率、回收延迟
内存软限制 memory.high memcg_stat 水位线 高压持续时间、throttle次数
NUMA亲和性 cpuset.mems numa_hit/numa_miss 本地内存访问比例
实践建议:内存资源模型应优先使用memory.high软限制配合eBPF水位线告警,避免硬限制触发OOM Killer导致租户进程被强制终止。仅在关键生产租户上启用memory.max硬限制。

3.4 网络带宽资源抽象原则

网络带宽抽象是eBPF网络观测的核心场景,需要同时覆盖入方向、出方向、连接数、吞吐量四个维度。

  • 带宽限速(Bandwidth Shaping):基于tc BPF或XDP实现每租户流量整形。出方向使用HTB队列,入方向通过ifb设备或XDP限速。
  • 连接数限制(Connection Limit):通过BPF_MAP_TYPE_HASH跟踪每租户活跃连接数,超过阈值时丢包或重置。
  • 吞吐量记账(Throughput Accounting):在XDP或tc BPF入口处统计字节数,按租户ID聚合到BPF map中。
// eBPF网络带宽限速与记账(tc BPF出口方向)
struct bpf_elf_map {
    __uint(type, BPF_MAP_TYPE_HASH);
    __uint(max_entries, 4096);
    __type(key, u32);   // 租户ID
    __type(value, struct rate_limit);
} tenant_rate_map SEC("maps");

struct rate_limit {
    __u64 bytes_quota;      // 周期内允许字节数
    __u64 bytes_used;       // 已使用字节数
    __u64 last_update;      // 上次更新时间戳
};

SEC("tc")
int tc_egress(struct __sk_buff *skb) {
    u32 tenant_id = skb->cb[0];  // 从skb控制块获取租户ID
    struct rate_limit *rl = bpf_map_lookup_elem(&tenant_rate_map, &tenant_id);
    if (!rl) return TC_ACT_OK;

    __u64 now = bpf_ktime_get_ns();
    if (now - rl->last_update > 1000000000) {  // 每秒重置
        rl->bytes_used = 0;
        rl->last_update = now;
    }

    if (rl->bytes_used + skb->len > rl->bytes_quota) {
        return TC_ACT_SHOT;  // 超过配额,丢包
    }

    __sync_fetch_and_add(&rl->bytes_used, skb->len);
    return TC_ACT_OK;
}
注意:网络带宽抽象必须区分“承诺速率(CIR)”和“突发速率(PIR)”。eBPF限速程序应使用令牌桶算法,允许短时突发但长期平均不超过承诺值。直接丢包会导致TCP重传风暴,建议配合ECN标记进行拥塞通知。

3.5 资源模型协同关系图

下图展示CPU、内存、网络带宽三种资源在eBPF观测视角下的协同关系:

面向租户的资源模型协同关系 租户A / 租户B / 租户C CPU 抽象 内存 抽象 网络带宽 抽象 eBPF 观测引擎(perf_event / tracepoint / kprobe / XDP / tc) BPF Map 聚合(租户维度:CPU时间 / 内存用量 / 网络字节数) 准入控制决策(配额校验 / 限速触发 / OOM预防) 反馈闭环 → 更新租户资源配额 三种资源独立采集,协同决策

3.6 资源模型设计检查清单

在实际落地资源模型时,建议对照以下清单逐项验证:

  1. 完备性:是否覆盖CPU、内存、网络带宽三大核心资源?是否遗漏磁盘IO或GPU?
  2. 可观测性:每种资源的eBPF观测点是否明确?采集频率是否可控?
  3. 可配额性:租户能否通过API查询当前配额和已用量?
  4. 隔离性:一个租户的资源耗尽是否会影响其他租户的观测数据?
  5. 性能开销:eBPF程序在资源采集路径上的CPU开销是否低于1%?
  6. 可扩展性:新增资源类型(如eBPF map大小)是否需要修改核心模型?
核心结论:面向租户的资源模型不是简单的“配额+监控”,而是通过eBPF在底层实现细粒度观测,在上层提供统一的租户视图。CPU、内存、网络带宽三种资源虽然抽象方式不同,但都遵循“物理→虚拟→租户”的三层架构,并通过BPF map实现跨资源的数据关联。