Mga limitasyon ng CPU at agresibong throttling sa Kubernetes

Tandaan. transl.: Ang kasaysayang nagbubukas ng mata ng Omioβ€”isang European travel aggregatorβ€”ay dinadala ang mga mambabasa mula sa pangunahing teorya hanggang sa mga kaakit-akit na praktikal na intricacies ng configuration ng Kubernetes. Ang pagiging pamilyar sa mga ganitong kaso ay nakakatulong hindi lamang na palawakin ang iyong mga abot-tanaw, ngunit maiwasan din ang mga di-maliit na problema.

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes

Nagkaroon ka na ba ng aplikasyon na natigil sa lugar, huminto sa pagtugon sa mga pagsusuri sa kalusugan, at hindi mo alam kung bakit? Ang isang posibleng paliwanag ay nauugnay sa mga limitasyon sa quota ng mapagkukunan ng CPU. Ito ang pag-uusapan natin sa artikulong ito.

TL; DR:
Lubos naming inirerekomendang i-disable ang mga limitasyon ng CPU sa Kubernetes (o i-disable ang mga CFS quota sa Kubelet) kung gumagamit ka ng bersyon ng Linux kernel na may CFS quota bug. Sa kaibuturan magagamit seryoso at kilalang kilala isang bug na humahantong sa sobrang throttling at pagkaantala
.

Sa Omio ang buong imprastraktura ay pinamamahalaan ng Kubernetes. Ang lahat ng aming stateful at stateless na workload ay eksklusibong tumatakbo sa Kubernetes (ginagamit namin ang Google Kubernetes Engine). Sa nakalipas na anim na buwan, nagsimula kaming makakita ng mga random na paghina. Ang mga application ay nag-freeze o huminto sa pagtugon sa mga pagsusuri sa kalusugan, nawalan ng koneksyon sa network, atbp. Ang pag-uugaling ito ay naging palaisipan sa amin sa mahabang panahon, at sa wakas ay nagpasya kaming seryosohin ang problema.

Buod ng artikulo:

  • Ilang salita tungkol sa mga lalagyan at Kubernetes;
  • Paano ipinapatupad ang mga kahilingan at limitasyon ng CPU;
  • Paano gumagana ang limitasyon ng CPU sa mga multi-core na kapaligiran;
  • Paano subaybayan ang CPU throttling;
  • Solusyon sa problema at mga nuances.

Ilang salita tungkol sa mga container at Kubernetes

Ang Kubernetes ay mahalagang modernong pamantayan sa mundo ng imprastraktura. Ang pangunahing gawain nito ay ang orkestra ng lalagyan.

Mga lalagyan

Noong nakaraan, kailangan naming gumawa ng mga artifact tulad ng Java JARs/WARs, Python Eggs, o mga executable para tumakbo sa mga server. Gayunpaman, upang gumana ang mga ito, kailangang gumawa ng karagdagang trabaho: pag-install ng runtime environment (Java/Python), paglalagay ng mga kinakailangang file sa mga tamang lugar, pagtiyak ng pagiging tugma sa isang partikular na bersyon ng operating system, atbp. Sa madaling salita, kailangang bigyan ng maingat na pansin ang pamamahala ng pagsasaayos (na kadalasang pinagmumulan ng pagtatalo sa pagitan ng mga developer at mga administrator ng system).

Binago ng mga lalagyan ang lahat. Ngayon ang artifact ay isang lalagyan na imahe. Maaari itong katawanin bilang isang uri ng pinalawig na maipapatupad na file na naglalaman hindi lamang ng programa, kundi pati na rin ng isang ganap na kapaligiran sa pagpapatupad (Java/Python/...), pati na rin ang mga kinakailangang file/package, na na-pre-install at handa nang gamitin. tumakbo. Maaaring i-deploy at patakbuhin ang mga container sa iba't ibang server nang walang anumang karagdagang hakbang.

Bilang karagdagan, ang mga lalagyan ay tumatakbo sa kanilang sariling sandbox na kapaligiran. Mayroon silang sariling virtual network adapter, sariling file system na may limitadong pag-access, sariling hierarchy ng mga proseso, sariling limitasyon sa CPU at memorya, atbp. Ang lahat ng ito ay ipinatupad salamat sa isang espesyal na subsystem ng Linux kernel - namespaces.

Kubernetes

