API Priority and Fairness

API Priority and Fairness

СТАН ФУНКЦІОНАЛУ: GA since Kubernetes v1.29

Керування поведінкою API-сервера Kubernetes у ситуації перевантаження — ключове завдання адміністраторів кластера. kube-apiserver має певні засоби керування (тобто прапорці командного рядка --max-requests-inflight та --max-mutating-requests-inflight), щоб обмежити обсяг незавершеної роботи, яка приймається, запобігаючи перевантаженню й можливому збою API-сервера через потік вхідних запитів, але цих прапорців недостатньо, щоб найважливіші запити проходили в період високого навантаження.

Можливість API Priority and Fairness (APF) — це альтернатива, яка усуває згадані обмеження max-inflight. APF класифікує та ізолює запити точніше. Вона також запроваджує обмежене чергування, щоб під час дуже коротких сплесків запити не відхилялися. Запити вибираються з черг за технікою справедливого чергування, тому, наприклад, контролер, який погано поводиться, не позбавить ресурсів інші (навіть на тому самому рівні пріоритету).

Ця можливість розроблена так, щоб добре працювати зі стандартними контролерами, які використовують інформери й реагують на збої API-запитів експоненційним back-off, та з іншими клієнтами, що працюють так само.

Увага:

Деякі запити, класифіковані як «тривалі», — наприклад, віддалене виконання команд або читання кінця логів (tail), — не підпадають під фільтр API Priority and Fairness. Це також стосується прапорця --max-requests-inflight без увімкненої можливості API Priority and Fairness. API Priority and Fairness застосовується до запитів watch. Коли API Priority and Fairness вимкнено, запити watch не підпадають під обмеження --max-requests-inflight.

Увімкнення/вимкнення API Priority and Fairness

Можливість API Priority and Fairness керується прапорцем командного рядка і стандартно ввімкнена. Загальне пояснення доступних параметрів командного рядка kube-apiserver та способів їх увімкнення й вимкнення дивіться в розділі Options. Назва параметра командного рядка для APF — "--enable-priority-and-fairness". Ця можливість також використовує групу API із: (a) стабільною версією v1, запровадженою у 1.29 і стандартно ввімкненою, (b) версією v1beta3, стандартно ввімкненою і застарілою у v1.29. Ви можете вимкнути бета-версію групи API v1beta3, додавши такі прапорці командного рядка до виклику kube-apiserver:

kube-apiserver \
--runtime-config=flowcontrol.apiserver.k8s.io/v1beta3=false \
 # …і інші прапорці, як завжди

Прапорець командного рядка --enable-priority-and-fairness=false вимкне можливість API Priority and Fairness.

Рекурсивні сценарії сервера

API Priority and Fairness слід використовувати обережно в рекурсивних сценаріях сервера. Це сценарії, у яких сервер A, обробляючи запит, надсилає допоміжний запит на сервер B. Сервер B може навіть зробити ще один допоміжний виклик назад до сервера A. У ситуаціях, коли контроль Priority and Fairness застосовується як до початкового запиту, так і до деяких допоміжних, незалежно від глибини рекурсії, існує небезпека інверсії пріоритетів та/або взаємоблокувань.

Один із прикладів рекурсії — коли kube-apiserver викликає вебхук допуску на сервері B, і під час обробки цього виклику сервер B робить ще один допоміжний запит назад до kube-apiserver. Інший приклад рекурсії — коли обʼєкт APIService вказує kube-apiserver делегувати запити щодо певної групи API власному зовнішньому серверу B (це одне з того, що називають «агрегацією»).

Коли відомо, що початковий запит належить до певного рівня пріоритету, а допоміжні контрольовані запити класифікуються на вищі рівні пріоритету, це одне з можливих рішень. Коли початкові запити можуть належати до будь-якого рівня пріоритету, допоміжні контрольовані запити мають бути звільнені від обмежень Priority and Fairness. Один зі способів зробити це — обʼєкти, які налаштовують класифікацію та обробку, описані нижче. Інший спосіб — повністю вимкнути Priority and Fairness на сервері B за допомогою описаних вище прийомів. Третій спосіб, найпростіший, коли сервер B не є kube-apiserver, — зібрати сервер B із вимкненим у коді Priority and Fairness.

Концепції

Можливість API Priority and Fairness складається з кількох окремих механізмів. Вхідні запити класифікуються за атрибутами запиту за допомогою FlowSchemas і призначаються рівням пріоритету. Рівні пріоритету додають певну ізоляцію завдяки окремим обмеженням паралелізму, тому запити, призначені різним рівням пріоритету, не можуть позбавити ресурсів один одного. У межах рівня пріоритету алгоритм справедливого чергування не дозволяє запитам із різних потоків позбавляти ресурсів один одного й дозволяє ставити запити в чергу, щоб сплески трафіку не спричиняли збої запитів, коли середнє навантаження прийнятно низьке.

Рівні пріоритету

