[Käännös] Envoy-langoitusmalli

Artikkelin käännös: Envoy-ketjutusmalli - https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Minusta tämä artikkeli oli varsin mielenkiintoinen, ja koska Envoyta käytetään useimmiten kubernetesin "istion" osana tai yksinkertaisesti "sisääntuloohjaimena", useimmat ihmiset eivät ole sen kanssa samaa suoraa vuorovaikutusta kuin esimerkiksi tyypillisen Nginx- tai Haproxy-asennukset. Jos jokin kuitenkin rikkoutuu, olisi hyvä ymmärtää, miten se toimii sisältä käsin. Yritin kääntää tekstistä mahdollisimman suuren osan venäjäksi, myös erikoissanoja; niille, joille tämä on tuskallista katsoa, ​​jätin alkuperäiset suluihin. Tervetuloa kissalle.

Envoy-koodikannan matalan tason tekninen dokumentaatio on tällä hetkellä melko niukkaa. Tämän korjaamiseksi aion tehdä sarjan blogikirjoituksia Envoyn eri alajärjestelmistä. Koska tämä on ensimmäinen artikkeli, kerro minulle, mitä mieltä olet ja mistä saatat olla kiinnostunut tulevissa artikkeleissa.

Yksi yleisimmistä Envoysta saamistani teknisistä kysymyksistä on vaatia matalan tason kuvausta sen käyttämästä kierteitysmallista. Tässä viestissä kuvailen, kuinka Envoy yhdistää yhteydet säikeisiin sekä Thread Local Storage -järjestelmän, jota se käyttää sisäisesti tehdäkseen koodista rinnakkaisemman ja tehokkaamman.

Langaton yleiskatsaus

[Käännös] Envoy-langoitusmalli

Envoy käyttää kolmea eri tyyppistä virtaa:

  • Pääasiallinen: Tämä säie ohjaa prosessin käynnistystä ja lopettamista, kaikkea XDS (xDiscovery Service) API:n käsittelyä, mukaan lukien DNS, kuntotarkastus, yleinen klusterin ja ajonajan hallinta, tilastojen nollaus, hallinta ja yleinen prosessien hallinta - Linux-signaalit, kuuma uudelleenkäynnistys jne. tässä säikeessä tapahtuu asynkroninen ja "ei-esto". Yleensä pääsäie koordinoi kaikkia kriittisiä toiminnallisia prosesseja, jotka eivät vaadi paljon suoritinta toimiakseen. Tämä mahdollistaa useimpien ohjauskoodien kirjoittamisen ikään kuin se olisi yksisäikeinen.
  • Työntekijä: Oletuksena Envoy luo työsäikeen jokaiselle järjestelmän laitteistosäikeelle, tätä voidaan ohjata vaihtoehdolla --concurrency. Jokainen työntekijäsäie ajaa "estoamattoman" tapahtumasilmukan, joka on vastuussa jokaisen kuuntelijan kuuntelemisesta; Kirjoitushetkellä (29. heinäkuuta 2017) kuuntelijaa ei murskata, hyväksytään uusia yhteyksiä, luodaan suodatinpino yhteys ja prosessoi kaikki input/output (IO) -toiminnot yhteyden käyttöiän aikana. Tämä taas mahdollistaa useimpien yhteydenkäsittelykoodien kirjoittamisen ikään kuin se olisi yksisäikeinen.
  • Tiedostojen huuhtelulaite: Jokaisella lähettilään kirjoittamalla tiedostolla, pääasiassa pääsylokeilla, on tällä hetkellä itsenäinen estoketju. Tämä johtuu siitä, että kirjoitetaan tiedostojärjestelmän välimuistiin tallentamiin tiedostoihin jopa käytettäessä O_NONBLOCK voi joskus tukkeutua (huokaus). Kun työsäikeiden on kirjoitettava tiedostoon, tiedot siirretään itse asiassa muistin puskuriin, jossa ne lopulta huuhdellaan säikeen läpi. tiedosto huuhdellaan. Tämä on yksi koodialue, jossa teknisesti kaikki työntekijäsäikeet voivat estää saman lukon yrittäessään täyttää muistipuskuria.

