[Vertimas] Pasiuntinio įsriegimo modelis

Straipsnio vertimas: „Envoy“ įsriegimo modelis – https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Šis straipsnis man pasirodė gana įdomus, o kadangi Envoy dažniausiai naudojamas kaip „istio“ dalis arba tiesiog kaip „kubernetes“ „įėjimo valdiklis“, dauguma žmonių su juo neturi tokios pat tiesioginės sąveikos kaip, pavyzdžiui, su tipiniu. „Nginx“ arba „Haproxy“ įrenginiai. Tačiau jei kažkas sugenda, būtų gerai suprasti, kaip tai veikia iš vidaus. Stengiausi išversti kuo daugiau teksto į rusų kalbą, įskaitant specialius žodžius, kam skaudu į tai žiūrėti, originalus palikau skliausteliuose. Sveiki atvykę į katę.

Žemo lygio techninė Envoy kodų bazės dokumentacija šiuo metu yra gana menka. Kad tai ištaisytų, planuoju padaryti keletą tinklaraščio įrašų apie įvairius pasiuntinio posistemius. Kadangi tai pirmasis straipsnis, praneškite man, ką manote ir kas jus gali sudominti būsimuose straipsniuose.

Vienas iš dažniausiai užduodamų techninių klausimų apie Envoy yra žemo lygio jo naudojamo sriegimo modelio aprašymas. Šiame įraše aprašysiu, kaip Envoy susieja ryšius su gijomis, taip pat Thread Local Storage sistemą, kurią ji naudoja viduje, kad kodas būtų lygiagretesnis ir našesnis.

Siūlų apžvalga

[Vertimas] Pasiuntinio įsriegimo modelis

Envoy naudoja tris skirtingus srautų tipus:

  • Pagrindinis: Ši gija valdo proceso paleidimą ir nutraukimą, visą XDS (xDiscovery Service) API apdorojimą, įskaitant DNS, sveikatos patikrinimą, bendrą grupių ir vykdymo laiko valdymą, statistikos atstatymą, administravimą ir bendrą procesų valdymą – Linux signalus. karštas paleidimas ir tt Viskas, kas įvykiai šioje gijoje yra asinchroniniai ir „neblokuojantys“. Apskritai pagrindinė gija koordinuoja visus svarbiausius funkcinius procesus, kuriems paleisti nereikia daug procesoriaus. Tai leidžia daugumą valdymo kodų parašyti taip, lyg jis būtų vienos gijos.
  • Darbuotojas: Pagal numatytuosius nustatymus pasiuntinys sukuria darbinę giją kiekvienai sistemos aparatinės įrangos gijai, kurią galima valdyti naudojant parinktį --concurrency. Kiekviena darbuotojo gija vykdo „neblokuojančią“ įvykių kilpą, kuri yra atsakinga už kiekvieno klausytojo išklausymą; rašymo metu (29 m. liepos 2017 d.) nėra klausytojo suskaidymo, naujų jungčių priėmimo, filtrų krūvos momentų. ryšį ir apdoroja visas įvesties / išvesties (IO) operacijas per ryšio veikimo laiką. Vėlgi, tai leidžia daugumą ryšio tvarkymo kodų parašyti taip, tarsi jis būtų vienas sriegis.
  • Failų ploviklis: Kiekvienas pasiuntinio rašomas failas, daugiausia prieigos žurnalai, šiuo metu turi nepriklausomą blokavimo giją. Taip yra dėl to, kad rašymas į failus, saugomus failų sistemos talpykloje, net naudojant O_NONBLOCK kartais gali užsikimšti (atodūsis). Kai darbuotojo gijos turi įrašyti į failą, duomenys iš tikrųjų perkeliami į buferį atmintyje, kur galiausiai išplauti per giją nuplaukite failą. Tai yra viena kodo sritis, kurioje techniškai visos darbuotojo gijos gali užblokuoti tą patį užraktą bandant užpildyti atminties buferį.

Ryšio tvarkymas

Kaip trumpai aptarta aukščiau, visos darbuotojo gijos klauso visų klausytojų be jokių skilimų. Taigi branduolys naudojamas grakščiai siųsti priimtus lizdus į darbuotojų gijas. Šiuolaikiniai branduoliai paprastai yra labai geri, jie naudoja tokias funkcijas kaip įvesties/išvesties (IO) prioriteto padidinimas, kad bandytų užpildyti giją darbu prieš pradėdami naudoti kitas gijas, kurios taip pat klauso tame pačiame lizde, ir taip pat nenaudoja apvalaus veikimo. užrakinimas (Spinlock), kad būtų galima apdoroti kiekvieną užklausą.
Kai ryšys priimamas darbuotojo gijoje, jis niekada nepalieka tos gijos. Visas tolesnis ryšio apdorojimas visiškai apdorojamas darbuotojo gijoje, įskaitant bet kokią persiuntimo veiklą.