Без увімкненої APF загальний паралелізм в API-сервері обмежується прапорцями kube-apiserver --max-requests-inflight та --max-mutating-requests-inflight. З увімкненою APF обмеження паралелізму, визначені цими прапорцями, сумуються, а потім сума розподіляється між налаштовуваним набором рівнів пріоритету. Кожен вхідний запит призначається одному рівню пріоритету, і кожен рівень пріоритету запускає лише стільки одночасних запитів, скільки дозволяє його власне обмеження.

Наприклад, стандартна конфігурація містить окремі рівні пріоритету для запитів виборів лідера, запитів від вбудованих контролерів і запитів від Podʼів. Це означає, що Pod, який поводиться погано й завалює API-сервер запитами, не може завадити виборам лідера чи діям вбудованих контролерів.

Обмеження паралелізму рівнів пріоритету періодично коригуються, що дозволяє недовикористаним рівням пріоритету тимчасово надавати паралелізм рівням із високим навантаженням. Ці обмеження базуються на номінальних обмеженнях і межах того, скільки паралелізму рівень пріоритету може надати та скільки може позичити; усі вони випливають з обʼєктів конфігурації, згаданих нижче.

Місця, які займає запит

Наведений вище опис керування паралелізмом — це базова модель. Запити мають різну тривалість, але в будь-який момент рахуються однаково під час порівняння з обмеженням паралелізму рівня пріоритету. У базовій моделі кожен запит займає одну одиницю паралелізму. Слово «місце» (seat) означає одну одиницю паралелізму; його навіяло те, як кожен пасажир у поїзді чи літаку займає одне з фіксованої кількості місць.

Але деякі запити займають більше ніж одне місце. Серед них запити list, які, за оцінкою сервера, повернуть велику кількість обʼєктів. Вони виявилися надзвичайно важким навантаженням для сервера. Тому сервер оцінює кількість обʼєктів, які буде повернуто, і вважає, що запит займає кількість місць, пропорційну цій оцінці.

Коригування часу виконання для запитів watch

API Priority and Fairness керує запитами watch, але це передбачає ще кілька відступів від базової поведінки. Перший стосується того, як довго запит watch вважається таким, що займає своє місце. Залежно від параметрів запиту відповідь на запит watch може починатися або не починатися зі сповіщень create для всіх відповідних наявних обʼєктів. API Priority and Fairness вважає, що запит watch звільняє своє місце, щойно цей початковий сплеск сповіщень (якщо він є) закінчився.

Звичайні сповіщення надсилаються одночасним сплеском до всіх відповідних потоків відповідей watch, коли сервер отримує сповіщення про створення, оновлення або видалення обʼєкта. Щоб врахувати цю роботу, API Priority and Fairness вважає, що кожен запит на запис займає місця ще певний час після завершення фактичного запису. Сервер оцінює кількість сповіщень, які буде надіслано, і коригує кількість місць запиту на запис і час їх зайнятості, щоб врахувати цю додаткову роботу.

Чергування

Навіть у межах рівня пріоритету може бути велика кількість різних джерел трафіку. У ситуації перевантаження важливо не дати одному потоку запитів позбавити ресурсів інші (зокрема, у відносно поширеному випадку, коли один клієнт із помилками завалює kube-apiserver запитами, такий клієнт в ідеалі взагалі не повинен помітно впливати на інших клієнтів). Для цього використовується алгоритм справедливого чергування, який обробляє запити, призначені одному рівню пріоритету. Кожен запит призначається потоку, який визначається назвою відповідної FlowSchema та розрізнювачем потоку — це або користувач, який надіслав запит, або простір імен цільового ресурсу, або нічого, — і система намагається надати приблизно однакову вагу запитам у різних потоках одного рівня пріоритету. Щоб різні екземпляри оброблялися окремо, контролери з багатьма екземплярами мають автентифікуватися з різними іменами користувачів.

Після класифікації запиту в потік API Priority and Fairness може призначити запит до черги. Для цього використовується техніка, відома як shuffle sharding, яка досить ефективно використовує черги, щоб ізолювати потоки низької інтенсивності від потоків високої інтенсивності.

Подробиці алгоритму чергування налаштовуються для кожного рівня пріоритету й дозволяють адміністраторам балансувати використання памʼяті, справедливість (властивість, за якої незалежні потоки просуваються, коли загальний трафік перевищує місткість), стійкість до сплесків трафіку та додаткову затримку через чергування.

Звільнені запити

Деякі запити вважаються настільки важливими, що на них не поширюються жодні обмеження цієї можливості. Ці винятки запобігають тому, щоб неправильно налаштоване керування потоком повністю вивело API-сервер з ладу.

Ресурси

API керування потоком використовує два види ресурсів. PriorityLevelConfigurations визначають доступні рівні пріоритету, частку доступного бюджету паралелізму, яку кожен із них може обробити, і дозволяють точно налаштовувати поведінку черг. FlowSchemas використовуються для класифікації окремих вхідних запитів, зіставляючи кожен з однією PriorityLevelConfiguration.

PriorityLevelConfiguration

PriorityLevelConfiguration представляє один рівень пріоритету. Кожна PriorityLevelConfiguration має незалежне обмеження на кількість незавершених запитів та обмеження на кількість запитів у черзі.

