[Tulkojums] Sūtņa vītnes modelis

Raksta tulkojums: Envoy vītņu modelis — https://blog.envoyproxy.io/envoy-threading-model-a8d44b922310

Šis raksts man likās diezgan interesants, un tā kā Envoy visbiežāk tiek izmantots kā daļa no “istio” vai vienkārši kā kubernetes “ieejas kontrolieris”, lielākajai daļai cilvēku ar to nav tādas tiešas mijiedarbības kā, piemēram, ar tipisku Nginx vai Haproxy instalācijas. Tomēr, ja kaut kas saplīst, būtu labi saprast, kā tas darbojas no iekšpuses. Es centos pēc iespējas vairāk teksta pārtulkot krieviski, arī īpašus vārdus, tiem, kam uz to skatīties ir sāpīgi, oriģinālus atstāju iekavās. Laipni lūdzam kaķī.

Zema līmeņa tehniskā dokumentācija Envoy kodu bāzei pašlaik ir diezgan niecīga. Lai to novērstu, es plānoju izveidot virkni emuāra ierakstu par dažādām Envoy apakšsistēmām. Tā kā šis ir pirmais raksts, lūdzu, dariet man zināmu, ko domājat un kas jūs varētu interesēt nākamajos rakstos.

Viens no visbiežāk uzdotajiem tehniskajiem jautājumiem par Envoy ir lūgt zema līmeņa aprakstu par izmantoto vītņu modeli. Šajā ziņojumā es aprakstīšu, kā Envoy kartē savienojumus ar pavedieniem, kā arī Thread Local Storage sistēmu, ko tā izmanto iekšēji, lai padarītu kodu paralēlāku un augstas veiktspējas.

Vītņu pārskats

[Tulkojums] Sūtņa vītnes modelis

Envoy izmanto trīs dažādu veidu straumes:

  • Galvenais: Šis pavediens kontrolē procesa palaišanu un izbeigšanu, visu XDS (xDiscovery Service) API apstrādi, tostarp DNS, stāvokļa pārbaudi, vispārējo klasteru un izpildlaika pārvaldību, statistikas atiestatīšanu, administrēšanu un vispārējo procesu pārvaldību — Linux signālus. karstā restartēšana utt. kas notiek šajā pavedienā, ir asinhrons un "nebloķējošs". Kopumā galvenais pavediens koordinē visus kritiskos funkcionalitātes procesus, kuru darbībai nav nepieciešams liels CPU daudzums. Tas ļauj lielāko daļu kontroles koda rakstīt tā, it kā tas būtu ar vienu pavedienu.
  • Strādnieks: Pēc noklusējuma Envoy izveido darbinieka pavedienu katram sistēmas aparatūras pavedienam, to var kontrolēt, izmantojot opciju --concurrency. Katrs darbinieka pavediens palaiž “nebloķējošu” notikumu cilpu, kas ir atbildīga par katra klausītāja noklausīšanos; rakstīšanas laikā (29. gada 2017. jūlijā) nav klausītāja sadalīšanas, jaunu savienojumu pieņemšanas, filtru steka instantiances. savienojumu un visu ievades/izvades (IO) darbību apstrādi savienojuma darbības laikā. Atkal, tas ļauj lielāko daļu savienojuma apstrādes koda rakstīt tā, it kā tas būtu viens pavediens.
  • Failu skalošanas līdzeklis: Katram failam, ko Envoy raksta, galvenokārt piekļuves žurnāliem, pašlaik ir neatkarīgs bloķēšanas pavediens. Tas ir saistīts ar faktu, ka ierakstīšana failos, kas saglabāti failu sistēmā, pat tad, ja to lietojat O_NONBLOCK dažreiz var aizsprostot (nopūta). Kad darbinieka pavedieniem ir jāraksta failā, dati faktiski tiek pārvietoti uz buferi atmiņā, kur tie galu galā tiek izskaloti caur pavedienu. failu flush. Šis ir viens no koda apgabaliem, kurā tehniski visi darbinieku pavedieni var bloķēt vienu un to pašu bloķēšanu, mēģinot aizpildīt atmiņas buferi.