Tai turi keletą svarbių pasekmių:

  • Visi „Envoy“ ryšio telkiniai yra priskirti darbuotojo gijai. Taigi, nors HTTP/2 ryšio telkiniai vienu metu užmezga tik vieną ryšį su kiekvienu aukštesnio srauto pagrindiniu kompiuteriu, jei yra keturios darbuotojo gijos, pastovioje būsenoje bus keturios HTTP/2 jungtys viename aukštesniajame priegloboje.
  • Priežastis, kodėl Envoy veikia taip, yra ta, kad viską laikant vienoje darbuotojo gijoje, beveik visas kodas gali būti parašytas neužblokuojant ir taip, tarsi jis būtų viena gija. Šis dizainas leidžia lengvai parašyti daug kodo ir neįtikėtinai gerai išplėsti iki beveik neriboto skaičiaus darbininkų gijų.
  • Tačiau vienas iš pagrindinių dalykų yra tai, kad atminties telkinio ir ryšio efektyvumo požiūriu iš tikrųjų labai svarbu sukonfigūruoti --concurrency. Turėdami daugiau darbininkų gijų, nei reikia, eikvosite atmintį, sukursite daugiau tuščiosios eigos jungčių ir sumažinsite ryšių telkimo greitį. „Lyft“ mūsų pasiuntinio šoninių priekabų konteineriai važiuoja labai mažu lygiagrečiu, todėl našumas maždaug atitinka tarnybų, prie kurių jie sėdi, našumą. Mes vykdome „Envoy“ kaip tarpinį serverį tik maksimaliai vienu metu.

Ką reiškia neblokuoti?

Sąvoka „neblokavimas“ iki šiol buvo vartojama keletą kartų aptariant, kaip veikia pagrindinės ir darbinės gijos. Visas kodas parašytas darant prielaidą, kad niekas niekada nėra užblokuotas. Tačiau tai nėra visiškai tiesa (kas nėra visiškai tiesa?).

Envoy naudoja keletą ilgo proceso užraktų:

  • Kaip aptarta, rašant prieigos žurnalus, prieš užpildant atmintyje esantį žurnalo buferį, visos darbuotojo gijos įgyja tą patį užraktą. Užrakto laikymo laikas turėtų būti labai trumpas, tačiau užraktas gali būti ginčijamas esant dideliam vienu metu ir dideliu pralaidumu.
  • „Envoy“ naudoja labai sudėtingą sistemą vietinei gijos statistikai tvarkyti. Tai bus atskiro įrašo tema. Tačiau trumpai paminėsiu, kad apdorojant gijų statistiką vietoje, kartais reikia įsigyti centrinės „statistikos parduotuvės“ užraktą. Šio užrakto niekada neturėtų būti reikalaujama.
  • Pagrindinis siūlas periodiškai turi būti derinamas su visomis darbininkų gijomis. Tai daroma „paskelbiant“ iš pagrindinės gijos į darbuotojų gijas, o kartais iš darbuotojo gijų atgal į pagrindinę giją. Norint siųsti, reikia užrakinti, kad paskelbtą pranešimą būtų galima įrašyti į eilę vėlesniam pristatymui. Dėl šių spynų niekada nereikėtų rimtai ginčytis, tačiau techniškai jas vis tiek galima užblokuoti.
  • Kai pasiuntinys įrašo žurnalą į sistemos klaidų srautą (standartinė klaida), jis užblokuoja visą procesą. Apskritai „Envoy“ vietinė medienos ruoša laikoma siaubinga našumo požiūriu, todėl nebuvo skirta daug dėmesio jų tobulinimui.
  • Yra keletas kitų atsitiktinių užraktų, tačiau nė vienas iš jų nėra labai svarbus veikimui ir niekada neturėtų būti ginčijamas.

Gijos vietinė saugykla

Dėl to, kaip pasiuntinys atskiria pagrindinės gijos pareigas nuo darbuotojo gijos pareigų, yra reikalavimas, kad pagrindinėje gijoje būtų galima atlikti sudėtingą apdorojimą, o tada teikti kiekvienam darbuotojo gijai labai vienu metu. Šiame skyriuje aprašoma aukšto lygio pasiuntinių gijų vietinė saugykla (TLS). Kitame skyriuje aprašysiu, kaip jis naudojamas klasteriui valdyti.
[Vertimas] Pasiuntinio įsriegimo modelis