Gaya ng nasabi kanina, ang Kubernetes ay isang container orchestrator. Ito ay gumagana tulad nito: bibigyan mo ito ng isang pool ng mga machine, at pagkatapos ay sabihin: "Hey, Kubernetes, ilunsad natin ang sampung instance ng aking container na may 2 processor at 3 GB ng memory bawat isa, at panatilihing tumatakbo ang mga ito!" Kubernetes na ang bahala sa iba. Makakakita ito ng libreng kapasidad, maglulunsad ng mga container at i-restart ang mga ito kung kinakailangan, maglalabas ng mga update kapag nagbabago ng mga bersyon, atbp. Sa pangkalahatan, binibigyang-daan ka ng Kubernetes na alisin ang bahagi ng hardware at gumawa ng malawak na uri ng mga system na angkop para sa pag-deploy at pagpapatakbo ng mga application.

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Kubernetes mula sa pananaw ng karaniwang tao

Ano ang mga kahilingan at limitasyon sa Kubernetes

Okay, natakpan na namin ang mga container at Kubernetes. Alam din namin na maraming lalagyan ang maaaring manirahan sa iisang makina.

Ang isang pagkakatulad ay maaaring iguguhit sa isang komunal na apartment. Ang isang maluwag na lugar (mga makina/unit) ay kinuha at inuupahan sa ilang mga nangungupahan (mga lalagyan). Kubernetes ay gumaganap bilang isang rieltor. Ang tanong ay arises, kung paano panatilihin ang mga nangungupahan mula sa mga salungatan sa bawat isa? Paano kung ang isa sa kanila, sabihin, ay nagpasya na humiram ng banyo para sa kalahating araw?

Dito pumapasok ang mga kahilingan at limitasyon. CPU Hiling kailangan lamang para sa mga layunin ng pagpaplano. Ito ay tulad ng isang "listahan ng nais" ng lalagyan, at ginagamit ito upang piliin ang pinakaangkop na node. Kasabay nito ang CPU Limitasyon maihahambing sa isang kasunduan sa pag-upa - sa sandaling pumili kami ng isang unit para sa lalagyan, ang hindi pwede lumampas sa itinakdang limitasyon. At dito lumalabas ang problema...

Paano ipinapatupad ang mga kahilingan at limitasyon sa Kubernetes

Gumagamit ang Kubernetes ng throttling mechanism (paglaktaw sa mga cycle ng orasan) na binuo sa kernel para ipatupad ang mga limitasyon ng CPU. Kung ang isang application ay lumampas sa limitasyon, ang throttling ay pinagana (ibig sabihin, nakakatanggap ito ng mas kaunting mga cycle ng CPU). Iba ang pagkakaayos ng mga kahilingan at limitasyon para sa memorya, kaya mas madaling matukoy ang mga ito. Upang gawin ito, tingnan lamang ang huling restart status ng pod: kung ito ay "OOMKilled". Ang CPU throttling ay hindi gaanong simple, dahil ginagawa lang ng K8s na available ang mga sukatan sa pamamagitan ng paggamit, hindi ng mga cgroup.

Kahilingan sa CPU

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Paano ipinapatupad ang kahilingan sa CPU

Para sa pagiging simple, tingnan natin ang proseso gamit ang isang makina na may 4-core na CPU bilang isang halimbawa.

