Når vi bevæger os fra en monolitisk applikation til en mikroservicearkitektur, står vi over for nye udfordringer.
I en monolitisk applikation er det normalt ret nemt at bestemme, hvilken del af systemet fejlen opstod i. Sandsynligvis ligger problemet i selve monolittens kode eller i databasen. Men når vi begynder at lede efter et problem i en mikroservicearkitektur, er alt ikke længere så indlysende. Vi skal finde hele stien, som anmodningen tog fra start til slut, og vælge den fra hundredvis af mikrotjenester. Desuden har mange af dem også deres egne lagerfaciliteter, hvilket også kan forårsage logiske fejl, samt problemer med ydeevne og fejltolerance.
Jeg har længe ledt efter et værktøj, der kunne hjælpe med at klare sådanne problemer (jeg skrev om dette på Habré:
Distribueret sporing er en almindelig løsning på problemet med at finde fejl i distribuerede systemer. Men hvad nu hvis denne tilgang til indsamling af information om netværksinteraktioner endnu ikke er implementeret i systemet, eller værre, i en del af systemet fungerer den allerede korrekt, men til dels ikke, da den ikke er blevet tilføjet til gamle tjenester ? For at bestemme den nøjagtige årsag til et problem, er det nødvendigt at have et komplet billede af, hvad der sker i systemet. Det er især vigtigt at forstå, hvilke mikrotjenester der er involveret i vigtige forretningskritiske veje.
Her kan service mesh-tilgangen komme os til hjælp, som vil håndtere alle maskineri til indsamling af netværksinformation på et niveau, der er lavere end tjenesterne selv opererer. Denne tilgang giver os mulighed for at opsnappe al trafik og analysere den på farten. Desuden behøver applikationer ikke engang at vide noget om det.
Service mesh tilgang
Hovedideen med service mesh-tilgangen er at tilføje endnu et infrastrukturlag over netværket, som vil give os mulighed for at gøre hvad som helst med inter-service interaktion. De fleste implementeringer fungerer som følger: En ekstra sidevognsbeholder med en gennemsigtig proxy tilføjes til hver mikrotjeneste, hvorigennem al indgående og udgående trafik af tjenesten sendes. Og det er netop det sted, hvor vi kan foretage klientbalancering, anvende sikkerhedspolitikker, pålægge begrænsninger for antallet af anmodninger og indsamle vigtig information om interaktionen mellem tjenester i produktionen.
Решения
Der er allerede flere implementeringer af denne tilgang:
Som et resultat kiggede vi på præcis, hvilke muligheder vi havde brug for lige nu, og besluttede, at hovedårsagen til, at vi begyndte at implementere sådanne løsninger, var evnen til at indsamle sporingsinformation fra hele systemet gennemsigtigt. Vi ønskede også at have kontrol over interaktionen af tjenester og lave forskellige manipulationer med de overskrifter, der overføres mellem tjenester.
Som et resultat kom vi til vores beslutning:
Netramesh
Hovedmålene med den nye løsning var lav ressourceoverhead og høj ydeevne. Blandt hovedfunktionerne ønskede vi straks at være i stand til transparent at sende sporingsspænd til vores Jaeger-system.
I dag er de fleste cloud-løsninger implementeret i Golang. Og det er der selvfølgelig grunde til. At skrive netværksapplikationer i Golang, der arbejder asynkront med I/O og skalerer på tværs af kerner efter behov, er praktisk og ganske enkelt. Og hvad der også er meget vigtigt, ydeevnen er tilstrækkelig til at løse dette problem. Derfor valgte vi også Golang.
Ydelse
Vi har fokuseret vores indsats på at opnå maksimal produktivitet. For en løsning, der installeres ved siden af hver instans af tjenesten, kræves et lille forbrug af RAM og CPU-tid. Og svarforsinkelsen skal selvfølgelig også være lille.
Lad os se, hvilke resultater vi fik.
RAM
Netramesh forbruger ~10 Mb uden trafik og 50 Mb maksimalt med en belastning på op til 10000 RPS pr. instans.
Istio envoy proxy bruger altid ~300 Mb i vores klynger med tusindvis af forekomster. Dette tillader ikke, at den skaleres til hele klyngen.
Med Netramesh fik vi en ~10x reduktion i hukommelsesforbrug.
CPU
CPU-brug er relativt lige under belastning. Det afhænger af antallet af anmodninger pr. tidsenhed til sidevognen. Værdier ved 3000 forespørgsler i sekundet ved peak:
Der er endnu et vigtigt punkt: Netramesh - en løsning uden kontrolplan og uden belastning bruger ikke CPU-tid. Med Istio opdaterer sidevogne altid serviceendepunkter. Som et resultat kan vi se dette billede uden belastning:
Vi bruger HTTP/1 til kommunikation mellem tjenester. Stigningen i responstid for Istio ved proxying via envoy var op til 5-10ms, hvilket er ret meget for tjenester, der er klar til at svare på et millisekund. Med Netramesh er denne tid faldet til 0.5-2ms.
Skalerbarhed
Den lille mængde ressourcer, der forbruges af hver proxy, gør det muligt at placere den ved siden af hver tjeneste. Netramesh blev med vilje skabt uden en kontrolplankomponent for blot at holde hver sidevogn let. Ofte i servicenetløsninger distribuerer kontrolplanet serviceopdagelsesinformation til hver sidevogn. Sammen med det kommer information om timeouts og balanceringsindstillinger. Alt dette giver dig mulighed for at gøre en masse nyttige ting, men desværre blæser det sidevogne i størrelse.
Service opdagelse
Netramesh tilføjer ingen yderligere mekanismer til serviceopdagelse. Al trafik proxes transparent gennem netra sidevogn.
Netramesh understøtter HTTP/1-applikationsprotokol. For at definere det, bruges en konfigurerbar liste over porte. Systemet har typisk flere porte, hvorigennem HTTP-kommunikation sker. For eksempel bruger vi 80, 8890, 8080 til interaktion mellem tjenester og eksterne anmodninger. I dette tilfælde kan de indstilles ved hjælp af en miljøvariabel NETRA_HTTP_PORTS
.
Hvis du bruger Kubernetes som en orkestrator og dens Service-entitetsmekanisme til intra-cluster-kommunikation mellem tjenester, så forbliver mekanismen nøjagtig den samme. Først opnår mikrotjenesten en tjeneste-IP-adresse ved hjælp af kube-dns og åbner en ny forbindelse til den. Denne forbindelse etableres først med den lokale netra-sidecar, og alle TCP-pakker ankommer i starten til netra. Dernæst etablerer netra-sidecar en forbindelse med den oprindelige destination. NAT på pod IP på noden forbliver nøjagtig den samme som uden netra.
Distribueret sporing og kontekstvideresendelse
Netramesh giver den nødvendige funktionalitet til at sende sporingsspænd om HTTP-interaktioner. Netra-sidecar analyserer HTTP-protokollen, måler anmodningsforsinkelser og udtrækker de nødvendige oplysninger fra HTTP-headere. I sidste ende får vi alle sporene i et enkelt Jaeger-system. Til finmasket konfiguration kan du også bruge miljøvariablerne fra det officielle bibliotek
Men der er et problem. Indtil tjenester genererer og sender en speciel uber-header, vil vi ikke se forbundne sporingsspænd i systemet. Og det er det, vi skal bruge for hurtigt at finde årsagen til problemerne. Her har Netramesh igen en løsning. Proxyer læser HTTP-headere og genererer en, hvis de ikke indeholder uber-sporings-id'et. Netramesh gemmer også information om indgående og udgående anmodninger i en sidevogn og matcher dem ved at berige dem med de nødvendige udgående anmodningsheaders. Alt du skal gøre i tjenesterne er kun at sende én header X-Request-Id
, som kan konfigureres ved hjælp af en miljøvariabel NETRA_HTTP_REQUEST_ID_HEADER_NAME
. For at kontrollere størrelsen af konteksten i Netramesh kan du indstille følgende miljøvariabler: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS
(det tidspunkt, hvor konteksten vil blive gemt) og NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL
(hyppighed af kontekstoprydning).
Det er også muligt at kombinere flere stier på dit system ved at markere dem med et særligt sessionstoken. Netra giver dig mulighed for at installere HTTP_HEADER_TAG_MAP
at omdanne HTTP-headere til tilsvarende sporingsspændingstags. Dette kan især være nyttigt til test. Efter at have bestået funktionstesten kan du se, hvilken del af systemet, der blev påvirket af filtrering efter den tilsvarende sessionsnøgle.
Bestemmelse af anmodningskilden
For at bestemme, hvor anmodningen kom fra, kan du bruge funktionaliteten til automatisk at tilføje en header med kilden. Brug af en miljøvariabel NETRA_HTTP_X_SOURCE_HEADER_NAME
Du kan angive et headernavn, der automatisk installeres. Ved hjælp af NETRA_HTTP_X_SOURCE_VALUE
du kan indstille den værdi, som X-Source-headeren indstilles til for alle udgående anmodninger.
Dette gør det muligt at distribuere denne nyttige header ensartet over hele netværket. Så kan du bruge det i tjenester og tilføje det til logfiler og metrics.
Trafik routing og Netramesh internals
Netramesh består af to hovedkomponenter. Den første, netra-init, sætter netværksregler for at opsnappe trafik. Han bruger INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS
.
Værktøjet har også en interessant funktion - probabilistisk routing. Hvis du udelukkende bruger Netramesh til at indsamle sporingsspænd, kan du i et produktionsmiljø spare ressourcer og aktivere probabilistisk routing ved hjælp af variabler NETRA_INBOUND_PROBABILITY
и NETRA_OUTBOUND_PROBABILITY
(fra 0 til 1). Standardværdien er 1 (al trafik opfanges).
Efter vellykket aflytning accepterer netra sidevogn den nye forbindelse og bruger SO_ORIGINAL_DST
socket mulighed for at få den oprindelige destination. Netra åbner derefter en ny forbindelse til den oprindelige IP-adresse og etablerer to-vejs TCP-kommunikation mellem parterne og lytter til al trafik, der passerer igennem. Hvis porten er defineret som HTTP, forsøger Netra at parse og spore den. Hvis HTTP-parsing mislykkes, falder Netra tilbage til TCP og proxyer transparent bytes.
Opbygning af en afhængighedsgraf
Efter at have modtaget en stor mængde sporingsinformation i Jaeger, ønsker jeg at få en komplet graf over interaktioner i systemet. Men hvis dit system er ret belastet, og der akkumuleres milliarder af sporingsspænd om dagen, bliver det ikke så let at samle dem. Der er en officiel måde at gøre dette på:
Hvis du bruger Elasticsearch til at gemme sporingsspænd, kan du bruge
Sådan bruger du Netramesh
Netra kan nemt tilføjes til enhver tjeneste, der kører enhver orkestrator. Du kan se et eksempel
Netra har i øjeblikket ikke mulighed for automatisk at implementere sidevogne til tjenester, men der er planer om implementering.
Fremtiden for Netramesh
hovedmål
I fremtiden vil Netramesh understøtte andre applikationslagsprotokoller udover HTTP. L7-routing vil være tilgængelig i den nærmeste fremtid.
Brug Netramesh, hvis du støder på lignende problemer, og skriv til os med spørgsmål og forslag.
Kilde: www.habr.com