Kaip jau buvo aprašyta, pagrindinė gija tvarko praktiškai visas valdymo ir valdymo plokštumos funkcijas pasiuntinio procese. Valdymo plokštuma čia yra šiek tiek perkrauta, bet pažvelgus į ją pačiame pasiuntinio procese ir palyginus su persiuntimu, kurį atlieka darbuotojo gijos, tai prasminga. Bendra taisyklė yra ta, kad pagrindinis gijos procesas atlieka tam tikrą darbą, tada jis turi atnaujinti kiekvieną darbuotojo giją pagal to darbo rezultatą. šiuo atveju darbuotojo sriegis nebūtinai turi turėti užraktą prie kiekvienos prieigos.

Envoy's TLS (Thread local storage) sistema veikia taip:

  • Kodas, veikiantis pagrindinėje gijoje, visam procesui gali skirti TLS lizdą. Nors tai yra abstrahuota, praktiškai tai yra indeksas į vektorių, suteikiantis prieigą prie O(1).
  • Pagrindinė gija į savo lizdą gali įdiegti savavališkus duomenis. Kai tai daroma, duomenys skelbiami kiekvienoje darbuotojo gijoje kaip įprastas įvykio ciklo įvykis.
  • Darbuotojų gijos gali nuskaityti iš savo TLS lizdo ir gauti visus ten turimus gijų vietinius duomenis.

Nors tai labai paprasta ir neįtikėtinai galinga paradigma, ji labai panaši į RCU (skaitymo-kopijavimo-atnaujinimo) blokavimo koncepciją. Iš esmės darbuotojo gijos niekada nemato jokių duomenų pakeitimų TLS lizduose, kai dirbama. Pokyčiai vyksta tik poilsio laikotarpiu tarp darbo įvykių.

Pasiuntinys tai naudoja dviem skirtingais būdais:

  • Išsaugant skirtingus duomenis kiekvienoje darbuotojo gijoje, duomenis galima pasiekti be jokio blokavimo.
  • Išlaikant bendrinamą rodyklę į pasaulinius duomenis tik skaitymo režimu kiekvienoje darbuotojo gijoje. Taigi kiekviena darbuotojo gija turi duomenų nuorodų skaičių, kurio negalima sumažinti, kol vykdomas darbas. Tik tada, kai visi darbuotojai nurims ir įkels naujus bendrinamus duomenis, seni duomenys bus sunaikinti. Tai identiška RCU.

Grupės naujinimo gijos

Šiame skyriuje aprašysiu, kaip TLS (Thread local storage) naudojamas klasteriui valdyti. Klasterio valdymas apima xDS API ir (arba) DNS apdorojimą, taip pat sveikatos patikrinimą.
[Vertimas] Pasiuntinio įsriegimo modelis

Klasterio srauto valdymas apima šiuos komponentus ir veiksmus:

  1. Klasterių tvarkyklė yra „Envoy“ komponentas, valdantis visas žinomas klasterio aukštesnes grandines, „Cluster Discovery Service“ (CDS) API, slaptosios aptikimo tarnybos (SDS) ir „Endpoint Discovery Service“ (EDS) API, DNS ir aktyvius išorinius patikrinimus. Jis yra atsakingas už „galų gale nuoseklaus“ kiekvienos aukštesniosios grupės klasterio rodinį, apimantį atrastus pagrindinius kompiuterius ir sveikatos būklę.
  2. Sveikatos tikrintojas atlieka aktyvų sveikatos patikrinimą ir praneša apie sveikatos būklės pokyčius grupės vadovui.
  3. CDS (Cluster Discovery Service) / SDS (Secret Discovery Service) / EDS (Galinio taško aptikimo paslauga) / DNS atliekama siekiant nustatyti grupės narystę. Būsenos pakeitimas grąžinamas klasterio valdytojui.
  4. Kiekviena darbuotojo gija nuolat vykdo įvykio kilpą.
  5. Kai klasterio valdytojas nustato, kad klasterio būsena pasikeitė, jis sukuria naują tik skaitomą klasterio būsenos momentinį vaizdą ir siunčia jį kiekvienai darbuotojo gijai.
  6. Kitu tyliuoju laikotarpiu darbuotojo gija atnaujins momentinę nuotrauką priskirtame TLS lizde.
  7. Įvesties / išvesties įvykio metu, kuris turėtų nustatyti pagrindinio kompiuterio apkrovos balansą, apkrovos balansavimo priemonė paprašys TLS (Thread local storage) lizdo, kad gautų informaciją apie pagrindinį kompiuterį. Tam nereikia spynų. Taip pat atminkite, kad TLS taip pat gali suaktyvinti atnaujinimo įvykius, kad apkrovos balansavimo priemonės ir kiti komponentai galėtų perskaičiuoti talpyklas, duomenų struktūras ir kt. Tai nepatenka į šio įrašo taikymo sritį, tačiau naudojama įvairiose kodo vietose.