Savienojuma apstrāde

Kā īsi minēts iepriekš, visi darbinieku pavedieni klausās visus klausītājus bez jebkādas šķelšanās. Tādējādi kodols tiek izmantots, lai graciozi nosūtītu pieņemtās ligzdas uz darbinieku pavedieniem. Mūsdienu kodoli parasti ir ļoti labi šajā ziņā, tie izmanto tādas funkcijas kā ievades/izvades (IO) prioritātes pastiprināšana, lai mēģinātu aizpildīt pavedienu ar darbu, pirms tie sāk izmantot citus pavedienus, kas arī klausās tajā pašā ligzdā, kā arī neizmanto round robin. bloķēšana (Spinlock), lai apstrādātu katru pieprasījumu.
Kad savienojums tiek pieņemts darbinieka pavedienā, tas nekad neatstāj šo pavedienu. Visa turpmākā savienojuma apstrāde tiek pilnībā apstrādāta darbinieka pavedienā, tostarp jebkura pārsūtīšanas darbība.

Tam ir vairākas svarīgas sekas:

  • Visi savienojumu pūli programmā Envoy ir piešķirti darbinieka pavedienam. Tātad, lai gan HTTP/2 savienojumu pūli vienlaikus veido tikai vienu savienojumu ar katru augšupējo resursdatoru, ja ir četri darbinieka pavedieni, stabilā stāvoklī katram augšpus resursdatoram būs četri HTTP/2 savienojumi.
  • Iemesls, kāpēc Envoy darbojas šādi, ir tas, ka, saglabājot visu vienā darbinieka pavedienā, gandrīz visu kodu var ierakstīt bez bloķēšanas un tā, it kā tas būtu viens pavediens. Šis dizains ļauj viegli uzrakstīt daudz koda un neticami labi mērogot līdz gandrīz neierobežotam skaitam darbinieku pavedienu.
  • Tomēr viens no galvenajiem aspektiem ir tas, ka no atmiņas baseina un savienojuma efektivitātes viedokļa patiesībā ir ļoti svarīgi konfigurēt --concurrency. Ja ir vairāk darbinieku pavedienu, nekā nepieciešams, tiks iztērēta atmiņa, tiks izveidots vairāk dīkstāves savienojumu un samazināsies savienojumu apkopošanas ātrums. Uzņēmums Lyft mūsu sūtņa blakusvāģu konteineri darbojas ar ļoti zemu vienlaicīgumu, tāpēc veiktspēja aptuveni atbilst pakalpojumiem, kuriem tie atrodas blakus. Mēs palaižam Envoy kā malas starpniekserveri tikai maksimāli vienlaicīgi.

Ko nozīmē nebloķēšana?

Termins "nebloķēšana" līdz šim ir izmantots vairākas reizes, apspriežot galveno un darba pavedienu darbību. Viss kods ir rakstīts, pieņemot, ka nekas nekad nav bloķēts. Tomēr tā nav pilnīga taisnība (kas nav pilnīgi taisnība?).

