[Vertaling] Gesant-inrygmodel

Vertaling van die artikel: Envoy threading model - https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Hierdie artikel het vir my nogal interessant gelyk, en aangesien Envoy die meeste gebruik word as deel van die "istio" of bloot as die "ingangsbeheerder" van kubernetes, het die meeste mense dus nie dieselfde direkte interaksie daarmee as byvoorbeeld met tipiese Nginx- of Haproxy-installasies. As iets egter breek, sal dit goed wees om van binne af te verstaan ​​hoe dit werk. Ek het probeer om soveel as moontlik van die teks in Russies te vertaal, insluitend spesiale woorde, vir diegene wat dit pynlik vind om na te kyk, ek het die oorspronklikes tussen hakies gelos. Welkom onder kat.

Laevlak tegniese dokumentasie op die Envoy-kodebasis is tans taamlik yl. Om dit reg te stel, beplan ek om 'n reeks blogplasings oor die verskillende Gesant-substelsels te doen. Aangesien dit die eerste artikel is, laat weet my asseblief wat jy dink en waarin jy dalk in toekomstige artikels sal belangstel.

Een van die mees algemene tegniese vrae wat ek oor Envoy kry, is 'n versoek vir 'n lae-vlak beskrywing van die draadmodel wat gebruik word. In hierdie pos sal ek beskryf hoe Envoy verbindings na drade karteer, sowel as 'n beskrywing van die Thread Local Storage-stelsel wat intern gebruik word om kode meer parallel en werksaam te maak.

Beskrywing van drade (Threading-oorsig)

[Vertaling] Gesant-inrygmodel

Envoy gebruik drie verskillende tipes strome:

  • Hoof (hoof): Hierdie draad bestuur die begin en einde van die proses, alle XDS (xDiscovery Service) API-verwerking, insluitend DNS, gesondheidskontrole, algemene groepering en diensprosesbestuur (looptyd), statistiek-terugstelling, administrasie en algemene prosesbestuur - Linux-seine, warm herbegin , ens. Alles wat in hierdie draad gebeur is asynchronies en "nie-blokkerend". Oor die algemeen koördineer die hoofdraad alle kritiese prosesse van funksionaliteit wat nie 'n groot aantal SVE's benodig om te voltooi nie. Dit laat die meeste beheerkodes toe om geskryf te word asof dit enkeldraad is.
  • Werker: By verstek, Envoy skep 'n werkers draad vir elke hardeware draad in die stelsel, dit kan beheer word met die opsie --concurrency. Elke werker draad begin 'n "nie-blokkerende" gebeurtenis lus (gebeurtenis lus), wat verantwoordelik is om te luister (luister) na elke luisteraar (luisteraar), ten tyde van die skryf daarvan (29 Julie 2017) is daar geen versplintering (sharding) van die luisteraar (luisteraar), aanvaarding van nuwe verbindings, instansieering van die filterstapel vir die verbinding, en hantering van alle invoer/uitset (IO) bewerkings gedurende die leeftyd van die verbinding. Weereens, dit laat die meeste verbindingshanteringskodes toe om geskryf te word asof dit enkeldraad is.
  • Lêer (lêerspoel): Elke lêer wat Envoy skryf, meestal toegangslogboeke, het tans 'n onafhanklike blokkeerdraad. Dit is te wyte aan die feit dat skryf na lêers wat deur die lêerstelsel gekas word, selfs wanneer dit gebruik word O_NONBLOCK kan soms blokkeer (sug). Wanneer werkersdrade na 'n lêer moet skryf, word die data eintlik na 'n buffer in die geheue geskuif waar dit uiteindelik deur die draad gespoel word lêer spoel. Dit is een kodearea waar tegnies alle werkersdrade dieselfde slot kan blokkeer terwyl hulle probeer om die geheuebuffer te vul.

Verbindingshantering

Soos kortliks hierbo bespreek, luister alle werkersdrade na alle luisteraars sonder enige segmentering. Die kern word dus gebruik om op intelligente wyse ontvangde voetstukke na werkersdrade te stuur. Moderne pitte is oor die algemeen baie goed hiermee, hulle gebruik kenmerke soos I/O-prioriteitversterking om 'n draad met werk te probeer vul voordat hulle begin om ander drade te gebruik wat ook op dieselfde sok luister, en ook nie spinlock (Spinlock) gebruik om verwerk elke versoek.
Sodra 'n verbinding op 'n werkersdraad aanvaar is, verlaat dit nooit daardie draad nie. Alle verdere verwerking van die verbinding word geheel en al in die werkersdraad hanteer, insluitend enige aanstuurgedrag.

