元鉴
返回中文阅读流

Kubernetes Blog

从 cgroup v1 CPU shares 到 v2 CPU weight 的新转换方式

宣布实现从 cgroup v1 CPU shares 到 cgroup v2 CPU weight 的改进转换公式,解决 cgroup v2 系统上 Kubernetes 工作负载的 CPU 优先级分配问题。

中文内容

已翻译official company source英文原文2026-01-30

从 cgroup v1 CPU shares 到 v2 CPU weight 的新转换方式

By Itamar Holder (Red Hat) | Friday, January 30, 2026

我很高兴宣布,已实现从 cgroup v1 CPU shares 到 cgroup v2 CPU weight 的改进转换公式。此增强解决了在使用 cgroup v2 的系统上运行 Kubernetes 工作负载时,CPU 优先级分配方面的关键问题。

背景

Kubernetes 最初是围绕 cgroup v1 设计的,其中 CPU shares 根据容器的 CPU requests 通过以下公式得出:

正文:$$cpu.shares = milliCPU \times \frac{1024}{1000}$$

请注意,此公式中的 1024 是 cgroup v1 中默认的 cpu.shares 值,与 millicores 无关。例如,请求 1 CPU(1000m)的容器会得到(cpu.shares = 1000 \times 1024 / 1000 = 1024),请求 100m 的容器会得到(cpu.shares = 100 \times 1024 / 1000 = 102)。

一段时间后,cgroup v1 开始被其继任者 cgroup v2 取代。在 cgroup v2 中,CPU shares 的概念(范围为 2 到 262144,或 2¹ 到 2¹⁸)被 CPU weight 取代(范围为 [1, 10000],或 10⁰ 到 10⁴)。

随着向 cgroup v2 过渡,KEP-2254 引入了一个转换公式,用于将 cgroup v1 CPU shares 映射到 cgroup v2 CPU weight。该转换公式定义为:cpu.weight = (1 + ((cpu.shares - 2) * 9999) / 262142)

此公式将 [2¹, 2¹⁸] 中的值线性映射到 [10⁰, 10⁴]。

Linear conversion formula

虽然这种方法很简单,但线性映射带来了几个重大问题,并影响性能和配置粒度。

先前转换公式存在的问题

当前转换公式会产生两个主要问题:

1. 相对于非 Kubernetes 工作负载的优先级降低

在 cgroup v1 中,CPU shares 的默认值为 1024,这意味着请求 1 CPU 的容器与 Kubernetes 范围之外的系统进程具有相同优先级。然而,在 cgroup v2 中,默认 CPU weight 为 100,但当前公式仅将 1 CPU(1000m)转换为约 39 的 weight——不到默认值的 40%。

示例:

  • 请求 1 CPU(1000m)的容器
  • cgroup v1:cpu.shares = 1024(等于默认值)
  • cgroup v2(当前):cpu.weight = 39(远低于默认值 100)

这意味着迁移到 cgroup v2 后,Kubernetes(或 OCI)工作负载相对于非 Kubernetes 进程实际上会降低其 CPU 优先级。对于有许多在 Kubernetes 范围之外运行的系统守护进程、且预期 Kubernetes 工作负载具有优先级的部署来说,这个问题可能很严重,尤其是在资源匮乏的情况下。

2. 难以管理的粒度

当前公式会为较小的 CPU requests 生成非常低的值,从而限制了在容器内创建子 cgroups 以进行细粒度资源分配的能力(未来这可能会变得容易得多,更多信息见 KEP #5474)。

示例:

  • 请求 100m CPU 的容器
  • 正文:cgroup v1:cpu.shares = 102
  • cgroup v2(当前):cpu.weight = 4(对于子 cgroup 配置来说过低)

在 cgroup v1 中,请求 100m CPU 会产生 102 个 CPU shares,从可管理性角度看,可以在主容器内创建子 cgroups,为不同进程组分配细粒度的 CPU 优先级。然而在 cgroup v2 中,只有 4 个 shares 很难在子 cgroups 之间分配,因为粒度不够。

随着计划允许非特权容器使用可写 cgroups,这一点变得更加相关。

新的转换公式

说明

新公式更复杂,但能更好地在 cgroup v1 CPU shares 与 cgroup v2 CPU weight 之间进行映射:

$$cpu.weight = \lceil 10^{(L^{2}/612 + 125L/612 - 7/34)} \rceil, \text{ 其中: } L = \log_2(cpu.shares)$$

其思路是,这是一个二次函数,用于穿过以下数值点:

  • (2, 1):两个范围的最小值。
  • (1024, 100):两个范围的默认值。
  • (262144, 10000):两个范围的最大值。

从视觉上看,新函数如下:

2025-10-25-new-cgroup-v1-to-v2-conversion-formula-new-conversion.png

如果放大到重要部分:

2025-10-25-new-cgroup-v1-to-v2-conversion-formula-new-conversion-zoom.png

新公式“接近线性”,但经过精心设计,以巧妙方式映射这些范围,使上述三个重要点能够被穿过。

它如何解决这些问题

  1. 更好的优先级对齐:请求 1 CPU(1000m)的容器现在将得到 cpu.weight = 102。该值接近 cgroup v2 的默认值 100。这恢复了 Kubernetes 工作负载与系统进程之间预期的优先级关系。
  2. 改进的粒度:请求 100m CPU 的容器将得到 cpu.weight = 17(见此处)。这支持在容器内实现更好的细粒度资源分配。

采用与集成

此更改是在 OCI 层实现的。换言之,它并未在 Kubernetes 本身中实现;因此,新转换公式的采用完全取决于 OCI runtime 的采用情况。

例如:

  • runc:新公式自版本 1.3.2 起启用。
  • crun:新公式自版本 1.23 起启用。

对现有部署的影响

重要:如果某些使用者假定旧的线性转换公式,可能会受到影响。基于先前公式直接计算预期 CPU weight 值的应用程序或监控工具,可能需要更新以适配新的二次转换。这一点尤其适用于:

  • 预测 CPU weight 值的自定义资源管理工具。
  • 验证或期望特定 weight 值的监控系统。
  • 以编程方式设置或验证 CPU weight 值的应用程序。

另请注意,从 cpu.weight 反向转换回 milliCPU 并不总能得到完全相同的原始值。信息丢失有两个来源:milliCPU 到 cpu.shares 的转换涉及整数截断(例如 100m 变为 102 shares,而不是 102.4);更重要的是,shares 到 weight 的映射是多对一的(例如 milliCPU 值 90 到 109 都映射到 cpu.weight = 17)。需要精确 CPU request 值的工具应直接从 pod spec 读取,而不是从 cgroup 参数推导。

Kubernetes 项目建议,在升级 OCI runtimes 之前,先在非生产环境中测试新的转换公式,以确保与现有工具兼容。

我可以在哪里了解更多?

对这一增强感兴趣的人:

  • Kubernetes GitHub Issue #131216——详细的技术分析和示例,包括关于选择上述公式的讨论与理由。
  • KEP-2254:cgroup v2——Kubernetes 中最初的 cgroup v2 实现。
  • Kubernetes cgroup 文档——当前资源管理指南。

我如何参与?

如果你有兴趣参与 Kubernetes 节点级功能,请加入 Kubernetes Node Special Interest Group。我们始终欢迎新的贡献者,以及关于资源管理挑战的多元视角。

  • ← 上一篇
  • 下一篇 →
Last modified March 09, 2026 at 9:26 AM PST: Add milliCPU to cpu.shares conversion formula (740c0f53de)

原文标题

New Conversion from cgroup v1 CPU Shares to v2 CPU Weight