Envoy izmanto vairākas ilgstošas ​​​​procesa bloķēšanas:

  • Kā minēts, rakstot piekļuves žurnālus, visi darbinieka pavedieni iegūst vienu un to pašu bloķēšanu, pirms tiek aizpildīts atmiņā esošā žurnāla buferis. Slēdzenes turēšanas laikam jābūt ļoti zemam, taču ir iespējams, ka slēdzeni var apstrīdēt ar augstu vienlaicīgumu un lielu caurlaidspēju.
  • Envoy izmanto ļoti sarežģītu sistēmu, lai apstrādātu statistiku, kas ir lokāla pavedienam. Tā būs atsevišķa ieraksta tēma. Tomēr es īsi pieminēšu, ka, apstrādājot pavedienu statistiku lokāli, dažkārt ir jāiegādājas centrālā "statistikas veikala" atslēga. Šo bloķēšanu nekad nevajadzētu pieprasīt.
  • Galvenais pavediens periodiski jāsaskaņo ar visiem darbinieka pavedieniem. Tas tiek darīts, "publicējot" no galvenā pavediena uz darbinieku pavedieniem un dažreiz no darbinieka pavedieniem atpakaļ uz galveno pavedienu. Sūtīšanai ir nepieciešama bloķēšana, lai publicēto ziņojumu varētu ievietot rindā vēlākai piegādei. Šīs slēdzenes nekad nevajadzētu nopietni apstrīdēt, taču tās joprojām var tehniski bloķēt.
  • Kad Envoy ieraksta žurnālu sistēmas kļūdu straumē (standarta kļūda), tas iegūst bloķēšanu visam procesam. Kopumā Envoy vietējā mežizstrāde tiek uzskatīta par briesmīgu no veiktspējas viedokļa, tāpēc tās uzlabošanai nav pievērsta liela uzmanība.
  • Ir dažas citas nejaušas slēdzenes, taču nevienai no tām nav būtiskas veiktspējas, un tās nekad nevajadzētu apstrīdēt.

Pavedienu lokālā krātuve

Tā kā sūtnis nodala galvenā pavediena pienākumus no darbinieka pavediena pienākumiem, pastāv prasība, ka galvenajā pavedienā var veikt sarežģītu apstrādi un pēc tam nodrošināt to katram darbinieka pavedienam ļoti vienlaicīgi. Šajā sadaļā ir aprakstīta sūtņa pavediena vietējā krātuve (TLS) augstā līmenī. Nākamajā sadaļā es aprakstīšu, kā tas tiek izmantots klastera pārvaldīšanai.
[Tulkojums] Sūtņa vītnes modelis

Kā jau aprakstīts, galvenais pavediens apstrādā praktiski visas vadības un vadības plaknes funkcionalitātes sūtņa procesā. Šeit vadības plakne ir nedaudz pārslogota, taču, aplūkojot to pašā sūtņa procesā un salīdzinot to ar pārsūtīšanu, ko veic darbinieka pavedieni, tas ir loģiski. Vispārējais noteikums ir tāds, ka galvenā pavediena process veic noteiktu darbu, un pēc tam tam ir jāatjaunina katrs darbinieka pavediens atbilstoši šī darba rezultātam. šajā gadījumā darbinieka pavedienam nav jāiegūst bloķēšana katrai piekļuvei.

Sūtņa TLS (pavedienu lokālā krātuve) sistēma darbojas šādi:

  • Kods, kas darbojas galvenajā pavedienā, var piešķirt TLS slotu visam procesam. Lai gan tas ir abstrahēts, praksē tas ir vektora indekss, kas nodrošina O(1) piekļuvi.
  • Galvenais pavediens savā slotā var instalēt patvaļīgus datus. Kad tas ir izdarīts, dati tiek publicēti katrā darbinieka pavedienā kā parasts notikumu cilpas notikums.
  • Darbinieku pavedieni var lasīt no sava TLS slota un izgūt visus tajā pieejamos pavedienu lokālos datus.

Lai gan tā ir ļoti vienkārša un neticami spēcīga paradigma, tā ir ļoti līdzīga RCU (lasīšanas-kopēšanas-atjaunināšanas) bloķēšanas koncepcijai. Būtībā darbinieku pavedieni nekad neredz datu izmaiņas TLS slotos, kamēr darbs darbojas. Izmaiņas notiek tikai atpūtas periodā starp darba notikumiem.

Sūtnis to izmanto divos dažādos veidos:

  • Saglabājot dažādus datus katrā darbinieka pavedienā, datiem var piekļūt bez jebkādas bloķēšanas.
  • Uzturot koplietotu rādītāju uz globālajiem datiem tikai lasīšanas režīmā katrā darbinieka pavedienā. Tādējādi katram darbinieka pavedienam ir datu atsauces skaits, ko nevar samazināt, kamēr darbs darbojas. Tikai tad, kad visi darbinieki nomierināsies un augšupielādēs jaunus kopīgotos datus, vecie dati tiks iznīcināti. Tas ir identisks RCU.

