Netramesh - lättviktslösning för servicenät

När vi går från en monolitisk applikation till en mikrotjänstarkitektur står vi inför nya utmaningar.

I en monolitisk applikation är det vanligtvis ganska lätt att avgöra i vilken del av systemet felet uppstod. Troligtvis ligger problemet i koden för själva monoliten eller i databasen. Men när vi börjar leta efter ett problem i en mikrotjänstarkitektur är allt inte längre så självklart. Vi måste hitta hela vägen som begäran tog från början till slut och välja den från hundratals mikrotjänster. Dessutom har många av dem också sina egna lagringsmöjligheter, vilket också kan orsaka logiska fel, liksom problem med prestanda och feltolerans.

Netramesh - lättviktslösning för servicenät

Jag har letat länge efter ett verktyg som skulle hjälpa till att hantera sådana problem (jag skrev om detta på Habré: 1, 2), men till slut gjorde jag min egen öppen källkodslösning. I den här artikeln pratar jag om fördelarna med servicemesh-metoden och delar ett nytt verktyg för dess implementering.

Distribuerad spårning är en vanlig lösning på problemet med att hitta fel i distribuerade system. Men vad händer om detta tillvägagångssätt för att samla in information om nätverksinteraktioner ännu inte har implementerats i systemet, eller ännu värre, i en del av systemet fungerar det redan korrekt, men delvis inte, eftersom det inte har lagts till i gamla tjänster ? För att fastställa den exakta grundorsaken till ett problem är det nödvändigt att ha en fullständig bild av vad som händer i systemet. Det är särskilt viktigt att förstå vilka mikrotjänster som är involverade i viktiga affärskritiska vägar.

Här kan servicemesh-metoden komma till vår hjälp, som kommer att hantera alla maskiner för att samla in nätverksinformation på en nivå som är lägre än vad tjänsterna själva fungerar. Detta tillvägagångssätt gör att vi kan fånga upp all trafik och analysera den i farten. Dessutom behöver applikationer inte ens veta något om det.

Service mesh tillvägagångssätt

Huvudidén med servicemesh-metoden är att lägga till ytterligare ett infrastrukturlager över nätverket, vilket gör att vi kan göra vad som helst med inter-service interaktion. De flesta implementeringar fungerar enligt följande: en extra sidovagnsbehållare med en transparent proxy läggs till varje mikrotjänst, genom vilken all inkommande och utgående trafik för tjänsten skickas. Och det här är själva platsen där vi kan göra klientbalansering, tillämpa säkerhetspolicyer, införa begränsningar för antalet förfrågningar och samla in viktig information om interaktionen mellan tjänster i produktionen.

Netramesh - lättviktslösning för servicenät

Решения

Det finns redan flera implementeringar av detta tillvägagångssätt: Samma и linkerd2. De ger många funktioner ur lådan. Men samtidigt kommer det stora omkostnader på resurserna. Dessutom, ju större kluster ett sådant system fungerar i, desto mer resurser kommer att krävas för att underhålla den nya infrastrukturen. På Avito driver vi kubernetes-kluster som innehåller tusentals tjänsteinstanser (och deras antal fortsätter att växa snabbt). I sin nuvarande implementering förbrukar Istio ~300 Mb RAM per tjänsteinstans. På grund av det stora antalet möjligheter påverkar transparent balansering också den totala svarstiden för tjänster (upp till 10 ms).

Som ett resultat av detta tittade vi på exakt vilka möjligheter vi behövde just nu och kom fram till att den främsta anledningen till att vi började implementera sådana lösningar var möjligheten att samla in spårningsinformation från hela systemet på ett transparent sätt. Vi ville också ha kontroll över interaktionen av tjänster och göra olika manipulationer med headers som överförs mellan tjänster.

Som ett resultat kom vi till vårt beslut:  Netramesh.

Netramesh

Netramesh är en lättviktslösning för servicenät med möjlighet att skala i det oändliga, oavsett antalet tjänster i systemet.

Huvudmålen med den nya lösningen var låg resurskostnad och hög prestanda. Bland huvudfunktionerna ville vi omedelbart kunna skicka spårningsspann till vårt Jaeger-system på ett transparent sätt.

Idag är de flesta molnlösningar implementerade i Golang. Och det finns förstås skäl till detta. Att skriva nätverksapplikationer i Golang som fungerar asynkront med I/O och skalas över kärnor efter behov är bekvämt och ganska enkelt. Och vad som också är mycket viktigt, prestandan är tillräcklig för att lösa detta problem. Därför valde vi också Golang.