Naudodamasis aukščiau pateikta procedūra, pasiuntinys gali apdoroti kiekvieną užklausą be jokio blokavimo (išskyrus anksčiau aprašytus atvejus). Be paties TLS kodo sudėtingumo, daugumai kodo nereikia suprasti, kaip veikia kelių gijų kūrimas, ir gali būti parašytas vienos gijos būdu. Dėl to daugumą kodo lengviau rašyti, be to, užtikrinamas puikus našumas.

Kitos posistemės, kuriose naudojamas TLS

TLS (Thread vietinė saugykla) ir RCU (Read Copy Update) yra plačiai naudojami Envoy.

Naudojimo pavyzdžiai:

  • Funkcionalumo pakeitimo vykdymo metu mechanizmas: Dabartinis įjungtų funkcijų sąrašas apskaičiuojamas pagrindinėje gijoje. Tada kiekvienai darbuotojo gijai suteikiamas tik skaitomas momentinis vaizdas, naudojant RCU semantiką.
  • Maršruto lentelių keitimas: maršruto lentelėms, kurias teikia RDS (Maršruto aptikimo paslauga), maršruto lentelės sukuriamos pagrindinėje gijoje. Tik skaitomas momentinis vaizdas vėliau bus pateiktas kiekvienai darbuotojo gijai naudojant RCU (skaitymo kopijavimo naujinimo) semantiką. Dėl to maršruto lentelių keitimas tampa atomiškai efektyvus.
  • HTTP antraštės kaupimas talpykloje: Pasirodo, HTTP antraštės skaičiavimas kiekvienai užklausai (paleidžiant ~25K+ RPS vienam branduoliui) yra gana brangus. Envoy centralizuotai apskaičiuoja antraštę maždaug kas pusę sekundės ir pateikia ją kiekvienam darbuotojui per TLS ir RCU.

Yra ir kitų atvejų, tačiau ankstesni pavyzdžiai turėtų gerai suprasti, kam naudojamas TLS.

Žinomos našumo spąstai

Nors „Envoy“ apskritai veikia gana gerai, yra keletas svarbių sričių, į kurias reikia atkreipti dėmesį, kai jis naudojamas labai vienu metu ir dideliu pralaidumu:

  • Kaip aprašyta šiame straipsnyje, šiuo metu visos darbuotojo gijos įgyja užraktą rašant į prieigos žurnalo atminties buferį. Esant dideliam vienu metu ir dideliam pralaidumui, rašydami į galutinį failą turėsite sugrupuoti kiekvienos darbuotojo gijos prieigos žurnalus netvarkingo pristatymo sąskaita. Arba galite sukurti atskirą prieigos žurnalą kiekvienai darbuotojo gijai.
  • Nors statistika yra labai optimizuota, esant labai dideliam lygiagretumui ir pralaidumui, dėl individualios statistikos gali kilti didžiulių ginčų. Šios problemos sprendimas yra skaitikliai, skirti darbuotojo gijai, periodiškai atkuriant centrinius skaitiklius. Tai bus aptarta kitame įraše.
  • Dabartinė architektūra neveiks gerai, jei „Envoy“ bus įdiegtas scenarijuje, kai yra labai mažai ryšių, kuriems reikia didelių apdorojimo išteklių. Nėra garantijos, kad jungtys bus tolygiai paskirstytos tarp darbininkų gijų. Tai galima išspręsti įdiegus darbuotojų ryšių balansavimą, kuris leis apsikeisti jungtimis tarp darbininkų gijų.

Išvada

„Envoy“ sriegių sujungimo modelis sukurtas taip, kad būtų lengviau programuoti ir būtų didžiulis lygiagretumas potencialiai eikvojančios atminties ir jungčių sąskaita, jei jis netinkamai sukonfigūruotas. Šis modelis leidžia labai gerai veikti esant labai dideliam gijų skaičiui ir našumui.
Kaip jau trumpai minėjau „Twitter“, dizainas taip pat gali veikti naudojant viso vartotojo režimo tinklo krūvą, pvz., DPDK (Data Plane Development Kit), todėl įprasti serveriai gali apdoroti milijonus užklausų per sekundę ir visiškai apdoroti L7. Bus labai įdomu pamatyti, kas bus pastatyta per ateinančius kelerius metus.
Paskutinis trumpas komentaras: manęs daug kartų klausė, kodėl pasirinkome C++ pasiuntiniui. Priežastis išlieka ta, kad tai vis dar yra vienintelė plačiai naudojama pramoninio lygio kalba, kuria galima sukurti šiame įraše aprašytą architektūrą. C++ tikrai netinka visiems ar net daugeliui projektų, tačiau tam tikrais naudojimo atvejais tai vis tiek yra vienintelė priemonė darbui atlikti.

Nuorodos į kodą

Nuorodos į šiame įraše aptartus failus su sąsajomis ir antraštėmis:

Šaltinis: www.habr.com

Добавить комментарий