Klasteru atjaunināšanas pavedienu veidošana

Šajā sadaļā es aprakstīšu, kā TLS (pavedienu lokālā krātuve) tiek izmantots klastera pārvaldībai. Klasteru pārvaldība ietver xDS API un/vai DNS apstrādi, kā arī veselības pārbaudi.
[Tulkojums] Sūtņa vītnes modelis

Klasteru plūsmas pārvaldība ietver šādus komponentus un darbības:

  1. Klasteru pārvaldnieks ir sūtņa komponents, kas pārvalda visas zināmās klasteru augšpuses, klasteru atklāšanas pakalpojuma (CDS) API, slepenā atklāšanas pakalpojuma (SDS) un galapunkta noteikšanas pakalpojuma (EDS) API, DNS un aktīvās ārējās pārbaudes. Tas ir atbildīgs par "galu galā konsekventa" skata izveidi par katru augšupējo klasteru, kas ietver atklātos saimniekdatorus, kā arī veselības stāvokli.
  2. Veselības pārbaudītājs veic aktīvo veselības pārbaudi un ziņo par veselības stāvokļa izmaiņām klastera pārvaldniekam.
  3. CDS (klasteru noteikšanas pakalpojums) / SDS (slepenais meklēšanas pakalpojums) / EDS (gala punkta noteikšanas pakalpojums) / DNS tiek veikti, lai noteiktu klastera dalību. Stāvokļa izmaiņas tiek atgrieztas klastera pārvaldniekam.
  4. Katrs darbinieka pavediens nepārtraukti izpilda notikumu cilpu.
  5. Kad klastera pārvaldnieks nosaka, ka klastera stāvoklis ir mainījies, tas izveido jaunu tikai lasāmu klastera stāvokļa momentuzņēmumu un nosūta to katram darbinieka pavedienam.
  6. Nākamajā klusajā periodā darbinieka pavediens atjauninās momentuzņēmumu piešķirtajā TLS slotā.
  7. I/O notikuma laikā, kam ir jānosaka resursdatora slodzes līdzsvars, slodzes līdzsvarotājs pieprasīs TLS (pavedienu lokālās atmiņas) slotu, lai iegūtu informāciju par resursdatoru. Tam nav nepieciešamas slēdzenes. Ņemiet vērā arī to, ka TLS var arī aktivizēt atjaunināšanas notikumus, lai slodzes balansētāji un citi komponenti varētu pārrēķināt kešatmiņas, datu struktūras utt. Tas ir ārpus šīs ziņas darbības jomas, taču tiek izmantots dažādās koda vietās.

Izmantojot iepriekš minēto procedūru, sūtnis var apstrādāt katru pieprasījumu bez jebkādas bloķēšanas (izņemot gadījumus, kas aprakstīti iepriekš). Neatkarīgi no paša TLS koda sarežģītības, lielākajai daļai koda nav jāsaprot, kā darbojas daudzpavedienu izveide, un to var rakstīt vienā pavedienā. Tas padara lielāko daļu koda vieglāk ierakstāmu, kā arī nodrošina izcilu veiktspēju.

Citas apakšsistēmas, kas izmanto TLS

TLS (pavedienu lokālā krātuve) un RCU (lasīšanas kopijas atjauninājums) tiek plaši izmantoti programmā Envoy.