Производительность

Vi har fokuserat våra ansträngningar på att uppnå maximal produktivitet. För en lösning som distribueras bredvid varje instans av tjänsten krävs en liten förbrukning av RAM och CPU-tid. Och naturligtvis bör svarsfördröjningen också vara liten.

Låt oss se vilka resultat vi fick.

RAM

Netramesh förbrukar ~10Mb utan trafik och 50Mb maximalt med en belastning på upp till 10000 XNUMX RPS per instans.

Istio envoy proxy förbrukar alltid ~300 Mb i våra kluster med tusentals instanser. Detta tillåter inte att den skalas till hela klustret.

Netramesh - lättviktslösning för servicenät

Netramesh - lättviktslösning för servicenät

Med Netramesh fick vi en ~10x minskning av minnesförbrukningen.

CPU

CPU-användningen är relativt lika under belastning. Det beror på antalet förfrågningar per tidsenhet till sidvagnen. Värden vid 3000 förfrågningar per sekund vid topp:

Netramesh - lättviktslösning för servicenät

Netramesh - lättviktslösning för servicenät

Det finns ytterligare en viktig punkt: Netramesh - en lösning utan kontrollplan och utan belastning förbrukar inte CPU-tid. Med Istio uppdaterar sidvagnar alltid tjänstens slutpunkter. Som ett resultat kan vi se den här bilden utan belastning:

Netramesh - lättviktslösning för servicenät

Vi använder HTTP/1 för kommunikation mellan tjänster. Ökningen av svarstid för Istio vid proxysändning via envoy var upp till 5-10ms, vilket är ganska mycket för tjänster som är redo att svara på en millisekund. Med Netramesh har denna tid minskat till 0.5-2ms.

Skalbarhet

Den lilla mängd resurser som förbrukas av varje proxy gör det möjligt att placera den bredvid varje tjänst. Netramesh skapades avsiktligt utan en kontrollplanskomponent för att helt enkelt hålla varje sidovagn lätt. Ofta i servicenätlösningar distribuerar kontrollplanet serviceupptäcktsinformation till varje sidovagn. Tillsammans kommer information om timeouts och balanseringsinställningar. Allt detta låter dig göra många användbara saker, men tyvärr sväller det sidvagnar i storlek.

Service upptäckt

Netramesh - lättviktslösning för servicenät

Netramesh lägger inte till några ytterligare mekanismer för att upptäcka tjänster. All trafik proxias transparent genom netra sidovagn.

Netramesh stöder HTTP/1-applikationsprotokoll. För att definiera det används en konfigurerbar lista över portar. Vanligtvis har systemet flera portar genom vilka HTTP-kommunikation sker. Till exempel använder vi 80, 8890, 8080 för interaktion mellan tjänster och externa förfrågningar. I det här fallet kan de ställas in med en miljövariabel NETRA_HTTP_PORTS.

Om du använder Kubernetes som en orkestrator och dess tjänsteenhetsmekanism för intra-klusterkommunikation mellan tjänster, förblir mekanismen exakt densamma. Först erhåller mikrotjänsten en tjänst IP-adress med hjälp av kube-dns och öppnar en ny anslutning till den. Denna anslutning upprättas först med den lokala netra-sidecaren och alla TCP-paket anländer initialt till netra. Därefter upprättar netra-sidecar en förbindelse med den ursprungliga destinationen. NAT på pod IP på noden förblir exakt densamma som utan netra.

Distribuerad spårning och kontextvidarebefordran

Netramesh tillhandahåller den funktionalitet som behövs för att skicka spårningsspann om HTTP-interaktioner. Netra-sidecar analyserar HTTP-protokollet, mäter begärandefördröjningar och extraherar nödvändig information från HTTP-huvuden. I slutändan får vi alla spår i ett enda Jaeger-system. För finkornig konfiguration kan du också använda de miljövariabler som tillhandahålls av det officiella biblioteket jaeger go bibliotek.

Netramesh - lättviktslösning för servicenät

Netramesh - lättviktslösning för servicenät

Men det är ett problem. Tills tjänster genererar och skickar en speciell uber-header kommer vi inte att se anslutna spårningsspann i systemet. Och det här är vad vi behöver för att snabbt hitta orsaken till problemen. Även här har Netramesh en lösning. Proxyer läser HTTP-rubriker och, om de inte innehåller spårnings-id:t för uber, genererar du ett. Netramesh lagrar också information om inkommande och utgående förfrågningar i en sidovagn och matchar dem genom att berika dem med de nödvändiga utgående förfrågningarnas rubriker. Allt du behöver göra i tjänsterna är att bara skicka en rubrik X-Request-Id, som kan konfigureras med en miljövariabel NETRA_HTTP_REQUEST_ID_HEADER_NAME. För att styra storleken på sammanhanget i Netramesh kan du ställa in följande miljövariabler: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS (den tid under vilken sammanhanget kommer att lagras) och NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL (frekvens av kontextrensning).

