2. 资源模型与度量体系

做资源利用率优化,第一步不是调参,而是把“资源”这件事在 Kubernetes 里说清楚。Kubernetes 并不直接管理物理 CPU 核或内存条,它管理的是一套抽象后的可声明、可调度、可计量的资源模型。只有先理解这套模型,才能理解为什么“节点 CPU 使用率 30%”和“Pod 的 CPU 利用率 30%”可能指向完全不同的结论。

一、Kubernetes 的资源抽象层次

Kubernetes 把资源分成三个层次来理解:节点可分配资源(Allocatable)、容器声明资源(Requests/Limits)、实际使用资源(Usage)。调度器只看 Requests,kubelet 的驱逐逻辑看 Limits 与节点压力,而监控系统看的是 Usage。三者不一致,正是利用率指标容易误读的根源。

节点侧,一个 Node 的容量(Capacity)会被系统组件、kubelet 预留、驱逐阈值逐步扣减,最终得到可分配给 Pod 的 Allocatable。例如一个 8 核 32GiB 的节点,扣除 kube-reserved、system-reserved 和 eviction 阈值后,Allocatable 可能只有 7.6 核 29GiB。因此节点利用率的分母应当是 Allocatable,而不是 Capacity。

二、CPU 的计量单位与语义

CPU 在 Kubernetes 中是可压缩资源,计量单位是“核”,写法上 1 等于 1000m(毫核)。500m 表示 0.5 核。CPU 的 Requests 决定调度权重和 cgroup 的 cpu.shares,Limits 决定 cgroup 的 cpu.cfs_quota_us,也就是 CPU 上限。超过 Limits 时 CPU 会被节流(throttling),而不是被杀掉。

这里有一个关键点:CPU 利用率的分母选择会显著改变结论。若用 Requests 作分母,得到的是“配额使用率”,反映申请是否虚高;若用节点 Allocatable 作分母,得到的是“节点真实占用率”,反映整体水位。工程上通常两个都要看。

三、内存的计量单位与语义

内存是不可压缩资源,单位是字节,常用 Mi、Gi 表示。256Mi 即 256×1024×1024 字节。内存超过 Limits 会触发 OOMKill,容器被强制终止;节点内存紧张时,kubelet 会按 QoS 等级驱逐 Pod。QoS 由 Requests 与 Limits 的关系决定:两者相等且都设置的是 Guaranteed,只设 Requests 的是 Burstable,都不设的是 BestEffort。

内存利用率同样要区分口径:容器工作集(working set)与 RSS 不同,缓存(page cache)是否计入也会影响结果。通常用 container_memory_working_set_bytes 作为内存使用量,它更接近“真实占用”。

四、存储、网络与 GPU 的抽象

存储分为临时存储(ephemeral-storage)和持久卷(PV)。临时存储以字节计量,用于限制容器可写的本地磁盘量,超限会被驱逐。PV 通过 PVC 声明容量,单位同样是字节,但它是“容量配额”而非“实时用量”,利用率需要结合文件系统实际使用量计算。

网络在 Kubernetes 中没有 Requests/Limits 形式的资源声明,它通过 CNI 插件、带宽插件或 eBPF 观测来度量。常用指标是带宽(bps)、包速率(pps)和连接数。网络利用率通常以网卡线速或节点带宽上限为分母。

GPU 是扩展资源,以整数计量,nvidia.com/gpu: 1 表示申请一张 GPU。GPU 不可超卖,Requests 必须等于 Limits。GPU 利用率不能只看“是否被占用”,而要看 SM 利用率、显存占用、显存带宽等维度,通常由 DCGM 等工具采集。

Kubernetes 资源模型:抽象层次与计量口径 节点层 Node Capacity:物理总量 − kube-reserved − system-reserved − eviction 阈值 = Allocatable(分母) 示例:8C/32Gi → 7.6C/29Gi 容器层 Pod/Container Requests:调度依据 Limits:运行上限 QoS:Guaranteed / Burstable / BestEffort CPU 可压缩 / 内存不可压缩 超限:CPU 节流,内存 OOMKill 实际使用层 Usage CPU:core / millicore 内存:working_set_bytes 存储:ephemeral / PV GPU:SM / 显存 / 带宽 监控采集口径 cAdvisor / DCGM / eBPF 利用率口径(分母决定结论) 配额使用率 = Usage ÷ Requests → 判断申请是否虚高 节点占用率 = Usage ÷ Allocatable → 判断整体水位与扩容时机 限流率 = throttled_periods ÷ total_periods → 判断 CPU Limits 是否过紧 五类资源的计量与超限行为 CPU 核/毫核 · 可压缩 · 节流 内存 字节 · 不可压缩 · OOM 存储 字节 · 配额 · 驱逐 网络 bps/pps · 无声明 · 观测 GPU 整数 · 不可超卖 · 独占

五、利用率指标的定义与陷阱

利用率本质是一个比值:利用率 = 实际使用量 ÷ 可用总量。难点在于分子和分母都可能有多种口径。以 CPU 为例,分子可以是容器 CPU 使用秒数速率,分母可以是 Requests、Limits 或 Allocatable;以内存为例,分子可以是 working set、RSS 或含缓存的总量。指标定义不统一,优化就会失去基准。

实践中建议固定一套口径并写入监控规范。例如:CPU 配额使用率 = rate(container_cpu_usage_seconds_total[5m]) ÷ kube_pod_container_resource_requests{resource="cpu"};内存工作集使用率 = container_memory_working_set_bytes ÷ kube_pod_container_resource_limits{resource="memory"}。分母为 0 或缺失时要显式排除,避免出现无穷大或误导性尖峰。

注意:CPU 利用率低不等于资源浪费。若 Requests 远高于实际使用,节点会因“已分配”而无法调度新 Pod,形成分配性浪费;若 Limits 设置过紧,则会出现节流,表现为延迟升高而利用率看起来并不高。两类问题需要分别用配额使用率和限流率来定位。

六、可参考的度量字段清单

资源计量单位关键指标超限行为
CPU核 / 毫核(m)usage_seconds_total、throttled_periods节流,不终止
内存字节(Mi/Gi)working_set_bytes、rssOOMKill / 驱逐
临时存储字节ephemeral_storage_used驱逐 Pod
持久卷字节kubelet_volume_stats_used_bytes写入失败
网络bps / ppscontainer_network_receive_bytes无硬限制,拥塞
GPU整数(张)DCGM_FI_DEV_GPU_UTIL、显存占用调度失败

把这张表当作度量体系的“字典”:任何一次利用率分析,先确认用的是哪一行、哪个分母、哪个采集源。资源模型清晰之后,后续的 Requests/Limits 调优、HPA 阈值设定、节点扩容判断才有共同语言。