Gumagamit ang K8s ng mekanismo ng control group (cgroups) upang kontrolin ang paglalaan ng mga mapagkukunan (memory at processor). Ang isang hierarchical na modelo ay magagamit para dito: ang bata ay nagmamana ng mga limitasyon ng pangkat ng magulang. Ang mga detalye ng pamamahagi ay naka-imbak sa isang virtual na file system (/sys/fs/cgroup). Sa kaso ng isang processor ito ay /sys/fs/cgroup/cpu,cpuacct/*.

Gumagamit ng file ang K8s cpu.share upang maglaan ng mga mapagkukunan ng processor. Sa aming kaso, ang root cgroup ay nakakakuha ng 4096 shares ng CPU resources - 100% ng available na processor power (1 core = 1024; ito ay isang fixed value). Ang root group ay namamahagi ng mga mapagkukunan nang proporsyonal depende sa mga bahagi ng mga inapo na nakarehistro cpu.share, at sila naman ay gumagawa ng ganoon sa kanilang mga inapo, atbp. Sa karaniwang Kubernetes node, ang root cgroup ay may tatlong anak: system.slice, user.slice ΠΈ kubepods. Ang unang dalawang subgroup ay ginagamit upang ipamahagi ang mga mapagkukunan sa pagitan ng mga kritikal na pag-load ng system at mga program ng user sa labas ng K8s. Huli - kubepods β€” nilikha ng Kubernetes upang ipamahagi ang mga mapagkukunan sa pagitan ng mga pod.

Ang diagram sa itaas ay nagpapakita na ang una at pangalawang subgroup ay nakatanggap ng bawat isa 1024 pagbabahagi, kasama ang subgroup ng kuberpod na inilaan 4096 pagbabahagi Paano ito posible: pagkatapos ng lahat, ang root group ay may access lamang sa 4096 pagbabahagi, at ang kabuuan ng mga bahagi ng kanyang mga inapo ay higit na lumampas sa bilang na ito (6144)? Ang punto ay ang halaga ay may lohikal na kahulugan, kaya ginagamit ito ng Linux scheduler (CFS) upang proporsyonal na maglaan ng mga mapagkukunan ng CPU. Sa aming kaso, ang unang dalawang grupo ay tumatanggap 680 tunay na pagbabahagi (16,6% ng 4096), at tinatanggap ng kubepod ang natitira 2736 pagbabahagi Sa kaso ng downtime, hindi gagamitin ng unang dalawang grupo ang mga inilalaang mapagkukunan.

Sa kabutihang palad, ang scheduler ay may mekanismo upang maiwasan ang pag-aaksaya ng hindi nagamit na mapagkukunan ng CPU. Inililipat nito ang "idle" na kapasidad sa isang pandaigdigang pool, kung saan ito ay ipinamamahagi sa mga grupo na nangangailangan ng karagdagang kapangyarihan ng processor (ang paglipat ay nangyayari sa mga batch upang maiwasan ang pag-ikot ng mga pagkalugi). Ang isang katulad na pamamaraan ay inilalapat sa lahat ng mga inapo ng mga inapo.

Tinitiyak ng mekanismong ito ang isang patas na pamamahagi ng kapangyarihan ng processor at tinitiyak na walang sinumang nagproseso ng "nagnanakaw" ng mga mapagkukunan mula sa iba.

Limitasyon ng CPU

Sa kabila ng katotohanan na ang mga pagsasaayos ng mga limitasyon at mga kahilingan sa K8 ay mukhang magkatulad, ang kanilang pagpapatupad ay lubhang naiiba: ito pinaka-nakaliligaw at ang pinakakaunting dokumentado na bahagi.

Nakikipag-ugnayan ang K8s mekanismo ng quota ng CFS upang ipatupad ang mga limitasyon. Ang kanilang mga setting ay tinukoy sa mga file cfs_period_us ΠΈ cfs_quota_us sa direktoryo ng cgroup (ang file ay matatagpuan din doon cpu.share).

Hindi katulad cpu.share, nakabatay ang quota sa panahon, at wala sa magagamit na kapangyarihan ng processor. cfs_period_us tumutukoy sa tagal ng panahon (panahon) - ito ay palaging 100000 ΞΌs (100 ms). May opsyong baguhin ang value na ito sa K8s, ngunit available lang ito sa alpha sa ngayon. Ginagamit ng scheduler ang panahon para i-restart ang mga ginamit na quota. Pangalawang file cfs_quota_us, ay tumutukoy sa magagamit na oras (quota) sa bawat panahon. Tandaan na ito ay tinukoy din sa microseconds. Maaaring lumampas ang quota sa haba ng panahon; sa madaling salita, ito ay maaaring higit sa 100 ms.

Tingnan natin ang dalawang senaryo sa 16-core na makina (ang pinakakaraniwang uri ng computer na mayroon tayo sa Omio):

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Scenario 1: 2 thread at 200 ms na limitasyon. Walang throttling

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Scenario 2: 10 thread at 200 ms na limitasyon. Magsisimula ang throttling pagkatapos ng 20 ms, ang pag-access sa mga mapagkukunan ng processor ay magpapatuloy pagkatapos ng isa pang 80 ms

Sabihin nating itinakda mo ang limitasyon ng CPU sa 2 butil; Isasalin ng Kubernetes ang halagang ito sa 200 ms. Nangangahulugan ito na ang lalagyan ay maaaring gumamit ng maximum na 200ms ng oras ng CPU nang walang throttling.

At dito na magsisimula ang saya. Gaya ng nabanggit sa itaas, ang available na quota ay 200 ms. Kung nagtatrabaho ka sa parallel sampu mga thread sa isang 12-core na makina (tingnan ang ilustrasyon para sa senaryo 2), habang ang lahat ng iba pang mga pod ay idle, ang quota ay mauubos sa loob lamang ng 20 ms (mula noong 10 * 20 ms = 200 ms), at lahat ng mga thread ng pod na ito ay mag-hang Β» (throttle) para sa susunod na 80 ms. Ang nabanggit na bug ng scheduler, dahil sa kung saan nangyayari ang labis na throttling at hindi man lang matugunan ng container ang kasalukuyang quota.

Paano suriin ang throttling sa mga pod?

Mag-login lang sa pod at i-execute cat /sys/fs/cgroup/cpu/cpu.stat.

  • nr_periods β€” ang kabuuang bilang ng mga panahon ng scheduler;
  • nr_throttled β€” bilang ng mga throttled period sa komposisyon nr_periods;
  • throttled_time β€” pinagsama-samang oras ng throttled sa nanoseconds.

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes

Ano ba talaga ang nangyayari?

Bilang resulta, nakakakuha kami ng mataas na throttling sa lahat ng application. Minsan siya ay pumasok isa't kalahating beses mas malakas kaysa sa inaasahan!

Ito ay humahantong sa iba't ibang mga error - mga pagkabigo sa pagsusuri sa kahandaan, pag-freeze ng lalagyan, mga break ng koneksyon sa network, mga timeout sa loob ng mga tawag sa serbisyo. Sa huli, nagreresulta ito sa tumaas na latency at mas mataas na rate ng error.

Desisyon at kahihinatnan

Simple lang ang lahat dito. Inabandona namin ang mga limitasyon ng CPU at sinimulan naming i-update ang OS kernel sa mga cluster sa pinakabagong bersyon, kung saan naayos ang bug. Ang bilang ng mga error (HTTP 5xx) sa aming mga serbisyo ay agad na bumaba nang malaki:

Mga error sa HTTP 5xx

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Mga error sa HTTP 5xx para sa isang kritikal na serbisyo

Oras ng pagtugon p95

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Latensi ng kahilingan sa kritikal na serbisyo, 95th percentile

Mga gastos sa pagpapatakbo

Mga limitasyon ng CPU at agresibong throttling sa Kubernetes
Bilang ng mga instance na oras na ginugol

Ano ang mahuli?

Tulad ng sinabi sa simula ng artikulo:

Ang isang pagkakatulad ay maaaring iguhit sa isang komunal na apartment... Kubernetes ay kumikilos bilang isang rieltor. Ngunit paano maiiwasan ang mga nangungupahan sa mga salungatan sa isa't isa? Paano kung ang isa sa kanila, sabihin, ay nagpasya na humiram ng banyo para sa kalahating araw?

Narito ang catch. Maaaring kainin ng isang walang ingat na lalagyan ang lahat ng magagamit na mapagkukunan ng CPU sa isang makina. Kung mayroon kang isang matalinong application stack (halimbawa, JVM, Go, Node VM ay maayos na na-configure), kung gayon hindi ito isang problema: maaari kang magtrabaho sa ganitong mga kondisyon sa loob ng mahabang panahon. Ngunit kung ang mga application ay hindi gaanong na-optimize o hindi na-optimize sa lahat (FROM java:latest), ang sitwasyon ay maaaring mawalan ng kontrol. Sa Omio mayroon kaming automated na base Dockerfiles na may sapat na default na mga setting para sa pangunahing stack ng wika, kaya hindi umiral ang isyung ito.

Inirerekomenda namin ang pagsubaybay sa mga sukatan GAMITIN (paggamit, saturation at mga error), mga pagkaantala sa API at mga rate ng error. Tiyakin na ang mga resulta ay nakakatugon sa mga inaasahan.

sanggunian

Ito ang ating kwento. Ang mga sumusunod na materyales ay lubos na nakatulong upang maunawaan kung ano ang nangyayari:

Mga ulat ng bug ng Kubernetes:

Nakatagpo ka na ba ng mga katulad na problema sa iyong pagsasanay o may karanasan na nauugnay sa pag-throttling sa mga containerized na kapaligiran ng produksyon? Ibahagi ang iyong kuwento sa mga komento!

PS mula sa tagasalin

Basahin din sa aming blog:

Pinagmulan: www.habr.com

Magdagdag ng komento