Номінальне обмеження паралелізму для PriorityLevelConfiguration задається не абсолютною кількістю місць, а «номінальними частками паралелізму» (nominal concurrency shares). Загальне обмеження паралелізму API-сервера розподіляється між наявними PriorityLevelConfiguration пропорційно цим часткам, що дає кожному рівню його номінальне обмеження в місцях. Це дозволяє адміністратору кластера збільшувати або зменшувати загальний обсяг трафіку до сервера, перезапускаючи kube-apiserver з іншим значенням --max-requests-inflight (або --max-mutating-requests-inflight), і максимально дозволений паралелізм усіх PriorityLevelConfiguration зросте (або зменшиться) на ту саму частку.

Увага:

У версіях до v1beta3 відповідне поле PriorityLevelConfiguration має назву "assured concurrency shares", а не "nominal concurrency shares". Також у випуску Kubernetes 1.25 та раніших періодичних коригувань не було: номінальні/гарантовані обмеження завжди застосовувалися без коригування.

Межі того, скільки паралелізму рівень пріоритету може надати та скільки може позичити, задаються в PriorityLevelConfiguration у відсотках від номінального обмеження рівня. Вони перетворюються на абсолютні кількості місць множенням на номінальне обмеження / 100.0 та округленням. Динамічно кориговане обмеження паралелізму рівня пріоритету має лежати між (a) нижньою межею: його номінальне обмеження мінус місця, які він може надати, та (b) верхньою межею: його номінальне обмеження плюс місця, які він може позичити. Під час кожного коригування динамічні обмеження визначаються так: кожен рівень пріоритету повертає надані місця, на які нещодавно зʼявився попит, а потім усі рівні спільно й справедливо відповідають на нещодавній попит на місця в межах щойно описаних меж.

Увага:

Коли можливість Priority and Fairness увімкнено, загальне обмеження паралелізму сервера дорівнює сумі --max-requests-inflight та --max-mutating-requests-inflight. Різниці між змінювальними та незмінювальними запитами більше немає; якщо ви хочете обробляти їх окремо для певного ресурсу, створіть окремі FlowSchemas, які відповідають змінювальним і незмінювальним дієсловам відповідно.

Коли обсяг вхідних запитів, призначених одній PriorityLevelConfiguration, перевищує її дозволений рівень паралелізму, поле type її специфікації визначає, що станеться із зайвими запитами. Тип Reject означає, що зайвий трафік буде негайно відхилено з помилкою HTTP 429 (Too Many Requests). Тип Queue означає, що запити понад поріг буде поставлено в чергу, а для балансування просування між потоками запитів використовуються техніки shuffle sharding і справедливого чергування.

Конфігурація чергування дозволяє налаштувати алгоритм справедливого чергування для рівня пріоритету. Подробиці алгоритму наведено в пропозиції щодо вдосконалення, а стисло:

  • Збільшення queues зменшує частоту зіткнень між різними потоками ціною більшого використання памʼяті. Значення 1 фактично вимикає логіку справедливого чергування, але все ще дозволяє ставити запити в чергу.

  • Збільшення queueLengthLimit дозволяє витримувати більші сплески трафіку без відкидання запитів ціною більшої затримки та використання памʼяті.

  • Зміна handSize дозволяє налаштувати ймовірність зіткнень між різними потоками та загальний паралелізм, доступний одному потоку в ситуації перевантаження.

    Примітка:

    Більше значення handSize зменшує ймовірність зіткнення двох окремих потоків (а отже, того, що один позбавить ресурсів інший), але збільшує ймовірність того, що невелика кількість потоків домінуватиме в apiserver. Більше значення handSize також потенційно збільшує затримку, яку може спричинити один потік із високим трафіком. Максимальна кількість запитів у черзі від одного потоку становить handSize * queueLengthLimit.

Нижче наведено таблицю з цікавим набором конфігурацій shuffle sharding, яка для кожної показує ймовірність того, що певну мишу (потік низької інтенсивності) розчавлять слони (потоки високої інтенсивності) для ілюстративного набору кількостей слонів. Цю таблицю обчислює https://play.golang.org/p/Gi0PLgVHiUg. https://play.golang.org/p/Gi0PLgVHiUg, який обчислює цю таблицю.

Приклади конфігурацій shuffle sharding
HandSizeЧерги1 слон4 слони16 слонів
12324.428838398950118e-090.114313488300991440.9935089607656024
10321.550093439632541e-080.06264798402235450.9753101519027554
10646.601827268370426e-120.000455713209903707760.49999929150089345
9643.6310049976037345e-110.000455012123041122730.4282314876454858
8642.25929199850899e-100.00048866970530404460.35935114681123076
81286.994461389026097e-133.4055790161620863e-060.02746173137155063
71281.0579122850901972e-116.960839379258192e-060.02406157386340147
72567.597695465552631e-146.728547142019406e-080.0006709661542533682
62562.7134626662687968e-122.9516464018476436e-070.0008895654642000348
65124.116062922897309e-144.982983350480894e-092.26025764343413e-05
610246.337324016514285e-168.09060164312957e-114.517408062903668e-07

FlowSchema

