Pe măsură ce trecem de la o aplicație monolitică la o arhitectură de microservicii, ne confruntăm cu noi provocări.
Într-o aplicație monolitică, este de obicei destul de ușor să determinați în ce parte a sistemului a apărut eroarea. Cel mai probabil, problema este în codul monolitului în sine sau în baza de date. Dar când începem să căutăm o problemă într-o arhitectură de microservicii, totul nu mai este atât de evident. Trebuie să găsim întreaga cale pe care a luat-o cererea de la început până la sfârșit și să o selectăm din sute de microservicii. Mai mult, multe dintre ele au și propriile facilități de stocare, care pot provoca și erori logice, precum și probleme cu performanța și toleranța la erori.
Caut de multă vreme un instrument care să ajute să facă față unor astfel de probleme (am scris despre asta pe Habré:
Urmărirea distribuită este o soluție comună la problema găsirii erorilor în sistemele distribuite. Dar ce se întâmplă dacă această abordare a colectării informațiilor despre interacțiunile rețelei nu a fost încă implementată în sistem sau, mai rău, într-o parte a sistemului funcționează deja corect, dar în parte nu, deoarece nu a fost adăugată la serviciile vechi ? Pentru a determina cauza exactă a unei probleme, este necesar să aveți o imagine completă a ceea ce se întâmplă în sistem. Este deosebit de important să înțelegem care microservicii sunt implicate în căile esențiale pentru afaceri.
Aici ne poate veni în ajutor abordarea rețelei de servicii, care se va ocupa de toate mașinile de colectare a informațiilor din rețea la un nivel mai scăzut decât serviciile în sine. Această abordare ne permite să interceptăm tot traficul și să-l analizăm din mers. Mai mult, aplicațiile nici nu trebuie să știe nimic despre asta.
Abordarea prin plasă de serviciu
Ideea principală a abordării rețelei de servicii este de a adăuga un alt strat de infrastructură peste rețea, care ne va permite să facem orice lucru cu interacțiunea inter-servicii. Majoritatea implementărilor funcționează după cum urmează: la fiecare microserviciu este adăugat un container sidecar suplimentar cu un proxy transparent, prin care este trecut tot traficul de intrare și de ieșire al serviciului. Și chiar acesta este locul unde putem face echilibrarea clienților, aplică politici de securitate, impunem restricții asupra numărului de solicitări și colectăm informații importante despre interacțiunea serviciilor în producție.
Soluții
Există deja mai multe implementări ale acestei abordări:
Drept urmare, ne-am uitat la exact ce capabilități avem nevoie în acest moment și am decis că principalul motiv pentru care am început să implementăm astfel de soluții a fost capacitatea de a colecta informații de urmărire din întregul sistem în mod transparent. De asemenea, am vrut să avem control asupra interacțiunii serviciilor și să facem diverse manipulări cu anteturile care sunt transferate între servicii.
Drept urmare, am ajuns la decizia noastră:
Netramesh
Principalele obiective ale noii soluții au fost resursele generale reduse și performanța ridicată. Dintre caracteristicile principale, ne-am dorit imediat să putem trimite în mod transparent intervale de urmărire către sistemul nostru Jaeger.
Astăzi, majoritatea soluțiilor cloud sunt implementate în Golang. Și, desigur, există motive pentru asta. Scrierea aplicațiilor de rețea în Golang care funcționează asincron cu I/O și se scalează pe nuclee după cum este necesar este convenabilă și destul de simplă. Și, ceea ce este de asemenea foarte important, performanța este suficientă pentru a rezolva această problemă. De aceea am ales și Golang.
productivitate
Ne-am concentrat eforturile pe atingerea productivității maxime. Pentru o soluție care este implementată lângă fiecare instanță a serviciului, este necesar un mic consum de RAM și timp CPU. Și, desigur, întârzierea răspunsului ar trebui să fie, de asemenea, mică.
Să vedem ce rezultate avem.
RAM
Netramesh consumă ~10Mb fără trafic și maxim 50Mb cu o încărcare de până la 10000 RPS per instanță.
Istio envoy proxy consumă întotdeauna ~300 Mb în clusterele noastre cu mii de instanțe. Acest lucru nu îi permite să fie scalat la întregul cluster.
Cu Netramesh am obținut o reducere de ~10 ori a consumului de memorie.
Procesor
Utilizarea procesorului este relativ egală sub sarcină. Depinde de numărul de solicitări pe unitatea de timp către sidecar. Valori la 3000 de solicitări pe secundă la vârf:
Mai există un punct important: Netramesh - o soluție fără plan de control și fără încărcare nu consumă timp CPU. Cu Istio, sidecar-urile actualizează întotdeauna punctele finale de serviciu. Ca rezultat, putem vedea această imagine fără încărcare:
Folosim HTTP/1 pentru comunicarea între servicii. Creșterea timpului de răspuns pentru Istio la proxy prin envoy a fost de până la 5-10 ms, ceea ce este destul de mult pentru serviciile care sunt gata să răspundă într-o milisecundă. Cu Netramesh, acest timp a scăzut la 0.5-2 ms.
Scalabilitate
Cantitatea mică de resurse consumată de fiecare proxy face posibilă plasarea acestuia lângă fiecare serviciu. Netramesh a fost creat în mod intenționat fără o componentă a planului de control pentru a menține pur și simplu fiecare sidecar ușor. Adesea, în soluțiile de rețea de serviciu, planul de control distribuie informații de descoperire a serviciului fiecărui sidecar. Odată cu acesta, vin și informații despre timeout-uri și setările de echilibrare. Toate acestea vă permit să faceți o mulțime de lucruri utile, dar, din păcate, umflă sidecar-urile în dimensiune.
Descoperirea serviciului
Netramesh nu adaugă niciun mecanism suplimentar pentru descoperirea serviciului. Tot traficul este transmis transparent prin netra sidecar.
Netramesh acceptă protocolul de aplicație HTTP/1. Pentru a-l defini, se folosește o listă configurabilă de porturi. De obicei, sistemul are mai multe porturi prin care are loc comunicarea HTTP. De exemplu, folosim 80, 8890, 8080 pentru interacțiunea dintre servicii și solicitări externe. În acest caz, acestea pot fi setate folosind o variabilă de mediu NETRA_HTTP_PORTS
.
Dacă utilizați Kubernetes ca orchestrator și mecanismul său de entitate Service pentru comunicarea intra-cluster între servicii, atunci mecanismul rămâne exact același. În primul rând, microserviciul obține o adresă IP a serviciului folosind kube-dns și deschide o nouă conexiune la acesta. Această conexiune este stabilită mai întâi cu netra-sidecar-ul local și toate pachetele TCP ajung inițial la netra. În continuare, netra-sidecar stabilește o legătură cu destinația inițială. NAT pe pod IP pe nod rămâne exact la fel ca și fără netra.
Urmărirea distribuită și redirecționarea contextului
Netramesh oferă funcționalitatea necesară pentru a trimite intervale de urmărire despre interacțiunile HTTP. Netra-sidecar analizează protocolul HTTP, măsoară întârzierile solicitărilor și extrage informațiile necesare din anteturile HTTP. În cele din urmă, obținem toate urmele într-un singur sistem Jaeger. Pentru o configurație fină, puteți utiliza și variabilele de mediu furnizate de biblioteca oficială
Dar aici e o problema. Până când serviciile nu generează și trimit un antet uber special, nu vom vedea intervale de urmărire conectate în sistem. Și de asta avem nevoie pentru a găsi rapid cauza problemelor. Aici, din nou, Netramesh are o soluție. Proxy-urile citesc anteturile HTTP și, dacă nu conțin ID-ul de urmărire uber, generează unul. Netramesh stochează, de asemenea, informații despre cererile de intrare și de ieșire într-un sidecar și le potrivește îmbogățindu-le cu anteturile necesare cererilor de ieșire. Tot ce trebuie să faci în servicii este să trimiți un singur antet X-Request-Id
, care poate fi configurat folosind o variabilă de mediu NETRA_HTTP_REQUEST_ID_HEADER_NAME
. Pentru a controla dimensiunea contextului în Netramesh, puteți seta următoarele variabile de mediu: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS
(timpul pentru care contextul va fi stocat) și NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL
(frecvența curățării contextului).
De asemenea, este posibil să combinați mai multe căi pe sistemul dvs. prin marcarea lor cu un simbol de sesiune special. Netra vă permite să instalați HTTP_HEADER_TAG_MAP
pentru a transforma antetele HTTP în etichete de urmărire corespunzătoare. Acest lucru poate fi util în special pentru testare. După trecerea testului funcțional, puteți vedea ce parte a sistemului a fost afectată prin filtrarea după cheia de sesiune corespunzătoare.
Determinarea sursei cererii
Pentru a determina de unde a venit cererea, puteți utiliza funcționalitatea de a adăuga automat un antet cu sursa. Utilizarea unei variabile de mediu NETRA_HTTP_X_SOURCE_HEADER_NAME
Puteți specifica un nume de antet care va fi instalat automat. Prin utilizarea NETRA_HTTP_X_SOURCE_VALUE
puteți seta valoarea la care va fi setat antetul X-Source pentru toate cererile trimise.
Acest lucru permite distribuția acestui antet util să fie distribuită uniform în întreaga rețea. Apoi îl puteți utiliza în servicii și îl puteți adăuga la jurnalele și valorile.
Dirijarea traficului și elementele interne Netramesh
Netramesh este format din două componente principale. Primul, netra-init, stabilește reguli de rețea pentru a intercepta traficul. El foloseste INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS
.
Instrumentul are și o caracteristică interesantă - rutarea probabilistică. Dacă utilizați Netramesh exclusiv pentru colectarea intervalelor de urmărire, atunci într-un mediu de producție puteți economisi resurse și puteți activa rutarea probabilistică folosind variabile NETRA_INBOUND_PROBABILITY
и NETRA_OUTBOUND_PROBABILITY
(de la 0 la 1). Valoarea implicită este 1 (tot traficul este interceptat).
După interceptarea cu succes, netra sidecar acceptă noua conexiune și folosește SO_ORIGINAL_DST
opțiunea socket pentru a obține destinația inițială. Netra deschide apoi o nouă conexiune la adresa IP originală și stabilește o comunicare TCP bidirecțională între părți, ascultând tot traficul care trece. Dacă portul este definit ca HTTP, Netra încearcă să îl analizeze și să îl urmărească. Dacă analiza HTTP eșuează, Netra revine la TCP și trimite în mod transparent octeții.
Construirea unui grafic de dependență
După ce am primit o cantitate mare de informații de urmărire în Jaeger, vreau să obțin un grafic complet al interacțiunilor din sistem. Dar dacă sistemul dvs. este destul de încărcat și miliarde de intervale de urmărire se acumulează pe zi, agregarea lor nu devine o sarcină atât de ușoară. Există o modalitate oficială de a face acest lucru:
Dacă utilizați Elasticsearch pentru a stoca intervale de urmărire, puteți utiliza
Cum se utilizează Netramesh
Netra poate fi adăugat cu ușurință la orice serviciu care rulează orice orchestrator. Puteți vedea un exemplu
Momentan, Netra nu are capacitatea de a implementa automat sidecar-uri la servicii, dar există planuri de implementare.
Viitorul Netramesh
scopul principal
În viitor, Netramesh va suporta alte protocoale de nivel de aplicație în afară de HTTP. Rutarea L7 va fi disponibilă în viitorul apropiat.
Utilizați Netramesh dacă întâmpinați probleme similare și scrieți-ne cu întrebări și sugestii.
Sursa: www.habr.com