Kubernetes исправил формулу CPU cgroup v2: что изменилось и как это влияет
Kubernetes обновил формулу преобразования CPU shares из cgroup v1 в CPU weight для cgroup v2. Новая формула, реализованная в рамках KEP-2254, исправляет давнюю проблему, из-за которой контейнеры с запросом 1 CPU (1000m) получали CPU weight всего около 39 — менее 40% от дефолтного значения 100. Это п

Kubernetes обновил формулу преобразования CPU shares из cgroup v1 в CPU weight для cgroup v2. Новая формула, реализованная в рамках KEP-2254, исправляет давнюю проблему, из-за которой контейнеры с запросом 1 CPU (1000m) получали CPU weight всего около 39 — менее 40% от дефолтного значения 100. Это приводило к несправедливому распределению процессорного времени между Kubernetes-нагрузками и системными процессами, работающими вне оркестратора. Теперь контейнеры с запросом 1 CPU получают weight 100, что уравнивает их приоритет с системными задачами.
Новая формула преобразования CPU shares в CPU weight
Исходно Kubernetes был спроектирован для cgroup v1, где CPU shares вычислялись по формуле: cpu.shares = milliCPU × 1024 / 1000. Например, контейнер с запросом 1 CPU (1000m) получал 1024 shares, а с запросом 100m — 102 shares. В cgroup v2 концепция shares (диапазон от 2 до 262144) была заменена на weight (диапазон от 1 до 10000). Первая версия конверсии, введённая в KEP-2254, использовала линейное отображение: cpu.weight = 1 + ((cpu.shares - 2) × 9999) / 262142. Это давало вес 39 для 1024 shares. Новая формула, предложенная в этом обновлении, использует нелинейное отображение: cpu.weight = (cpu.shares / 1024) × 100. Таким образом, 1024 shares превращаются в 100 weight — то есть ровно в дефолтное значение cgroup v2, что восстанавливает паритет с системными процессами.
Почему старая формула была проблемной?
Проблема возникла из-за того, что cgroup v2, ставший стандартом в современных дистрибутивах Linux, использует другую шкалу приоритетов. Дефолтный CPU weight в cgroup v2 равен 100, и все процессы, не управляемые Kubernetes, получают этот вес. Однако старая формула давала контейнерам с 1 CPU вес 39, что делало их менее приоритетными по сравнению с фоновыми системными задачами. Это особенно критично для production-кластеров, где каждый процент процессорного времени на счету. Проблема усугублялась тем, что контейнеры с малыми запросами (например, 100m) получали вес около 4, что ещё сильнее снижало их приоритет. Новая формула решает эту проблему, делая преобразование более интуитивным и справедливым.
Как работает новая формула?
Новая формула проста: cpu.weight = (cpu.shares / 1024) × 100. Здесь 1024 — это дефолтное значение shares в cgroup v1, а 100 — дефолтный weight в cgroup v2. Таким образом, контейнер с запросом 1 CPU (1000m) получает weight 100, что равно приоритету системных процессов. Контейнер с запросом 2 CPU (2000m) получит weight 200, а с запросом 0.5 CPU (500m) — weight 50. Важно, что формула нелинейна относительно милликор: она линейна относительно shares, но shares линейно зависят от milliCPU. Фактически, weight теперь прямо пропорционален запрошенным миллиядрам, что упрощает понимание и предсказуемость поведения.
Технические подробности и влияние на производительность
Старая формула была линейной, но её диапазон [2, 262144] shares отображался на [1, 10000] weight. Это давало слишком низкие веса для типичных значений shares. Новая формула использует деление на 1024, что приводит к range от 0.00195 до 256. Однако на практике Kubernetes ограничивает weight минимальным значением 1 и максимальным 10000. Для контейнеров с запросом менее 2m weight будет округлён до 1, что соответствует минимальному приоритету. Для контейнеров с запросом более 100 CPU weight будет обрезан до 10000. Это изменение не влияет на производительность в обычных сценариях, но устраняет несправедливость в распределении CPU. Тесты показывают, что при конкурентной нагрузке контейнеры с новым весом получают ожидаемую долю процессорного времени, близкую к их запросам.
Как это повлияет на существующие кластеры?
Изменение коснётся всех кластеров Kubernetes, использующих cgroup v2 (по умолчанию в Kubernetes 1.24+). Администраторам кластеров не нужно предпринимать никаких действий — обновление будет включено в следующий релиз Kubernetes (предположительно 1.32). Однако разработчикам и DevOps-инженерам стоит пересмотреть свои ожидания по CPU priority: теперь контейнер с запросом 1 CPU будет иметь такой же приоритет, как и системные процессы. Это может повлиять на сценарии, где раньше полагались на более низкий приоритет контейнеров. Для пользователей, которые вручную настраивали CPU weight через cgroup v2, изменений нет — формула применяется только при автоматическом преобразовании из shares.
Что будет дальше
Новая формула уже реализована в коде Kubernetes и проходит стадию ревью. Ожидается, что она войдёт в состав релиза Kubernetes 1.32, запланированного на апрель 2026 года. Команда Kubernetes рекомендует всем, кто использует cgroup v2, протестировать новую формулу на тестовых кластерах после выхода обновления. В будущем возможно дальнейшее уточнение формулы для экстремальных значений, но текущее решение покрывает 99% сценариев использования.
Итог
Новая формула преобразования CPU shares в CPU weight восстанавливает справедливое распределение процессорного времени между Kubernetes-нагрузками и системными процессами. Это важное исправление, которое делает поведение cgroup v2 более предсказуемым и соответствующим ожиданиям администраторов. Следите за релизом Kubernetes 1.32, чтобы внедрить улучшение в свои кластеры.