FlowSchema зіставляє деякі вхідні запити й призначає їх рівню пріоритету. Кожен вхідний запит перевіряється за FlowSchemas, починаючи з тих, що мають найменше числове значення matchingPrecedence, і далі за зростанням. Перший збіг виграє.

Увага:

Для запиту має значення лише перша відповідна FlowSchema. Якщо одному вхідному запиту відповідає кілька FlowSchemas, його буде призначено на основі тієї, що має найвищий matchingPrecedence. Якщо одному запиту відповідає кілька FlowSchemas з однаковим matchingPrecedence, виграє та, що має лексикографічно менший name, але краще не покладатися на це, а подбати про те, щоб жодні дві FlowSchemas не мали однакового matchingPrecedence.

FlowSchema відповідає запиту, якщо відповідає принаймні одне з її rules. Правило відповідає, якщо запиту відповідають принаймні один з його subjects та принаймні одне з його resourceRules або nonResourceRules (залежно від того, чи вхідний запит стосується ресурсу, чи нересурсного URL).

Для поля name у субʼєктах і полів verbs, apiGroups, resources, namespaces та nonResourceURLs ресурсних і нересурсних правил можна вказати шаблон *, щоб відповідати всім значенням цього поля, фактично прибираючи його з розгляду.

Поле distinguisherMethod.type у FlowSchema визначає, як запити, що відповідають цій схемі, розділятимуться на потоки. Це може бути ByUser, за якого один користувач не зможе позбавити інших користувачів місткості; ByNamespace, за якого запити до ресурсів в одному просторі імен не зможуть позбавити місткості запити до ресурсів в інших просторах імен; або порожнє значення (або distinguisherMethod можна взагалі пропустити), за якого всі запити, що відповідають цій FlowSchema, вважаються частиною одного потоку. Правильний вибір для FlowSchema залежить від ресурсу та вашого конкретного середовища.

Стандартні налаштування

Кожен kube-apiserver підтримує два різновиди обʼєктів конфігурації APF: обовʼязкові та рекомендовані.

Обовʼязкові обʼєкти конфігурації

Чотири обовʼязкові обʼєкти конфігурації відображають фіксовану вбудовану запобіжну поведінку. Це поведінка, яку сервери мають ще до появи цих обʼєктів, а коли ці обʼєкти існують, їх специфікації відображають цю поведінку. Ось ці чотири обовʼязкові обʼєкти.

  • Обовʼязковий рівень пріоритету exempt використовується для запитів, які взагалі не підлягають керуванню потоком: вони завжди запускаються негайно. Обовʼязкова FlowSchema exempt відносить усі запити з групи system:masters до цього рівня пріоритету. За потреби ви можете визначити інші FlowSchemas, які спрямовують інші запити на цей рівень пріоритету.

  • Обовʼязковий рівень пріоритету catch-all використовується разом з обовʼязковою FlowSchema catch-all, щоб кожен запит отримав певну класифікацію. Зазвичай не варто покладатися на цю конфігурацію catch-all; натомість за потреби створіть власні FlowSchema і PriorityLevelConfiguration типу catch-all (або використовуйте рекомендований рівень пріоритету global-default, який встановлюється стандартно). Оскільки звичайно він не має використовуватися, обовʼязковий рівень пріоритету catch-all має дуже малу частку паралелізму й не ставить запити в чергу.

Рекомендовані обʼєкти конфігурації

Рекомендовані FlowSchemas і PriorityLevelConfigurations становлять розумну стандартну конфігурацію. За бажання ви можете змінювати їх та/або створювати додаткові обʼєкти конфігурації. Якщо ваш кластер може зазнавати високого навантаження, варто подумати, яка конфігурація працюватиме найкраще.

Рекомендована конфігурація групує запити в шість рівнів пріоритету:

  • Рівень пріоритету node-high призначений для оновлень справності від вузлів.

  • Рівень пріоритету system призначений для запитів, не повʼязаних зі справністю, з групи system:nodes, тобто від kubelet, які мають зʼєднуватися з API-сервером, щоб на вузлах можна було планувати робочі навантаження.

  • Рівень пріоритету leader-election призначений для запитів виборів лідера від вбудованих контролерів (зокрема, запитів до endpoints, configmaps або leases, що надходять від користувачів system:kube-controller-manager чи system:kube-scheduler і ServiceAccount у просторі імен kube-system). Ці запити важливо ізолювати від іншого трафіку, оскільки збої у виборах лідера спричиняють збої та перезапуски відповідних контролерів, а це, у свою чергу, створює дорожчий трафік, коли нові контролери синхронізують свої інформери.

  • Рівень пріоритету workload-high призначений для інших запитів від вбудованих контролерів.

  • Рівень пріоритету workload-low призначений для запитів від будь-якого іншого ServiceAccount, що зазвичай охоплює всі запити від контролерів, які працюють у Podʼах.

  • Рівень пріоритету global-default обробляє весь інший трафік, наприклад, інтерактивні команди kubectl, запущені непривілейованими користувачами.

Рекомендовані FlowSchemas спрямовують запити на наведені вище рівні пріоритету, і тут вони не перелічені.

Підтримка обовʼязкових і рекомендованих обʼєктів конфігурації