Dit het verskeie belangrike implikasies:

  • Alle verbindingspoele in Envoy is per werkersdraad. Dus, alhoewel HTTP/2-verbindingpoele net een verbinding met elke stroomop-gasheer op 'n slag maak, sal daar vier HTTP/2-verbindings per stroomop-gasheer in 'n bestendige toestand wees, as daar vier werkersdrade is.
  • Die rede waarom Envoy so werk, is dat deur alles op 'n enkele werkersdraad te hou, byna alle kode blokvry geskryf kan word en asof dit enkeldraad is. Hierdie ontwerp maak dit maklik om baie kode te skryf en skaal ongelooflik goed vir 'n byna onbeperkte aantal werkersdrade.
  • Een van die hoofbevindings is egter dat dit in terme van die doeltreffendheid van die geheuepoel en verbindings eintlik baie belangrik is om die parameter in te stel --concurrency. As u meer werkersdrade het as wat nodig is, sal u geheue mors, meer ledige verbindings skep en die treftempo van die verbindingspoel vertraag. By Lyft loop ons gesant-syspanhouers teen baie lae gelyktydigheid, so die werkverrigting is min of meer op gelyke voet met die dienste wat hulle langsaan sit. Ons gebruik Envoy as 'n randvolmag slegs met maksimum gelyktydigheid.

Wat beteken nie-blokkering

Die term "nie-blokkerend" is tot dusver 'n paar keer gebruik wanneer bespreek word hoe die hoof- en werkdrade werk. Alle kode is geskryf met die aanname dat niks ooit blokkeer nie. Dit is egter nie heeltemal waar nie (wat is nie heeltemal waar nie?).

Envoy gebruik verskeie lang prosesslotte:

  • Soos vroeër bespreek, wanneer toegangslogboeke geskryf word, verkry alle werkersdrade dieselfde slot voordat die in-geheue log buffer gevul word. Die slothoutyd behoort baie laag te wees, maar dit is moontlik dat hierdie slot onder hoë gelyktydigheid en hoë deurset betwis sal word.
  • Envoy gebruik 'n baie komplekse stelsel om statistieke te hanteer wat plaaslik op 'n draad is. Dit sal die onderwerp van 'n aparte pos wees. Ek sal egter kortliks noem dat dit as deel van die plaaslike verwerking van draadstatistieke soms nodig is om 'n slot op 'n sentrale "statistiekwinkel" aan te skaf. Hierdie slot moet nooit vereis word nie.
  • Die hoofdraad moet periodiek met alle werkersdrade koördineer. Dit word gedoen deur van die hoofdraad na werkersdrade te "plaas", en soms van werkersdrade terug na die hoofdraad. Die stuur vereis 'n slot sodat die gepubliseerde boodskap in tou gesit kan word vir latere aflewering. Hierdie slotte moet nooit swaar betwis word nie, maar hulle kan steeds tegnies gesluit word.
  • Wanneer Envoy 'n log na die stelselfoutstroom skryf (standaardfout), kry dit 'n proseswye slot. Oor die algemeen word Envoy se plaaslike aantekening as verskriklik beskou in terme van werkverrigting, so daar word nie veel aandag gegee aan die verbetering daarvan nie.
  • Daar is 'n paar ander ewekansige slotte, maar nie een van hulle is prestasie-kritiek nie en moet nooit betwis word nie.

Draad plaaslike berging

As gevolg van die manier waarop Envoy hoofdraadverantwoordelikhede skei van werkersdraadverantwoordelikhede, is daar 'n vereiste dat komplekse verwerking op die hoofdraad gedoen kan word en dan met 'n hoë mate van sameloop aan elke werkersdraad verskaf kan word. Hierdie afdeling beskryf die Envoy Thread Local Storage (TLS)-stelsel op 'n hoë vlak. In die volgende afdeling sal ek beskryf hoe dit gebruik word om 'n groepering te bestuur.
[Vertaling] Gesant-inrygmodel