Yhteyden käsittely

Kuten yllä lyhyesti käsiteltiin, kaikki työntekijäsäikeet kuuntelevat kaikkia kuuntelijoita ilman sirpaleita. Siten ydintä käytetään sulavasti lähettämään hyväksyttyjä pistokkeita työsäikeille. Nykyaikaiset ytimet ovat yleensä erittäin hyviä tässä, ne käyttävät ominaisuuksia, kuten input/output (IO) prioriteetin tehostusta yrittääkseen täyttää säikeen työllä ennen kuin ne alkavat käyttää muita säikeitä, jotka myös kuuntelevat samassa socketissa, eivätkä myöskään käytä round robinia. lukitus (Spinlock) jokaisen pyynnön käsittelemiseksi.
Kun yhteys on hyväksytty työntekijäsäikeessä, se ei koskaan poistu kyseisestä säikeestä. Kaikki yhteyden jatkokäsittely käsitellään kokonaan työntekijäsäikeessä, mukaan lukien edelleenlähetyskäyttäytyminen.

Tällä on useita tärkeitä seurauksia:

  • Kaikki Envoyn yhteyspoolit on määritetty työntekijäsäikeeseen. Joten vaikka HTTP/2-yhteyspoolit muodostavat vain yhden yhteyden kuhunkin ylävirran isäntään kerrallaan, jos työsäikeitä on neljä, HTTP/2-yhteyksiä on neljä yhtä ylävirran isäntää vakaassa tilassa.
  • Syy Envoy toimii tällä tavalla on se, että pitämällä kaikki yhdessä työntekijäsäikeessä, lähes kaikki koodi voidaan kirjoittaa ilman estoa ja ikään kuin se olisi yksisäikeinen. Tämän rakenteen ansiosta on helppo kirjoittaa paljon koodia ja skaalata uskomattoman hyvin lähes rajattomaan määrään työsäikeitä.
  • Yksi tärkeimmistä saavutuksista on kuitenkin se, että muistivaraston ja yhteyden tehokkuuden kannalta on todella tärkeää määrittää --concurrency. Tarvittavaa enemmän työsäikeitä tuhlaa muistia, luo enemmän käyttämättömiä yhteyksiä ja vähentää yhteyksien yhdistämisnopeutta. Lyftissä lähettiläämme sivuvaunukontit kulkevat erittäin alhaisella samanaikaisuudella, joten suorituskyky vastaa suunnilleen niiden vieressä olevia palveluita. Käytämme Envoyta reunavälityspalvelimena vain suurimmalla samanaikaisuudella.

Mitä estäminen tarkoittaa?

Termiä "ei-esto" on käytetty useita kertoja tähän mennessä keskusteltaessa siitä, miten pää- ja työsäikeet toimivat. Kaikki koodi on kirjoitettu olettaen, ettei mitään ole koskaan estetty. Tämä ei kuitenkaan ole täysin totta (mikä ei ole täysin totta?).