Кожен kube-apiserver незалежно підтримує обовʼязкові та рекомендовані обʼєкти конфігурації, виконуючи початкову й періодичну обробку. Тому в ситуації із сумішшю серверів різних версій можливе постійне перезаписування (thrashing), доки різні сервери мають різні уявлення про правильний вміст цих обʼєктів.

Кожен kube-apiserver виконує початковий прохід підтримки обовʼязкових і рекомендованих обʼєктів конфігурації, а потім періодично (раз на хвилину) підтримує ці обʼєкти.

Для обовʼязкових обʼєктів конфігурації підтримка полягає в тому, щоб обʼєкт існував і, якщо існує, мав правильну специфікацію. Сервер не дозволяє створення чи оновлення зі специфікацією, яка не узгоджується із запобіжною поведінкою сервера.

Підтримка рекомендованих обʼєктів конфігурації розрахована на те, що їх специфікації можна перевизначати. Видалення, натомість, не враховується: підтримка відновить обʼєкт. Якщо рекомендований обʼєкт конфігурації вам не потрібен, його слід залишити, але задати специфікацію з мінімальними наслідками. Підтримка рекомендованих обʼєктів також розрахована на автоматичну міграцію під час розгортання нової версії kube-apiserver, хоча, можливо, з постійним перезаписуванням, доки працюють сервери різних версій.

Підтримка рекомендованого обʼєкта конфігурації полягає в його створенні зі специфікацією, рекомендованою сервером, якщо обʼєкт не існує. Якщо ж обʼєкт уже існує, поведінка підтримки залежить від того, хто контролює обʼєкт: kube-apiservers чи користувачі. У першому випадку сервер стежить, щоб специфікація обʼєкта відповідала рекомендованій сервером; у другому специфікація залишається без змін.

Щоб зʼясувати, хто контролює обʼєкт, спочатку шукається анотація з ключем apf.kubernetes.io/autoupdate-spec. Якщо така анотація є і її значення true, обʼєкт контролюють kube-apiservers. Якщо така анотація є і її значення false, обʼєкт контролюють користувачі. Якщо жодна з цих умов не виконується, перевіряється metadata.generation обʼєкта. Якщо воно дорівнює 1, обʼєкт контролюють kube-apiservers. Інакше обʼєкт контролюють користувачі. Ці правила запроваджено у випуску 1.22, а врахування metadata.generation потрібне для міграції з простішої попередньої поведінки. Користувачі, які хочуть контролювати рекомендований обʼєкт конфігурації, мають встановити його анотацію apf.kubernetes.io/autoupdate-spec у false.

Підтримка обовʼязкового або рекомендованого обʼєкта конфігурації також включає забезпечення наявності анотації apf.kubernetes.io/autoupdate-spec, яка точно відображає, чи контролюють обʼєкт kube-apiservers.

Підтримка також включає видалення обʼєктів, які не є ні обовʼязковими, ні рекомендованими, але мають анотацію apf.kubernetes.io/autoupdate-spec=true.

Звільнення перевірок справності від обмежень паралелізму

Рекомендована конфігурація не передбачає особливої обробки запитів перевірки справності до kube-apiservers від їхніх локальних kubelet, які зазвичай використовують захищений порт, але не надають облікових даних. За рекомендованої конфігурації ці запити призначаються FlowSchema global-default і відповідному рівню пріоритету global-default, де інший трафік може їх витіснити.

Якщо ви додасте наведену нижче додаткову FlowSchema, ці запити буде звільнено від обмеження частоти.

Увага:

Ця зміна також дозволяє будь-якому зловмиснику надсилати запити перевірки справності, що відповідають цій FlowSchema, у будь-якому обсязі. Якщо у вас є фільтр вебтрафіку або подібний зовнішній механізм безпеки для захисту API-сервера кластера від загального інтернет-трафіку, ви можете налаштувати правила блокування запитів перевірки справності, що надходять ззовні кластера.
apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
  name: health-for-strangers
spec:
  matchingPrecedence: 1000
  priorityLevelConfiguration:
    name: exempt
  rules:
    - nonResourceRules:
      - nonResourceURLs:
          - "/healthz"
          - "/livez"
          - "/readyz"
        verbs:
          - "*"
      subjects:
        - kind: Group
          group:
            name: "system:unauthenticated"

Спостережуваність

Метрики

Примітка:

У версіях Kubernetes до v1.20 мітки flow_schema та priority_level мали неузгоджені назви flowSchema та priorityLevel відповідно. Якщо ви використовуєте Kubernetes v1.19 або раніші версії, дивіться документацію для вашої версії.

Коли ви вмикаєте можливість API Priority and Fairness, kube-apiserver експортує додаткові метрики. Їх моніторинг допоможе визначити, чи не обмежує ваша конфігурація неналежним чином важливий трафік, або знайти робочі навантаження, які погано поводяться й можуть шкодити справності системи.