Soos reeds beskryf, hanteer die hoofdraad byna al die bestuursfunksies en beheervlakfunksionaliteit in die Gesant-proses. Die beheervlak is hier 'n bietjie oorweldig, maar as dit gesien word in terme van die Gesant-proses self en vergelyk word met die aanstuur wat werkersdrade uitvoer, maak dit sin. As 'n algemene reël doen die hoofdraadproses 'n bietjie werk, en dan moet dit elke werkersdraad bywerk volgens die resultaat van hierdie werk, terwyl die werkersdraad nie 'n slot op elke toegang hoef te vestig nie.

Die TLS (Thread local storage) Envoy-stelsel werk soos volg:

  • Kode wat op die hoofdraad loop, kan 'n TLS-gleuf vir die hele proses toewys. Alhoewel dit abstrak is, is dit in die praktyk 'n indeks in 'n vektor, wat O(1)-toegang verskaf.
  • Die hoofdraad kan arbitrêre data op sy gleuf stel. Wanneer dit gedoen word, word die data na elke werkerdraad gepubliseer as 'n normale gebeurtenis in die gebeurtenislus.
  • Werkerdrade kan vanaf hul TLS-gleuf lees en enige draad-plaaslike data wat daar beskikbaar is, ophaal.

Alhoewel dit 'n baie eenvoudige en ongelooflike kragtige paradigma is wat baie ooreenstem met die RCU (Read-Copy-Update)-blokkeerkonsep. Werkerdrade sien in wese nooit enige dataveranderings in TLS-gleuwe terwyl die werk aan die gang is nie. Verandering vind slegs plaas gedurende die dormante tydperk tussen werkgebeurtenisse.

Envoy gebruik dit op twee verskillende maniere:

  • Deur verskillende data op elke werkersdraad te stoor, word toegang tot hierdie data verkry sonder enige blokkering.
  • Deur 'n gedeelde wyser na globale data in leesalleenmodus op elke werkersdraad te hou. Dus, elke werkersdraad het 'n dataverwysingtelling wat nie verminder kan word terwyl die werk gedoen word nie. Eers wanneer alle werkers kalmeer en nuwe gedeelde data oplaai, sal die ou data vernietig word. Dit is identies aan RCU.

Trosopdatering-draad

In hierdie afdeling sal ek beskryf hoe TLS (Thread local storage) gebruik word om 'n cluster te bestuur. Klusterbestuur sluit xDS- en/of DNS-API-verwerking en gesondheidskontrole in.
[Vertaling] Gesant-inrygmodel

Klustervloeibestuur sluit die volgende komponente en stappe in:

  1. Die groepbestuurder is 'n komponent binne Envoy wat alle bekende groepering stroomop, die CDS (Cluster Discovery Service) API, die SDS (Secret Discovery Service) en EDS (Endpoint Discovery Service) API's, DNS en aktiewe eksterne kontrole bestuur. Dit is verantwoordelik vir die skep van 'n "uiteindelik konsekwente" aansig van elke stroomop-kluster, wat die ontdekte gashere sowel as die gesondheidstatus insluit.
  2. Die gesondheidskontroleur doen 'n aktiewe gesondheidskontrole en rapporteer gesondheidstatusveranderinge aan die groepbestuurder.
  3. CDS (Cluster Discovery Service) / SDS (Secret Discovery Service) / EDS (Endpoint Discovery Service) / DNS word uitgevoer om groepslidmaatskap te bepaal. Die toestandsverandering word aan die groepbestuurder terugbesorg.
  4. Elke werkersdraad voer voortdurend 'n gebeurtenislus uit.
  5. Wanneer die klusterbestuurder bepaal dat die toestand vir die cluster verander het, skep dit 'n nuwe leesalleen-kiekie van die cluster en stuur dit na elke werkersdraad.
  6. Gedurende die volgende dormante tydperk sal die werkersdraad die momentopname in die toegekende TLS-gleuf opdateer.
  7. Tydens 'n I/O-gebeurtenis wat die gasheer moet bepaal om te balanseer, sal die lasbalanseerder die TLS (Thread local storage)-gleuf navraag doen vir inligting oor die gasheer. Dit vereis nie slotte nie. Let ook daarop dat TLS ook gebeurtenisse kan afvuur op verfris sodat lasbalanseerders en ander komponente kasgeheue, datastrukture, ensovoorts kan herbereken. Dit is buite die bestek van hierdie pos, maar word op verskeie plekke in die kode gebruik.

