3. 网络资源配额概念:Linux CGroup 与网络命名空间中的资源限制

在 Linux 内核中,网络资源配额主要通过 CGroup(Control Group) 和 网络命名空间(Network Namespace) 两大机制实现。CGroup 负责对进程组进行资源上限控制,而网络命名空间则提供网络栈的隔离。理解这两者的协同关系,是校准网络观测数据和排查资源超限故障的前提。

3.1 CGroup v1 与 v2 的网络资源限制

CGroup 将进程按层级组织,并对每个层级施加资源约束。网络相关的子系统在 v1 和 v2 版本中有显著差异:

特性 CGroup v1(net_cls / net_prio) CGroup v2(io / memory / cpu + eBPF)
带宽限制 通过 net_cls.classid 标记流量,配合 tc 过滤器实现 无原生网络带宽控制器;依赖 eBPF 程序或 tc 在 cgroup 层级挂载
连接数限制 无直接支持;需通过 iptables + connlimit 或 eBPF 辅助 无原生连接数控制器;推荐使用 eBPF cgroup_sock_addr 钩子
流量统计 通过 net_cls 标记后由 tc 统计 通过 cgroup.local_stat 或 eBPF map 聚合
优先级 net_prio.ifpriomap 设置网络优先级 无原生优先级控制;由 eBPF 或 tc 替代
eBPF 集成 需手动挂载 cgroup 钩子 原生支持 BPF_PROG_TYPE_CGROUP_SKB 等程序类型
实践要点:在 CGroup v2 环境中,网络资源配额通常由 eBPF 程序直接附着在 cgroup 层级上实现。这意味着 eBPF 观测工具(如 bpftrace、Cilium)可以直接读取 cgroup 的统计信息,无需依赖传统的 net_cls 标记。

3.2 网络命名空间的资源隔离

网络命名空间(netns)提供完全隔离的网络栈,包括独立的网络设备、路由表、ARP 表、iptables 规则和 socket 计数。每个 netns 拥有自己的资源视图,但内核全局资源(如总连接数、总内存)仍受系统级限制。

  • 带宽隔离:通过 veth pair 或 macvlan 连接不同 netns,在主机侧使用 tc 或 eBPF 进行带宽整形。
  • 连接数隔离:每个 netns 的 socket 数量受 net.core.somaxconn、net.ipv4.tcp_max_syn_backlog 等内核参数限制,但跨 netns 的连接数总和受系统 fs.nr_open 和 nofile 限制。
  • 流量隔离:每个 netns 的流量统计独立,可通过 ip netns exec 查看各命名空间的网络接口统计。

3.3 资源配额超限的典型场景

当 CGroup 或网络命名空间的资源配额被突破时,通常表现为以下故障模式:

  1. 带宽超限:tc 或 eBPF 的带宽整形器丢弃数据包,导致 TCP 重传率上升、吞吐量骤降。
  2. 连接数超限:新连接被内核拒绝(ECONNREFUSED 或 EAGAIN),应用日志出现 "Too many open files" 或 "Cannot assign requested address"。
  3. 流量配额耗尽:基于 eBPF 的流量计数达到上限后,触发丢包或限速策略,影响业务可用性。
常见误区:很多运维人员误以为 CGroup 的 memory.max 或 cpu.max 超限只会影响计算资源,实际上网络 socket 分配也需要内存。当 CGroup 内存配额不足时,新连接分配 sk_buff 会失败,表现为连接超时或拒绝,容易被误判为网络故障。

3.4 CGroup 与网络命名空间的协同架构

下图展示了 CGroup v2 与网络命名空间在资源配额管理中的协同关系:

CGroup v2 与网络命名空间协同架构 CGroup v2 层级 Root CGroup /sys/fs/cgroup/ Service A memory.max=512M Container-1 pids.max=100 eBPF 程序 cgroup_skb 钩子 网络命名空间 Host NetNS eth0, lo Service A NetNS veth0, 10.0.1.0/24 Container-1 NetNS veth1, 10.0.1.2/24 tc / iptables 带宽整形 + 连接限制 eBPF 附着点 说明:CGroup 提供进程级资源上限,网络命名空间提供网络栈隔离,eBPF 在两者之间实现配额校准与观测

3.5 资源配额的关键指标与观测点

在故障排查中,需要重点关注以下指标:

指标类别 具体指标 观测命令/工具 超限表现
带宽 吞吐量(bps)、丢包率 tc -s qdisc、sar -n DEV tc 队列丢弃、TCP 重传
连接数 当前连接数、连接速率 ss -s、cat /proc/net/sockstat 新连接失败、TIME_WAIT 堆积
流量配额 累计流量、剩余配额 eBPF map 读取、bpftool map dump eBPF 程序触发限速逻辑
CGroup 内存 memory.current、memory.max cat /sys/fs/cgroup/<path>/memory.current sk_buff 分配失败、OOM
NetNS 资源 各 netns 接口统计 ip netns exec <ns> ip -s link 单 netns 流量异常

3.6 配额校准的 eBPF 观测方法

eBPF 可以在 CGroup 和网络命名空间层面直接采集配额使用数据,避免传统工具(如 tc、iptables)的统计偏差:

  • cgroup_skb 程序:附着在 CGroup 上,统计每个 cgroup 的入站/出站字节数和包数,直接与配额上限对比。
  • cgroup_sock_addr 程序:监控 socket 的 bind/connect/accept 操作,实时统计连接数,并在接近上限时发出告警。
  • netns 感知:通过 bpf_get_ns_current_pid_tgid() 或 bpf_skc_to_netns() 辅助函数,将流量归因到具体网络命名空间。
校准示例:使用 bpftrace 实时观测 CGroup 级别的带宽使用:
bpftrace -e '
  kfunc:__cgroup_bpf_run_filter_skb
  {
    $cgrp = (struct cgroup *)arg0;
    printf("CGroup ID: %d, len: %d\n", $cgrp->kn->id, arg2);
  }'
该脚本可以捕获每个经过 CGroup 过滤的网络包,帮助确认配额统计是否准确。

3.7 常见配额超限故障排查流程

当怀疑网络资源配额超限时,建议按以下步骤排查:

  1. 确认超限现象:检查应用日志、系统日志(dmesg)是否有 "Resource temporarily unavailable" 或 "Quota exceeded" 错误。
  2. 定位受限层级:使用 cat /proc/<pid>/cgroup 确定进程所属 CGroup,使用 lsns -t net 确定网络命名空间。
  3. 读取配额上限:查看 CGroup 目录下的 memory.max、pids.max 等文件;查看 netns 的 sysctl 参数。
  4. 采集实时使用量:使用 eBPF 工具(如 bpftrace、cilium monitor)采集当前带宽、连接数、流量。
  5. 对比校准:将 eBPF 采集数据与 CGroup 统计文件(如 memory.current)对比,确认是否存在统计偏差。
  6. 调整或扩容:根据校准结果,调整 CGroup 配额上限、优化应用连接池、或增加网络命名空间资源。
排查陷阱:不要仅依赖 ss -s 或 netstat 判断连接数超限,这些工具显示的是系统全局连接数,而非 CGroup 或 netns 级别的配额。必须使用 eBPF 或 cgroup 接口获取受限视图的数据。