Рівень зрілості BETA

  • apiserver_flowcontrol_rejected_requests_total — це вектор лічильників (накопичувальний від запуску сервера) відхилених запитів із розбивкою за мітками flow_schema (вказує FlowSchema, що відповідала запиту), priority_level (вказує рівень, якому призначено запит) і reason. Мітка reason має одне з таких значень:

    • queue-full — у черзі вже забагато запитів.
    • concurrency-limit — PriorityLevelConfiguration налаштовано відхиляти зайві запити, а не ставити їх у чергу.
    • time-out — запит усе ще був у черзі, коли сплив граничний час перебування в черзі.
    • cancelled — запит не заблоковано від очищення (purge locked), і його вилучено з черги.
  • apiserver_flowcontrol_dispatched_requests_total — це вектор лічильників (накопичувальний від запуску сервера) запитів, які почали виконуватися, з розбивкою за flow_schema та priority_level.

  • apiserver_flowcontrol_current_inqueue_requests — це вектор gauge із миттєвою кількістю запитів у черзі (що не виконуються) з розбивкою за priority_level та flow_schema.

  • apiserver_flowcontrol_current_executing_requests — це вектор gauge із миттєвою кількістю виконуваних запитів (що не чекають у черзі) з розбивкою за priority_level та flow_schema.

  • apiserver_flowcontrol_current_executing_seats — це вектор gauge із миттєвою кількістю зайнятих місць з розбивкою за priority_level та flow_schema.

  • apiserver_flowcontrol_request_wait_duration_seconds — це вектор гістограм часу перебування запитів у черзі з розбивкою за мітками flow_schema, priority_level та execute. Мітка execute вказує, чи почалося виконання запиту.

    Примітка:

    Оскільки кожна FlowSchema завжди призначає запити одній PriorityLevelConfiguration, ви можете додати гістограми всіх FlowSchemas одного рівня пріоритету, щоб отримати ефективну гістограму для запитів, призначених цьому рівню пріоритету.
  • apiserver_flowcontrol_nominal_limit_seats — це вектор gauge із номінальним обмеженням паралелізму кожного рівня пріоритету, обчисленим із загального обмеження паралелізму API-сервера та налаштованих номінальних часток паралелізму рівня пріоритету.