Deur die bogenoemde prosedure te gebruik, kan Envoy elke versoek verwerk sonder enige blokkering (behalwe dié wat voorheen beskryf is). Afgesien van die kompleksiteit van die TLS-kode self, hoef die meeste van die kode nie te verstaan ​​hoe multithreading werk nie en kan dit in enkeldraadmodus geskryf word. Dit maak dit makliker om die meeste van die kode te skryf, benewens uitstekende werkverrigting.

Ander substelsels wat van TLS gebruik maak

TLS (Thread local storage) en RCU (Read Copy Update) word wyd in Envoy gebruik.

Voorbeelde van gebruik:

  • Meganisme vir die verandering van funksionaliteit tydens uitvoering: Die huidige lys van geaktiveerde kenmerke word op die hoofdraad geëvalueer. Elke werkersdraad word dan voorsien van 'n leesalleen-snapshot met behulp van RCU-semantiek.
  • Roetetabelle vervang: Vir roetetabelle wat deur RDS (Route Discovery Service) verskaf word, word roetetabelle op die hoofdraad geskep. Die leesalleen-kiekie sal dan aan elke werkersdraad verskaf word deur gebruik te maak van RCU (Read Copy Update) semantiek. Dit maak die verandering van roetetabelle atoomdoeltreffend.
  • HTTP-kop-kas: Soos dit blyk, is HTTP-kopskrif per versoek (teen ~25K+ RPS per kern) redelik duur. Envoy bereken sentraal 'n kopskrif ongeveer elke halwe sekonde en verskaf dit aan elke werker via TLS en RCU.

Daar is ander gevalle, maar die vorige voorbeelde behoort 'n goeie begrip te gee van waarvoor TLS gebruik word.

Bekende prestasie slaggate

Alhoewel Envoy oor die algemeen redelik goed presteer, is daar 'n paar noemenswaardige gebiede wat aandag verg wanneer dit met baie hoë gelyktydigheid en deurset gebruik word:

  • Soos reeds in hierdie artikel beskryf, verkry tans alle werkersdrade 'n slot terwyl hulle na die toegangsloggeheuebuffer skryf. Hoë gelyktydigheid en hoë deurset sal vereis dat die toegangslogboeke vir elke werkersdraad saamgevoeg word teen die koste van buite-order aflewering wanneer na die finale lêer geskryf word. Alternatiewelik kan jy 'n aparte toegangslogboek vir elke werkersdraad skep.
  • Alhoewel die statistieke baie sterk geoptimaliseer is, met 'n baie hoë sameloop en deurset, is daar waarskynlik atoomstryd oor individuele statistieke. Die oplossing vir hierdie probleem is tellers per werker draad met periodieke terugstelling van sentrale tellers. Dit sal in 'n volgende pos bespreek word.
  • Die huidige argitektuur sal nie goed werk as Envoy ontplooi word in 'n scenario waar daar baie min verbindings is wat aansienlike hulpbronne benodig om te verwerk nie. Daar is geen waarborg dat skakels eweredig tussen werkersdrade versprei sal word nie. Dit kan opgelos word deur werkerverbindingsbalansering te implementeer, wat die uitruil van verbindings tussen werkerdrade sal toelaat.

Afsluiting

Die Envoy threading model is ontwerp vir gemak van programmering en massiewe parallelisme ten koste van potensieel verkwistende geheue en verbindings as dit nie korrek gekonfigureer is nie. Hierdie model laat dit baie goed presteer teen baie hoë draadtellings en deurvloei.
Soos ek kortliks op Twitter genoem het, kan die ontwerp ook bo-op 'n volledige gebruikersmodus-netwerkstapel soos DPDK (Data Plane Development Kit) loop, wat daartoe kan lei dat normale bedieners miljoene versoeke per sekonde met volle L7-verwerking hanteer . Dit sal baie interessant wees om te sien wat in die volgende paar jaar gebou gaan word.
Een laaste vinnige opmerking: Ek is al baie keer gevra hoekom ons C++ vir Envoy gekies het. Die rede is steeds dat dit steeds die enigste wydgebruikte produksievlaktaal is waarop die argitektuur wat in hierdie pos beskryf word, gebou kan word. C++ is beslis nie geskik vir alle of selfs baie projekte nie, maar vir sekere gebruiksgevalle is dit steeds die enigste hulpmiddel om die werk gedoen te kry.

Skakels na kode

Skakels na lêers met koppelvlakke en implementering van opskrifte wat in hierdie pos bespreek word:

Bron: will.com

Voeg 'n opmerking