Envoy käyttää useita pitkiä prosessilukkeja:

  • Kuten on käsitelty, käyttölokeja kirjoitettaessa kaikki työntekijäsäikeet saavat saman lukituksen ennen kuin muistin lokipuskuri täyttyy. Lukon pitoajan tulee olla hyvin lyhyt, mutta lukko on mahdollista riitauttaa suurella samanaikaisuudella ja suurella suorituskyvyllä.
  • Envoy käyttää erittäin monimutkaista järjestelmää käsitelläkseen säikeen paikallisia tilastoja. Tästä tulee erillisen postauksen aihe. Mainitsen kuitenkin lyhyesti, että osana lankatilastojen paikallista käsittelyä on joskus tarpeen hankkia lukko keskitettyyn "tilastokauppaan". Tätä lukitusta ei pitäisi koskaan vaatia.
  • Pääsäikeen on ajoittain koordinoitava kaikkien työntekijäsäikeiden kanssa. Tämä tehdään "julkaisemalla" pääsäikeestä työntekijäsäikeisiin ja joskus työntekijäsäikeistä takaisin pääsäikeeseen. Lähettäminen vaatii lukon, jotta julkaistu viesti voidaan asettaa jonoon myöhempää toimitusta varten. Näitä lukkoja ei pidä koskaan kiistää vakavasti, mutta ne voidaan silti teknisesti estää.
  • Kun lähettiläs kirjoittaa lokin järjestelmän virhevirtaan (vakiovirhe), se saa lukon koko prosessiin. Yleisesti ottaen Envoyn paikallista puunkorjuuta pidetään suorituskyvyn kannalta kauheana, joten sen parantamiseen ei ole kiinnitetty paljon huomiota.
  • On olemassa muutamia muita satunnaisia ​​lukkoja, mutta yksikään niistä ei ole suorituskykykriittinen, eikä niitä tule koskaan kyseenalaistaa.

Säikeen paikallinen tallennustila

Koska Envoy erottaa pääsäikeen vastuut työntekijäsäikeen vastuista, on olemassa vaatimus, että monimutkainen käsittely voidaan tehdä pääsäikeellä ja toimittaa sitten kullekin työntekijäsäikeelle erittäin samanaikaisella tavalla. Tässä osassa kuvataan Envoy Thread Local Storage (TLS) -tallennustila korkealla tasolla. Seuraavassa osiossa kuvailen, kuinka sitä käytetään klusterin hallintaan.
[Käännös] Envoy-langoitusmalli

Kuten jo kuvattiin, pääsäie käsittelee käytännössä kaikki hallinta- ja ohjaustason toiminnot Envoy-prosessissa. Ohjaustaso on tässä hieman ylikuormitettu, mutta kun sitä tarkastellaan itse Envoy-prosessissa ja verrataan sitä edelleenlähetykseen, jota työntekijäsäikeet tekevät, se on järkevää. Yleissääntönä on, että pääsäieprosessi tekee jonkin verran työtä, ja sitten sen on päivitettävä jokainen työntekijäsäie työn tuloksen mukaan. tässä tapauksessa työsäikeen ei tarvitse saada lukkoa jokaisessa pääsyssä.

Envoyn TLS (Thread local storage) -järjestelmä toimii seuraavasti:

  • Pääsäikeessä käynnissä oleva koodi voi varata TLS-paikan koko prosessille. Vaikka tämä on abstrahoitu, käytännössä se on indeksi vektoriin, joka tarjoaa O(1) pääsyn.
  • Pääsäie voi asentaa mielivaltaisia ​​tietoja paikkaansa. Kun tämä on tehty, tiedot julkaistaan ​​jokaiseen työsäikeeseen normaalina tapahtumasilmukan tapahtumana.
  • Työntekijäsäikeet voivat lukea TLS-paikastaan ​​ja hakea sieltä saatavilla olevat säikeen paikalliset tiedot.

Vaikka se on hyvin yksinkertainen ja uskomattoman tehokas paradigma, se on hyvin samanlainen kuin RCU (Read-Copy-Update) -eston käsite. Pohjimmiltaan työntekijäsäikeet eivät koskaan näe tietomuutoksia TLS-paikoissa työn ollessa käynnissä. Muutos tapahtuu vain työtapahtumien välisen lepoajan aikana.

Envoy käyttää tätä kahdella eri tavalla:

  • Tallentamalla eri dataa jokaiseen työsäikeeseen, tietoihin pääsee käsiksi ilman estoa.
  • Ylläpitämällä jaettua osoitinta globaaleihin tietoihin vain luku -tilassa jokaisessa työsäikeessä. Siten jokaisella työntekijäsäikeellä on tietoviitemäärä, jota ei voi vähentää työn ollessa käynnissä. Vasta kun kaikki työntekijät rauhoittuvat ja lataavat uutta jaettua dataa, vanhat tiedot tuhoutuvat. Tämä on identtinen RCU:n kanssa.