Рівень зрілості ALPHA

  • apiserver_current_inqueue_requests — це вектор gauge нещодавніх пікових значень кількості запитів у черзі, згрупованих за міткою request_kind, значення якої — mutating або readOnly. Ці пікові значення описують найбільше число, зафіксоване в щойно завершеному односекундному вікні. Вони доповнюють старіший вектор gauge apiserver_current_inflight_requests, який містить пікове значення кількості запитів, що активно обслуговуються, за останнє вікно.

  • apiserver_current_inqueue_seats — це вектор gauge із сумою за запитами в черзі найбільшої кількості місць, яку займе кожен із них, згрупованою за мітками flow_schema та priority_level.

  • apiserver_flowcontrol_read_vs_write_current_requests — це вектор гістограм спостережень, зроблених наприкінці кожної наносекунди, кількості запитів із розбивкою за мітками phase (значення waiting та executing) та request_kind (значення mutating та readOnly). Кожне спостережуване значення — це відношення (від 0 до 1) кількості запитів до відповідного обмеження кількості запитів (обмеження обсягу черги для очікування та обмеження паралелізму для виконання).

  • apiserver_flowcontrol_request_concurrency_in_use — це вектор gauge із миттєвою кількістю зайнятих місць з розбивкою за priority_level та flow_schema.

  • apiserver_flowcontrol_priority_level_request_utilization — це вектор гістограм спостережень, зроблених наприкінці кожної наносекунди, кількості запитів із розбивкою за мітками phase (значення waiting та executing) та priority_level. Кожне спостережуване значення — це відношення (від 0 до 1) кількості запитів до відповідного обмеження кількості запитів (обмеження обсягу черги для очікування та обмеження паралелізму для виконання).

  • apiserver_flowcontrol_priority_level_seat_utilization — це вектор гістограм спостережень, зроблених наприкінці кожної наносекунди, використання обмеження паралелізму рівня пріоритету з розбивкою за priority_level. Це використання — частка (кількість зайнятих місць) / (обмеження паралелізму). Ця метрика враховує всі етапи виконання (як звичайний, так і додаткову затримку наприкінці запису для відповідної роботи зі сповіщеннями) усіх запитів, крім WATCH; для них вона враховує лише початковий етап, на якому доставляються сповіщення про наявні обʼєкти. Кожна гістограма у векторі також має мітку phase: executing (для фази очікування обмеження місць немає).

  • apiserver_flowcontrol_request_queue_length_after_enqueue — це вектор гістограм довжини черг із розбивкою за priority_level та flow_schema, вибірку для якого становлять запити, поставлені в чергу. Кожен запит, що потрапляє в чергу, додає до своєї гістограми один зразок — довжину черги одразу після додавання запиту. Зверніть увагу, що це дає іншу статистику, ніж неупереджене опитування.

    Примітка:

    Викид у гістограмі тут означає, що, ймовірно, один потік (тобто запити одного користувача або для одного простору імен, залежно від конфігурації) завалює API-сервер запитами й зазнає тротлінгу. Якщо ж гістограма одного рівня пріоритету показує, що всі черги цього рівня довші, ніж на інших рівнях, може бути доцільно збільшити частки паралелізму цієї PriorityLevelConfiguration.
  • apiserver_flowcontrol_request_concurrency_limit — те саме, що й apiserver_flowcontrol_nominal_limit_seats. До запровадження позичання паралелізму між рівнями пріоритету ця метрика завжди дорівнювала apiserver_flowcontrol_current_limit_seats (якої не існувало як окремої метрики).

  • apiserver_flowcontrol_lower_limit_seats — це вектор gauge із нижньою межею динамічного обмеження паралелізму кожного рівня пріоритету.

  • apiserver_flowcontrol_upper_limit_seats — це вектор gauge із верхньою межею динамічного обмеження паралелізму кожного рівня пріоритету.

  • apiserver_flowcontrol_demand_seats — це вектор гістограм, що підраховує спостереження наприкінці кожної наносекунди відношення (попит на місця) / (номінальне обмеження паралелізму) для кожного рівня пріоритету. Попит на місця рівня пріоритету — це сума за запитами в черзі та запитами в початковій фазі виконання максимальної кількості місць, зайнятих у початковій і кінцевій фазах виконання запиту.

  • apiserver_flowcontrol_demand_seats_high_watermark — це вектор gauge із максимальним попитом на місця для кожного рівня пріоритету за останній період коригування позичання паралелізму.

  • apiserver_flowcontrol_demand_seats_average — це вектор gauge із середнім за часом попитом на місця для кожного рівня пріоритету за останній період коригування позичання паралелізму.

  • apiserver_flowcontrol_demand_seats_stdev — це вектор gauge зі зваженим за часом стандартним відхиленням генеральної сукупності попиту на місця для кожного рівня пріоритету за останній період коригування позичання паралелізму.

  • apiserver_flowcontrol_demand_seats_smoothed — це вектор gauge зі згладженим обвідним попитом на місця для кожного рівня пріоритету, визначеним під час останнього коригування паралелізму.

  • apiserver_flowcontrol_target_seats — це вектор gauge із цільовим значенням паралелізму для кожного рівня пріоритету, яке використовується в задачі розподілу позичання.

  • apiserver_flowcontrol_seat_fair_frac — це gauge із часткою справедливого розподілу, визначеною під час останнього коригування позичання.

  • apiserver_flowcontrol_current_limit_seats — це вектор gauge із динамічним обмеженням паралелізму для кожного рівня пріоритету, визначеним під час останнього коригування.

  • apiserver_flowcontrol_request_execution_seconds — це вектор гістограм фактичного часу виконання запитів з розбивкою за flow_schema та priority_level.

  • apiserver_flowcontrol_watch_count_samples — це вектор гістограм кількості активних запитів WATCH, що стосуються певного запису, з розбивкою за flow_schema та priority_level.

  • apiserver_flowcontrol_work_estimated_seats — це вектор гістограм оціненої кількості місць (максимум для початкової та кінцевої стадій виконання), повʼязаних із запитами, з розбивкою за flow_schema та priority_level.

  • apiserver_flowcontrol_request_dispatch_no_accommodation_total — це вектор лічильників кількості подій, які в принципі могли привести до запуску запиту, але не привели через брак доступного паралелізму, з розбивкою за flow_schema та priority_level.

  • apiserver_flowcontrol_epoch_advance_total — це вектор лічильників кількості спроб перевести лічильник прогресу рівня пріоритету назад, щоб уникнути числового переповнення, згрупований за priority_level та success.

Рекомендації щодо використання API Priority and Fairness

Коли певний рівень пріоритету перевищує дозволений паралелізм, запити можуть зазнавати більшої затримки або відкидатися з помилкою HTTP 429 (Too Many Requests). Щоб запобігти цим побічним ефектам APF, ви можете змінити робоче навантаження або скоригувати налаштування APF так, щоб місць для обслуговування ваших запитів було достатньо.

Щоб виявити, чи відкидаються запити через APF, перевірте такі метрики:

  • apiserver_flowcontrol_rejected_requests_total — загальна кількість відхилених запитів за FlowSchema та PriorityLevelConfiguration.
  • apiserver_flowcontrol_current_inqueue_requests — поточна кількість запитів у черзі за FlowSchema та PriorityLevelConfiguration.
  • apiserver_flowcontrol_request_wait_duration_seconds — затримка, додана до запитів, що очікують у черзі.
  • apiserver_flowcontrol_priority_level_seat_utilization — використання місць за PriorityLevelConfiguration.

Зміни робочого навантаження

Щоб запити не ставилися в чергу, не отримували додаткової затримки й не відкидалися через APF, ви можете оптимізувати їх так:

  • Зменшуйте швидкість виконання запитів. Менша кількість запитів за фіксований період означає, що в певний момент часу потрібно менше місць.
  • Уникайте одночасного надсилання великої кількості дорогих запитів. Запити можна оптимізувати так, щоб вони використовували менше місць або мали меншу затримку й утримували ці місця коротше. Запити list можуть займати більше 1 місця залежно від кількості обʼєктів, отриманих під час запиту. Обмеження кількості обʼєктів, що повертаються в запиті list, наприклад за допомогою поділу на сторінки (pagination), використовуватиме менше місць загалом за коротший період. Крім того, заміна запитів list запитами watch потребуватиме менших загальних часток паралелізму, оскільки запити watch займають лише 1 місце під час початкового сплеску сповіщень. Якщо використовуються потокові списки у версіях 1.27 і новіших, запити watch займатимуть під час початкового сплеску сповіщень стільки ж місць, скільки запит list, оскільки потрібно передати весь стан колекції. Зверніть увагу, що в обох випадках запит watch не утримує місць після цієї початкової фази.