Det är också möjligt att kombinera flera sökvägar på ditt system genom att markera dem med en speciell sessionstoken. Netra låter dig installera HTTP_HEADER_TAG_MAP för att omvandla HTTP-rubriker till motsvarande spårningsspan-taggar. Detta kan vara särskilt användbart för testning. Efter att ha klarat funktionstestet kan du se vilken del av systemet som påverkades av filtrering med motsvarande sessionsnyckel.

Fastställande av förfrågningskällan

För att avgöra var begäran kom ifrån kan du använda funktionen att automatiskt lägga till en rubrik med källan. Använder en miljövariabel NETRA_HTTP_X_SOURCE_HEADER_NAME Du kan ange ett rubriknamn som kommer att installeras automatiskt. Genom att använda NETRA_HTTP_X_SOURCE_VALUE du kan ställa in värdet som X-Source-huvudet kommer att ställas in på för alla utgående förfrågningar.

Detta gör att distributionen av denna användbara rubrik kan distribueras enhetligt över hela nätverket. Sedan kan du använda det i tjänster och lägga till det i loggar och mätvärden.

Trafikdirigering och Netramesh interns

Netramesh består av två huvudkomponenter. Den första, netra-init, sätter nätverksregler för att fånga upp trafik. Han använder iptables omdirigeringsregler att avlyssna hela eller delar av trafiken på sidovagnen, vilket är den andra huvudkomponenten i Netramesh. Du kan konfigurera vilka portar som måste fångas upp för inkommande och utgående TCP-sessioner: INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS.

Verktyget har också en intressant funktion - probabilistisk routing. Om du använder Netramesh enbart för att samla in spårningsintervall, kan du i en produktionsmiljö spara resurser och möjliggöra probabilistisk routing med hjälp av variabler NETRA_INBOUND_PROBABILITY и NETRA_OUTBOUND_PROBABILITY (från 0 till 1). Standardvärdet är 1 (all trafik avlyssnas).

Efter lyckad avlyssning accepterar netra sidovagn den nya anslutningen och använder SO_ORIGINAL_DST socket alternativ för att få den ursprungliga destinationen. Netra öppnar sedan en ny anslutning till den ursprungliga IP-adressen och upprättar tvåvägs TCP-kommunikation mellan parterna och lyssnar på all trafik som passerar igenom. Om porten är definierad som HTTP, försöker Netra analysera och spåra den. Om HTTP-analys misslyckas, faller Netra tillbaka till TCP och proxar transparent byte.

Bygga en beroendegraf

Efter att ha fått en stor mängd spårningsinformation i Jaeger vill jag få en komplett graf över interaktioner i systemet. Men om ditt system är ganska laddat och miljarder spårningsintervall ackumuleras per dag, blir det inte så lätt att aggregera dem. Det finns ett officiellt sätt att göra detta: gnistberoende. Det kommer dock att ta timmar att bygga en komplett graf och kommer att tvinga dig att ladda ner hela datasetet från Jaeger för de senaste XNUMX timmarna.

Om du använder Elasticsearch för att lagra spårningsintervall kan du använda ett enkelt Golang-verktyg, som kommer att bygga samma graf på några minuter med hjälp av Elasticsearchs funktioner och möjligheter.

Netramesh - lättviktslösning för servicenät

Hur man använder Netramesh

Netra kan enkelt läggas till i vilken tjänst som helst som kör vilken orkestrator som helst. Du kan se ett exempel här.

Just nu har Netra inte möjlighet att automatiskt implementera sidovagnar till tjänster, men det finns planer på implementering.

Framtiden för Netramesh

huvudmål Netramesh är att uppnå minimala resurskostnader och hög prestanda, vilket ger grundläggande möjligheter för observerbarhet och kontroll av kommunikation mellan tjänster.

I framtiden kommer Netramesh att stödja andra applikationslagerprotokoll förutom HTTP. L7-routing kommer att finnas tillgänglig inom en snar framtid.

Använd Netramesh om du stöter på liknande problem och skriv till oss med frågor och förslag.

Källa: will.com

Lägg en kommentar