Vuonna 2016 me Pufferissa vaihtui Kubernetesiin, ja nyt noin 60 solmua (AWS:ssä) ja 1500 konttia työskentelevät k8s-klusterissamme, jota hallinnoi potkia. Mikropalveluihin kuitenkin siirryttiin yrityksen ja erehdyksen kautta, ja useiden vuosien k8s-työskentelyn jälkeen kohtaamme edelleen uusia ongelmia. Tässä viestissä puhumme prosessorin rajoitukset: miksi ajattelimme, että ne olivat hyviä käytäntöjä ja miksi ne eivät lopulta olleet niin hyviä.
Prosessorin rajoitukset ja kuristus
Kuten monet muut Kubernetes-käyttäjät, Google suosittelee prosessorirajojen asettamista. Ilman tällaista asetusta solmun kontit voivat viedä kaiken prosessorin tehon, mikä puolestaan aiheuttaa tärkeitä Kubernetes-prosesseja (esim. kubelet) lakkaa vastaamasta pyyntöihin. Näin ollen suorittimen rajojen asettaminen on hyvä tapa suojata solmujasi.
Prosessorirajoitukset määrittävät säilön suorittimen enimmäisajan, jonka se voi käyttää tietyn ajanjakson aikana (oletus on 100 ms), eikä säilö koskaan ylitä tätä rajaa. Kubernetes for kuristus säiliöön ja estämään sitä ylittämästä rajaa, käytetään erikoistyökalua CFS-kiintiö, mutta nämä keinotekoiset suorittimen rajoitukset heikentävät suorituskykyä ja lisäävät säilöjesi vasteaikaa.
Mitä voi tapahtua, jos emme aseta prosessorirajoja?
Valitettavasti jouduimme itse kohtaamaan tämän ongelman. Jokaisella solmulla on prosessi, joka vastaa säilöjen hallinnasta kubelet, ja hän lakkasi vastaamasta pyyntöihin. Kun tämä tapahtuu, solmu siirtyy tilaan NotReady, ja sen säiliöt ohjataan jonnekin muualle ja aiheuttavat samat ongelmat uusiin solmuihin. Ei lievästi sanottuna ihanteellinen skenaario.
Kuristuksen ja reagoinnin ongelman ilmentymä
Säilön seurannan tärkein mittari on trottling, se näyttää kuinka monta kertaa säiliötäsi on kuristettu. Huomasimme kiinnostuneena kuristuksen esiintymisen joissakin säiliöissä riippumatta siitä, oliko prosessorin kuormitus äärimmäistä vai ei. Katsotaanpa esimerkkinä yhtä tärkeimmistä sovellusliittymistämme:
Kuten alta näet, olemme asettaneet rajan 800m (0.8 tai 80 % ydintä) ja huippuarvot parhaimmillaan 200m (20 % ydin). Näyttää siltä, että ennen palvelun kuristamista meillä on vielä runsaasti prosessoritehoa, mutta...
Olet ehkä huomannut, että vaikka prosessorin kuormitus on alle määritettyjen rajojen - huomattavasti alle - kuristus tapahtuu silti.
Miksi näemme kuristusta alhaisella suorittimen kuormituksella? Lyhyt versio on: "Linux-ytimessä on virhe, joka aiheuttaa tarpeettoman kurituksen konttien määritetyillä prosessorirajoituksilla." Jos olet kiinnostunut ongelman luonteesta, voit lukea esityksen (video и teksti vaihtoehdot) kirjoittanut Dave Chiluk.
Pitkien keskustelujen jälkeen päätimme poistaa prosessorirajoitukset kaikista palveluista, jotka vaikuttivat suoraan tai välillisesti käyttäjiemme kriittisiin toimivuuteen.
Päätös ei ollut helppo, koska arvostamme suuresti klusterimme vakautta. Olemme jo aiemmin kokeilleet klusterimme epävakautta, jolloin palvelut kuluttivat liikaa resursseja ja hidastivat koko solmunsa työtä. Nyt kaikki oli hieman erilaista: meillä oli selkeä käsitys siitä, mitä odotimme klustereiltamme, sekä hyvä strategia suunniteltujen muutosten toteuttamiseksi.
Liikekirjeenvaihto kiireellisestä asiasta.
Kuinka suojata solmujasi, kun rajoituksia poistetaan?
"Rajoittamattomien" palvelujen eristäminen:
Olemme jo aiemmin nähneet joidenkin solmujen joutuneen tilaan notReadyjohtuen ensisijaisesti palveluista, jotka kuluttivat liikaa resursseja.
Päätimme sijoittaa tällaiset palvelut erillisiin ("merkittyihin") solmuihin, jotta ne eivät häiritse "liittyvät" palvelut. Seurauksena oli, että merkitsemällä joitain solmuja ja lisäämällä toleranssiparametrin "liittymättömiin" palveluihin, saimme paremman hallinnan klusteriin, ja meidän oli helpompi tunnistaa solmujen ongelmat. Voit tutustua vastaaviin prosesseihin itse dokumentointi.
Oikean prosessori- ja muistipyynnön määrittäminen:
Suurin pelkomme oli, että prosessi kuluttaisi liikaa resursseja ja solmu lakkaisi vastaamasta pyyntöihin. Koska nyt (Datadogin ansiosta) pystyimme selkeästi valvomaan kaikkia klusterimme palveluita, analysoin useiden kuukausien toiminnan niistä, jotka aioimme nimetä "liittymättömiksi". Asetin yksinkertaisesti CPU:n maksimikäytön 20% marginaalilla ja varasin siten tilaa solmussa siltä varalta, että k8s yrittää osoittaa solmulle muita palveluita.
Kuten kaaviosta näkyy, prosessorin enimmäiskuormitus on saavutettu 242m CPU-ytimet (0.242 prosessoriydintä). Prosessoripyyntöä varten riittää, että otat tätä arvoa hieman suuremman luvun. Huomaa, että koska palvelut ovat käyttäjäkeskeisiä, huippukuormitusarvot osuvat yhteen liikenteen kanssa.
Tee sama muistinkäytön ja kyselyiden kanssa, ja voila - olet valmis! Lisää turvallisuutta lisäämällä vaakasuuntaisen pod-automaattisen skaalauksen. Siten joka kerta, kun resurssien kuormitus on korkea, automaattinen skaalaus luo uusia podeja, ja kubernetes jakaa ne solmuille, joissa on vapaata tilaa. Jos itse klusterissa ei ole tilaa jäljellä, voit asettaa itsellesi hälytyksen tai määrittää uusien solmujen lisäämisen niiden automaattisen skaalauksen avulla.
Miinuksista on syytä huomata, että hävisimme "säiliön tiheys", eli yhdessä solmussa olevien säiliöiden määrä. Meillä voi myös olla paljon "rentoutumisia" alhaisella liikennetiheydellä, ja on myös mahdollista, että saavutat korkean prosessorikuorman, mutta automaattisen skaalauksen solmujen pitäisi auttaa jälkimmäisessä.
Tulokset
Olen iloinen voidessani julkaista nämä erinomaiset tulokset viime viikkojen kokeiluista. Olemme jo nähneet merkittäviä parannuksia kaikissa muokatuissa palveluissa:
Parhaat tulokset saavutimme kotisivullamme (buffer.com), siellä palvelu nopeutui kaksikymmentäkaksi kertaa!
Kuitenkin lukiessa kubernetes-ongelmia githubissatoiselle syyskuulle 2020 kohtaamme edelleen mainintoja joistakin Linux-projekteista, joissa on samanlainen vika. Uskon, että joissakin Linux-jakeluissa on edelleen tämä virhe, ja ne ovat vain korjaamassa sitä.
Jos jakeluversiosi on vanhempi kuin 4.19, suosittelen päivittämistä uusimpaan, mutta joka tapauksessa sinun tulee yrittää poistaa prosessorirajoitukset ja katsoa, jatkuuko kuristus. Alla näet osittaisen luettelon Kubernetes-hallintapalveluista ja Linux-jakeluista:
Debian: korjaus integroitu jakelun uusimpaan versioon, kaverija näyttää aika tuoreelta (Elokuu 2020). Jotkut aiemmat versiot voivat myös olla korjattuja.
EKS:llä on vielä korjaus joulukuussa vuoden 2019. Jos versiosi on tätä vanhempi, sinun tulee päivittää AMI.
kops: Kesäkuusta 2020 alkaen у kops 1.18+ Pääisäntäkuva on Ubuntu 20.04. Jos kops-versiosi on vanhempi, saatat joutua odottamaan korjausta. Me itse odotamme nyt.
En ole varma, onko ongelma täysin ratkaistu. Kun pääsemme korjauksen kernel-versioon, testaan klusterin ja päivitän viestin. Jos joku on jo päivittänyt, olisin kiinnostunut lukemaan tuloksiasi.
Johtopäätös
Jos työskentelet Docker-säilöjen kanssa Linuxissa (riippumatta Kubernetesista, Mesosista, Swarmista tai muista), säilösi voivat menettää suorituskykynsä kuristuksen vuoksi;
Yritä päivittää jakelusi uusimpaan versioon siinä toivossa, että virhe on jo korjattu.
Prosessorirajoitusten poistaminen ratkaisee ongelman, mutta tämä on vaarallinen tekniikka, jota tulee käyttää erittäin varoen (on parempi päivittää ensin ydin ja vertailla tuloksia);
Jos olet poistanut suorittimen rajoitukset, seuraa tarkasti suorittimen ja muistin käyttöä ja varmista, että suorittimen resurssit ylittävät kulutuksen.
Turvallinen vaihtoehto olisi skaalata podit automaattisesti uusien podien luomiseksi korkean laitteistokuormituksen tapauksessa, jotta kubernetes määrittää ne vapaille solmuille.
Toivon, että tämä viesti auttaa sinua parantamaan konttijärjestelmien suorituskykyä.
PS. Täällä kirjoittaja on kirjeenvaihdossa lukijoiden ja kommentoijien kanssa (englanniksi).