Памʼятайте, що чергування чи відхилення запитів через APF може спричинити як збільшення кількості запитів, так і збільшення затримки наявних запитів. Наприклад, якщо запити, які зазвичай виконуються за 1 с, починають виконуватися за 60 с, APF може почати відхиляти запити, оскільки через цю затримку вони займають місця довше, ніж зазвичай. Якщо APF починає відхиляти запити на кількох рівнях пріоритету без значної зміни робочого навантаження, можливо, проблема в продуктивності панелі управління, а не в робочому навантаженні чи налаштуваннях APF.

Налаштування Priority and Fairness

Ви також можете змінити стандартні обʼєкти FlowSchema та PriorityLevelConfiguration або створити нові обʼєкти цих видів, щоб краще пристосувати їх до вашого робочого навантаження.

Налаштування APF можна змінити, щоб:

  • Надати більше місць запитам високого пріоритету.
  • Ізолювати необовʼязкові або дорогі запити, які вичерпали б рівень паралелізму, якби він був спільним з іншими потоками.

Надайте більше місць запитам високого пріоритету

  1. За можливості кількість місць, доступних на всіх рівнях пріоритету конкретного kube-apiserver, можна збільшити, збільшивши значення прапорців max-requests-inflight та max-mutating-requests-inflight. Іншим варіантом є горизонтальне масштабування кількості екземплярів kube-apiserver, що збільшить загальний паралелізм на рівень пріоритету в усьому кластері за умови достатнього балансування навантаження запитів.
  2. Ви можете створити нову FlowSchema, яка посилається на PriorityLevelConfiguration з більшим рівнем паралелізму. Ця PriorityLevelConfiguration може бути наявним або новим рівнем із власним набором номінальних часток паралелізму. Наприклад, можна додати нову FlowSchema, щоб змінити PriorityLevelConfiguration для ваших запитів із global-default на workload-low і збільшити кількість місць, доступних вашому користувачу. Створення нової PriorityLevelConfiguration зменшить кількість місць, призначених наявним рівням. Нагадаємо, що редагування стандартної FlowSchema або PriorityLevelConfiguration потребує встановлення анотації apf.kubernetes.io/autoupdate-spec у false.
  3. Ви також можете збільшити NominalConcurrencyShares для PriorityLevelConfiguration, яка обслуговує ваші запити високого пріоритету. Або, для версій 1.26 і новіших, можна збільшити LendablePercent для конкурентних рівнів пріоритету, щоб цей рівень пріоритету мав більший пул місць, які він може позичати.

Ізолюйте необовʼязкові запити, щоб вони не позбавляли ресурсів інші потоки

Для ізоляції запитів ви можете створити FlowSchema, субʼєкт якої відповідає користувачу, що надсилає ці запити, або FlowSchema, що відповідає змісту запиту (відповідно до resourceRules). Далі цю FlowSchema можна зіставити з PriorityLevelConfiguration з малою часткою місць.

Наприклад, припустімо, що запити list для подій від Podʼів у просторі імен default використовують по 10 місць кожен і виконуються протягом 1 хвилини. Щоб ці дорогі запити не впливали на запити інших Podʼів, які використовують наявну FlowSchema service-accounts, можна застосувати наведену нижче FlowSchema, щоб ізолювати ці виклики list від інших запитів.

Приклад обʼєкта FlowSchema для ізоляції запитів list для подій:

apiVersion: flowcontrol.apiserver.k8s.io/v1
kind: FlowSchema
metadata:
  name: list-events-default-service-account
spec:
  distinguisherMethod:
    type: ByUser
  matchingPrecedence: 8000
  priorityLevelConfiguration:
    name: catch-all
  rules:
    - resourceRules:
      - apiGroups:
          - '*'
        namespaces:
          - default
        resources:
          - events
        verbs:
          - list
      subjects:
        - kind: ServiceAccount
          serviceAccount:
            name: default
            namespace: default
  • Ця FlowSchema охоплює всі виклики list для подій, виконані стандартним ServiceAccount у просторі імен default. Пріоритет відповідності 8000 менший за значення 9000, яке використовує наявна FlowSchema service-accounts, тому ці виклики list для подій відповідатимуть list-events-default-service-account, а не service-accounts.
  • Для ізоляції цих запитів використовується PriorityLevelConfiguration catch-all. Рівень пріоритету catch-all має дуже малу частку паралелізму й не ставить запити в чергу.

Що далі

Змінено November 02, 2026 at 7:59 AM PST: [uk] Add cluster-administration/flow-control.md (79c0f5aafb)