Klusterin päivitysketjutus

Tässä osiossa kuvailen, kuinka TLS:ää (Thread local storage) käytetään klusterin hallintaan. Klusterinhallinta sisältää xDS API- ja/tai DNS-käsittelyn sekä kuntotarkastuksen.
[Käännös] Envoy-langoitusmalli

Klusterivuon hallinta sisältää seuraavat komponentit ja vaiheet:

  1. Cluster Manager on Envoyn komponentti, joka hallitsee kaikkia tunnettuja klusterin ylävirtauksia, Cluster Discovery Servicen (CDS) API:ta, Secret Discovery Servicen (SDS) ja Endpoint Discovery Servicen (EDS) API:ta, DNS:ää ja aktiivisia ulkoisia tarkistuksia. Se on vastuussa "lopulta johdonmukaisen" näkymän luomisesta jokaisesta ylävirran klusterista, joka sisältää löydetyt isännät sekä terveydentilan.
  2. Terveystarkistus suorittaa aktiivisen terveystarkastuksen ja raportoi terveydentilan muutokset klusterin johtajalle.
  3. CDS (Cluster Discovery Service) / SDS (Secret Discovery Service) / EDS (Endpoint Discovery Service) / DNS suoritetaan klusterin jäsenyyden määrittämiseksi. Tilamuutos palautetaan klusterin hallinnoijalle.
  4. Jokainen työsäie suorittaa jatkuvasti tapahtumasilmukan.
  5. Kun klusterin hallinta määrittää, että klusterin tila on muuttunut, se luo uuden vain luku -vedoksen klusterin tilasta ja lähettää sen jokaiselle työntekijäsäikeelle.
  6. Seuraavan hiljaisen jakson aikana työntekijäsäie päivittää tilannevedoksen varattuun TLS-paikkaan.
  7. I/O-tapahtuman aikana, jonka on määrä määrittää isäntä ja kuormitustasapaino, kuormantasaaja pyytää TLS-paikkaa (Thread local storage) saadakseen tietoja isännästä. Tämä ei vaadi lukkoja. Huomaa myös, että TLS voi myös laukaista päivitystapahtumia, jotta kuormituksen tasaajat ja muut komponentit voivat laskea uudelleen välimuistit, tietorakenteet jne. Tämä ei kuulu tämän viestin soveltamisalaan, mutta sitä käytetään useissa paikoissa koodissa.

Yllä olevaa menettelyä käyttäen lähettiläs voi käsitellä jokaisen pyynnön ilman estoa (paitsi edellä kuvatulla tavalla). Itse TLS-koodin monimutkaisuuden lisäksi suurimman osan koodista ei tarvitse ymmärtää, kuinka monisäikeisyys toimii, ja se voidaan kirjoittaa yksisäikeisenä. Tämä tekee suurimman osan koodista helpompaa kirjoittaa erinomaisen suorituskyvyn lisäksi.

Muut alijärjestelmät, jotka käyttävät TLS:ää

TLS (Thread local storage) ja RCU (Read Copy Update) ovat laajalti käytössä Envoyssa.

Esimerkkejä käytöstä:

  • Mekanismi toimintojen muuttamiseen suorituksen aikana: Käytössä olevien toimintojen nykyinen luettelo lasketaan pääsäikeessä. Jokaiselle työntekijäsäikeelle annetaan sitten vain luku -tilassa oleva tilannekuva RCU-semantiikan avulla.
  • Reittitaulukoiden vaihto: RDS:n (Route Discovery Service) tarjoamille reittitaulukoille reittitaulukot luodaan pääsäikeeseen. Vain luku -tilassa oleva tilannevedos toimitetaan myöhemmin jokaiselle työntekijäsäikeelle RCU (Read Copy Update) -semantiikan avulla. Tämä tekee reittitaulukoiden vaihtamisesta atomisesti tehokasta.
  • HTTP-otsikon välimuisti: Kuten käy ilmi, HTTP-otsikon laskeminen kullekin pyynnölle (käytettäessä ~25 XNUMX + RPS:tä ydintä kohti) on melko kallista. Envoy laskee keskitetysti otsikon noin puolen sekunnin välein ja toimittaa sen jokaiselle työntekijälle TLS:n ja RCU:n kautta.

