Управління політиками керування ЦП на вузлі
Kubernetes v1.26 [stable]
Kubernetes зберігає багато аспектів того, як Podʼи виконуються на вузлах, абстрагованими від користувача. Це зроблено навмисно. Проте деякі завдання вимагають більших гарантій з погляду часу реакції та/або продуктивності, щоб працювати задовільно. Kubelet надає методи для включення складніших політик розміщення завдань, зберігаючи абстракцію вільною від явних директив розміщення.
Для отримання докладної інформації щодо управління ресурсами, будь ласка, зверніться до документації Управління ресурсами для Podʼів та контейнерів.
Перш ніж ви розпочнете
Вам треба мати кластер Kubernetes, а також інструмент командного рядка kubectl має бути налаштований для роботи з вашим кластером. Рекомендується виконувати ці настанови у кластері, що має щонайменше два вузли, які не виконують роль вузлів управління. Якщо у вас немає кластера, ви можете створити його, за допомогою minikube або використовувати одну з цих пісочниць:
Версія вашого Kubernetes сервера має бути не старішою ніж v1.26. Для перевірки версії введітьkubectl version
.Якщо ви використовуєте старішу версію Kubernetes, будь ласка, перегляньте документацію для версії, яку ви фактично використовуєте.
Політики керування ЦП
Стандартно, kubelet використовує квоту CFS, щоб обмежувати ЦП для Podʼів. Коли вузол виконує багато Podʼів, залежних від ЦП, навантаження може переміщуватися на різні ядра ЦП залежно від того, чи обмежений Pod, і які ядра ЦП доступні на момент планування. Багато завдань не чутливі до цього переміщення і, отже, працюють нормально без будь-якого втручання.
Проте, в завданнях, де спорідненість кешу ЦП та затримка планування значно впливають на продуктивність робочого завдання, kubelet дозволяє використовувати альтернативні політики керування ЦП для визначення деяких вподобань розміщення на вузлі.
Налаштування
Політика керування ЦП встановлюється прапорцем kubelet --cpu-manager-policy
або полем cpuManagerPolicy
в KubeletConfiguration. Підтримуються дві політики:
none
: стандартна політика.static
: дозволяє контейнерам з певними характеристиками ресурсів отримувати збільшену спорідненість ЦП та ексклюзивність на вузлі.
Керування ЦП періодично записує оновлення ресурсів через CRI, щоб звести до мінімуму проблеми сумісності памʼяті та виправити їх. Частота зведення встановлюється за допомогою нового значення конфігурації Kubelet --cpu-manager-reconcile-period
. Якщо вона не вказана, стандартно вона дорівнює тому ж часу, що й --node-status-update-frequency
.
Поведінку статичної політики можна налаштувати за допомогою прапорця --cpu-manager-policy-options
. Прапорець приймає список параметрів політики у вигляді ключ=значення
. Якщо ви вимкнули функціональну можливість CPUManagerPolicyOptions
, то ви не зможете налаштувати параметри політик керування ЦП. У цьому випадку керування ЦП працюватиме лише зі своїми стандартними налаштуваннями.
Окрім верхнього рівня CPUManagerPolicyOptions
, параметри політики розділені на дві групи: якість альфа (типово прихована) та якість бета (типово видима). Відмінно від стандарту Kubernetes, ці feature gate захищають групи параметрів, оскільки було б надто складно додати feature gate для кожного окремого параметра.
Зміна політики керування ЦП
Оскільки політику керування ЦП можна застосовувати лише коли kubelet створює нові Podʼи, просте змінення з "none" на "static" не застосується до наявних Podʼів. Тому, щоб правильно змінити політику керування ЦП на вузлі, виконайте наступні кроки:
- Виведіть з експлуатації вузол.
- Зупиніть kubelet.
- Видаліть старий файл стану керування ЦП. Типовий шлях до цього файлу
/var/lib/kubelet/cpu_manager_state
. Це очищує стан, що зберігається CPUManager, щоб множини ЦП, налаштовані за новою політикою, не конфліктували з нею. - Відредагуйте конфігурацію kubelet, щоб змінити політику керування ЦП на потрібне значення.
- Запустіть kubelet.
Повторіть цей процес для кожного вузла, який потребує зміни політики керування ЦП. Пропуск цього процесу призведе до постійної аварійної роботи kubelet з такою помилкою:
could not restore state from checkpoint: configured policy "static" differs from state checkpoint policy "none", please drain this node and delete the CPU manager checkpoint file "/var/lib/kubelet/cpu_manager_state" before restarting Kubelet
Політика none
Політика none
явно активує наявну стандартну схему спорідненості ЦП, не надаючи спорідненості поза тим, що робить планувальник ОС автоматично. Обмеження на використання ЦП для Podʼів з гарантованою продуктивністю та Podʼів з бурхливою продуктивністю накладаються за допомогою квоти CFS.
Політика static
Політика static
дозволяє контейнерам у Podʼах з гарантованою продуктивністю із цілими requests
ЦП мати доступ до ексклюзивних ЦП на вузлі. Ця ексклюзивність забезпечується за допомогою контролера груп cgroup для cpuset
.
Примітка:
Системні служби, такі як середовища виконання контейнерів та сам kubelet, можуть продовжувати працювати на цих ексклюзивних ЦП. Ексклюзивність поширюється лише на інші Podʼи.Примітка:
Керування ЦП не підтримує відключення та підключення ЦП в процесі роботи. Крім того, якщо набір онлайн ЦП змінюється на вузлі, вузол повинен бути виведений з експлуатації, а керування ЦП повинно бути вручну скинуте, видаливши файл стануcpu_manager_state
в кореневій теці kubelet.Ця політика керує спільним пулом ЦП, який на початку містить всі ЦП на вузлі. Кількість ексклюзивно виділених ЦП дорівнює загальній кількості ЦП на вузлі мінус будь-які резерви ЦП за допомогою параметрів kubelet --kube-reserved
або --system-reserved
. З версії 1.17 список резервувань ЦП може бути вказаний явно за допомогою параметру kubelet --reserved-cpus
. Явний список ЦП, вказаний за допомогою --reserved-cpus
, має пріоритет над резервуванням ЦП, вказаним за допомогою --kube-reserved
та --system-reserved
. ЦП, зарезервовані цими параметрами, беруться, у цілочисельній кількості, зі спільного пулу на основі фізичного ідентифікатора ядра. Цей спільний пул — це множина ЦП, на яких працюють контейнери в Podʼах з BestEffort
та Burstable
. Контейнери у Podʼах з гарантованою продуктивністю з цілими requests
ЦП також працюють на ЦП у спільному пулі. Ексклюзивні ЦП призначаються лише контейнерам, які одночасно належать до Podʼа з гарантованою продуктивністю та мають цілочисельні requests
ЦП.
Примітка:
Kubelet потребує, щоб було зарезервовано не менше одного ЦП за допомогою параметрів--kube-reserved
і/або --system-reserved
або --reserved-cpus
, коли включена статична політика. Це тому, що нульове резервування ЦП дозволить спільному пулу стати порожнім.Коли Podʼи з гарантованою продуктивністю (Guaranteed
), чий контейнер відповідає вимогам для статичного призначення, планується на вузол, ЦП видаляються зі спільного пулу і поміщаються у cpuset для контейнера. Квота CFS не використовується для обмеження використання ЦП цих контейнерів, оскільки їх використання обмежується самою областю планування. Іншими словами, кількість ЦП у cpuset контейнера дорівнює цілому limit
ЦП, вказаному в специфікації Podʼа. Це статичне призначення підвищує спорідненість ЦП та зменшує перемикання контексту через обмеження для навантаження, залежного від ЦП.
Розгляньте контейнери в наступних специфікаціях Podʼа:
spec:
containers:
- name: nginx
image: nginx
Pod, вказаний вище, працює в класі QoS BestEffort
, оскільки не вказані requests
або limits
ресурсів. Він працює у спільному пулі.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
Pod, вказаний вище, працює в класі QoS Burstable
, оскільки requests
ресурсів не дорівнюють limits
, а кількість cpu
не вказана. Він працює у спільному пулі.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
requests:
memory: "100Mi"
cpu: "1"
Pod, вказаний вище, працює в класі QoS Burstable
, оскільки requests
ресурсів не дорівнюють limits
. Він працює у спільному пулі.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
requests:
memory: "200Mi"
cpu: "2"
Pod, вказаний вище, працює в класі QoS Guaranteed
, оскільки requests
дорівнюють limits
. І ліміт ресурсу ЦП контейнера є цілим числом більшим або рівним одиниці. Контейнер nginx
отримує 2 ексклюзивних ЦП.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "1.5"
requests:
memory: "200Mi"
cpu: "1.5"
Pod, вказаний вище, працює в класі QoS Guaranteed
, оскільки requests
дорівнюють limits
. Але ліміт ресурсу ЦП контейнера є дробовим числом. Він працює у спільному пулі.
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "2"
Pod, вказаний вище, працює в класі QoS Guaranteed
, оскільки вказані тільки limits
, а requests
встановлені рівними limits
, коли не вказано явно. І ліміт ресурсу ЦП контейнера є цілим числом більшим або рівним одиниці. Контейнер nginx
отримує 2 ексклюзивних ЦП.
Параметри політики static
Ви можете включати та виключати групи параметрів на основі їх рівня зрілості, використовуючи наступні feature gate:
CPUManagerPolicyBetaOptions
— стандартно увімкнено. Вимкніть, щоб приховати параметри рівня бета.CPUManagerPolicyAlphaOptions
— стандартно вимкнено. Увімкніть, щоб показати параметри рівня альфа. Ви все ще повинні увімкнути кожен параметр за допомогою опції kubeletCPUManagerPolicyOptions
.
Для політики static CPUManager
існують наступні параметри:
full-pcpus-only
(бета, типово видимий) (1.22 або вище)distribute-cpus-across-numa
(альфа, типово прихований) (1.23 або вище)align-by-socket
(альфа, типово прихований) (1.25 або вище)distribute-cpus-across-cores
(альфа, типово прихований) (1.31 або вище)
Якщо вказано параметр політики full-pcpus-only
, статична політика завжди виділятиме повні фізичні ядра. Стандартно, без цієї опції, статична політика розподіляє ЦП, використовуючи найкращий вибір з урахуванням топології. На системах з увімкненими SMT, політика може виділяти окремі віртуальні ядра, які відповідають апаратним потокам. Це може призвести до того, що різні контейнери будуть використовувати одні й ті ж фізичні ядра; ця поведінка, своєю чергою, спричиняє проблему шумних сусідів. З включеною опцією, Pod буде прийнятий kubelet лише в тому випадку, якщо запити на ЦП всіх його контейнерів можна задовольнити виділенням повних фізичних ядер. Якщо Pod не пройде процедуру допуску, він буде переведений в стан Failed з повідомленням SMTAlignmentError
.
Якщо вказано параметр політики distribute-cpus-across-numa
, статична політика рівномірно розподілить ЦП по вузлах NUMA у випадках, коли для задоволення розподілу необхідно більше одного вузла NUMA. Стандартно CPUManager
буде пакувати ЦП на один вузол NUMA, поки він не буде заповнений, і будь-які залишкові ЦП просто перейдуть на наступний вузол NUMA. Це може призвести до небажаних заторів у паралельному коді, що покладається на барʼєри (та подібні примітиви синхронізації), оскільки цей тип коду, як правило, працює лише так швидко, як його найповільніший робітник (який сповільнюється тим, що на одному з вузлів NUMA доступно менше ЦП). Рівномірний розподіл ЦП по вузлах NUMA дозволяє розробникам програм легше забезпечувати те, що жоден окремий робітник не страждає від ефектів NUMA більше, ніж будь-який інший, що покращує загальну продуктивність цих типів програм.
Якщо вказано параметр політики align-by-socket
, ЦП будуть вважатися вирівненими на межі сокета при вирішенні того, як розподілити ЦП між контейнерами. Стандартно, CPUManager
вирівнює виділення ЦП на межі NUMA, що може призвести до погіршання продуктивності, якщо ЦП потрібно вилучати з більш ніж одного вузла NUMA для задоволення виділення. Попри те, що він намагається забезпечити, щоб всі ЦП були виділені з мінімальної кількості вузлів NUMA, немає гарантії, що ці вузли NUMA будуть на одному сокеті. Вказуючи CPUManager
явно вирівнювати ЦП на межі сокета, а не NUMA, ми можемо уникнути таких проблем. Зауважте, що ця опція політики несумісна з політикою TopologyManager
single-numa-node
і не застосовується до апаратного забезпечення, де кількість сокетів більша, ніж кількість вузлів NUMA.
Якщо вказана опція політики distribute-cpus-across-cores
, статична політика спробує розподілити віртуальні ядра (апаратні потоки) по різних фізичних ядрах. Стандартно, CPUManager
має тенденцію запаковувати процесори на якомога меншій кількості фізичних ядер, що може призвести до конфліктів між процесорами на одному фізичному ядрі та, як наслідок, до проблем з продуктивністю. Увімкнувши політику distribute-cpus-across-cores
, статична політика забезпечує розподіл процесорів по якомога більшій кількості фізичних ядер, зменшуючи конфлікти на одному фізичному ядрі й тим самим покращуючи загальну продуктивність. Проте, важливо зазначити, що ця стратегія може бути менш ефективною, коли система сильно навантажена. За таких умов вигода від зменшення конфліктів зменшується. З іншого боку, стандартна поведінка може допомогти зменшити витрати на комунікацію між ядрами, що потенційно забезпечує кращу продуктивність при високих навантаженнях.
Параметр full-pcpus-only
можна включити, додавши full-pcpus-only=true
до параметрів політики CPUManager
. Так само параметр distribute-cpus-across-numa
можна включити, додавши distribute-cpus-across-numa=true
до параметрів політики CPUManager
. Якщо обидва встановлені, вони "адитивні" у тому сенсі, що ЦП будуть розподілені по вузлах NUMA в шматках повних фізичних ядер, а не окремих ядер. Параметр політики align-by-socket
можна увімкнути, додавши align-by-socket=true
до параметрів політики CPUManager
. Він також адитивний до параметрів політики full-pcpus-only
та distribute-cpus-across-numa
.
Опцію distribute-cpus-across-cores
можна увімкнути, додавши distribute-cpus-across-cores=true
до параметрів політики CPUManager
. Зараз її не можна використовувати разом з параметрами політики full-pcpus-only
або distribute-cpus-across-numa
.