Lietošanas piemēri:

  • Mehānisms funkcionalitātes maiņai izpildes laikā: Pašreizējais iespējoto funkcionalitātes saraksts tiek aprēķināts galvenajā pavedienā. Pēc tam katram darbinieka pavedienam tiek piešķirts tikai lasāms momentuzņēmums, izmantojot RCU semantiku.
  • Maršruta tabulu nomaiņa: maršruta tabulām, ko nodrošina RDS (maršruta noteikšanas pakalpojums), maršruta tabulas tiek izveidotas galvenajā pavedienā. Tikai lasāms momentuzņēmums pēc tam tiks nodrošināts katram darbinieka pavedienam, izmantojot RCU (lasīšanas kopēšanas atjauninājuma) semantiku. Tas padara maršruta tabulu maiņu atomiski efektīvu.
  • HTTP galvenes kešatmiņa: Kā izrādās, HTTP galvenes aprēķināšana katram pieprasījumam (palaižot ~25K+ RPS uz kodolu) ir diezgan dārga. Envoy centralizēti aprēķina galveni aptuveni ik pēc pussekundes un nodrošina to katram darbiniekam, izmantojot TLS un RCU.

Ir arī citi gadījumi, taču iepriekšējiem piemēriem vajadzētu sniegt labu izpratni par to, kam tiek izmantots TLS.

Zināmas veiktspējas nepilnības

Lai gan Envoy kopumā darbojas diezgan labi, ir dažas ievērojamas jomas, kurām jāpievērš uzmanība, ja to lieto ar ļoti augstu vienlaicīgumu un caurlaidspēju:

  • Kā aprakstīts šajā rakstā, pašlaik visi darbinieka pavedieni iegūst bloķēšanu, rakstot piekļuves žurnāla atmiņas buferī. Augstas vienlaicības un lielas caurlaidspējas gadījumā, rakstot galīgajā failā, piekļuves žurnāli būs jāsagrupē katram darbinieka pavedienam uz ārpuskārtas piegādes rēķina. Varat arī izveidot atsevišķu piekļuves žurnālu katram darbinieka pavedienam.
  • Lai gan statistika ir ļoti optimizēta, ar ļoti augstu vienlaicīgumu un caurlaidspēju, iespējams, radīsies strīds par atsevišķu statistiku. Šīs problēmas risinājums ir skaitītāji katram darbinieka pavedienam ar periodisku centrālo skaitītāju atiestatīšanu. Tas tiks apspriests nākamajā ierakstā.
  • Pašreizējā arhitektūra nedarbosies labi, ja Envoy tiks izvietots scenārijā, kurā ir ļoti maz savienojumu, kuriem nepieciešami ievērojami apstrādes resursi. Nav garantijas, ka savienojumi tiks vienmērīgi sadalīti starp darba vītnēm. To var atrisināt, ieviešot strādnieku savienojumu balansēšanu, kas ļaus apmainīties ar savienojumiem starp strādnieku pavedieniem.

Secinājums

Envoy vītņu modelis ir izstrādāts, lai nodrošinātu vieglu programmēšanu un masveida paralēlismu uz potenciāli izšķērdīgas atmiņas un savienojumu rēķina, ja tas nav pareizi konfigurēts. Šis modelis ļauj tam ļoti labi darboties ar ļoti lielu pavedienu skaitu un caurlaidspēju.
Kā jau īsi minēju vietnē Twitter, dizains var darboties arī pilna lietotāja režīma tīkla steksā, piemēram, DPDK (Data Plane Development Kit), kā rezultātā parastie serveri apstrādā miljoniem pieprasījumu sekundē ar pilnu L7 apstrādi. Būs ļoti interesanti redzēt, kas tiks uzbūvēts tuvāko gadu laikā.
Pēdējais īss komentārs: man daudzas reizes ir jautāts, kāpēc mēs izvēlējāmies C++ priekš Envoy. Iemesls joprojām ir tāds, ka tā joprojām ir vienīgā plaši izmantotā industriālā līmeņa valoda, kurā var uzbūvēt šajā amatā aprakstīto arhitektūru. C++ noteikti nav piemērots visiem vai pat daudziem projektiem, taču noteiktiem lietošanas gadījumiem tas joprojām ir vienīgais rīks, lai paveiktu darbu.

Saites uz kodu

Saites uz failiem ar interfeisiem un galveņu ieviešanu, kas apspriesti šajā ziņojumā:

Avots: www.habr.com

Pievieno komentāru