On muitakin tapauksia, mutta aiempien esimerkkien pitäisi antaa hyvä käsitys siitä, mihin TLS:ää käytetään.

Tunnetut suorituskyvyn sudenkuopat

Vaikka Envoy toimii yleisesti ottaen melko hyvin, on olemassa muutamia merkittäviä alueita, joihin on kiinnitettävä huomiota, kun sitä käytetään erittäin korkealla samanaikaisuudella ja suorituskyvyllä:

  • Kuten tässä artikkelissa on kuvattu, tällä hetkellä kaikki työntekijäsäikeet saavat lukon kirjattaessa pääsylokin muistipuskuriin. Suurella samanaikaisuudella ja suurella suorituskyvyllä sinun on koottava jokaisen työntekijäsäikeen käyttölokit epäjärjestyksessä tapahtuvan toimituksen kustannuksella, kun kirjoitat lopulliseen tiedostoon. Vaihtoehtoisesti voit luoda erillisen käyttölokin jokaiselle työntekijäsäikeelle.
  • Vaikka tilastot ovat erittäin optimoituja, erittäin korkealla samanaikaisuudella ja suorituskyvyllä on todennäköisesti atomikiista yksittäisistä tilastoista. Ratkaisu tähän ongelmaan on laskurit työntekijäsäiettä kohti ja keskuslaskurien säännöllinen nollaus. Tästä keskustellaan seuraavassa postauksessa.
  • Nykyinen arkkitehtuuri ei toimi hyvin, jos Envoy otetaan käyttöön skenaariossa, jossa on hyvin vähän yhteyksiä, jotka vaativat merkittäviä käsittelyresursseja. Ei ole takeita siitä, että liitännät jakautuvat tasaisesti työkierteiden kesken. Tämä voidaan ratkaista ottamalla käyttöön työntekijöiden yhteyksien tasapainotus, joka mahdollistaa yhteyksien vaihdon työntekijäsäikeiden välillä.

Johtopäätös

Envoyn ketjutusmalli on suunniteltu helpottamaan ohjelmointia ja tarjoamaan massiivista rinnakkaisuutta mahdollisesti tuhlaavan muistin ja yhteyksien kustannuksella, jos sitä ei ole määritetty oikein. Tämän mallin ansiosta se toimii erittäin hyvin erittäin suurilla lankamäärillä ja suorituskyvyllä.
Kuten mainitsin lyhyesti Twitterissä, suunnittelu voi toimia myös täyden käyttäjätilan verkkopinon päällä, kuten DPDK (Data Plane Development Kit), mikä voi johtaa siihen, että perinteiset palvelimet käsittelevät miljoonia pyyntöjä sekunnissa täydellä L7-käsittelyllä. On erittäin mielenkiintoista nähdä, mitä lähivuosina rakennetaan.
Viimeinen nopea kommentti: Minulta on kysytty monta kertaa, miksi valitsimme C++:n Envoylle. Syynä on edelleen, että se on edelleen ainoa laajalti käytetty teollinen kieli, jolla tässä postauksessa kuvattu arkkitehtuuri voidaan rakentaa. C++ ei todellakaan sovi kaikkiin tai edes useisiin projekteihin, mutta tietyissä käyttötapauksissa se on silti ainoa työkalu työn suorittamiseen.

Linkkejä koodiin

Linkit tiedostoihin, joissa on tässä viestissä käsitelty käyttöliittymä ja otsikkototeutus:

Lähde: will.com

Lisää kommentti