Netramesh - lichtgewicht service mesh-oplossing

Terwijl we van een monolithische applicatie naar een microservices-architectuur evolueren, worden we geconfronteerd met nieuwe uitdagingen.

In een monolithische toepassing is het meestal vrij eenvoudig om te bepalen in welk deel van het systeem de fout is opgetreden. Hoogstwaarschijnlijk zit het probleem in de code van de monoliet zelf, of in de database. Maar als we op zoek gaan naar een probleem in een microservice-architectuur, is alles niet meer zo vanzelfsprekend. We moeten het volledige pad vinden dat het verzoek van begin tot eind heeft afgelegd en dit uit honderden microservices selecteren. Bovendien hebben velen van hen ook hun eigen opslagfaciliteiten, wat ook logische fouten kan veroorzaken, evenals problemen met de prestaties en fouttolerantie.

Netramesh - lichtgewicht service mesh-oplossing

Ik ben al lang op zoek naar een hulpmiddel dat zou kunnen helpen bij het omgaan met dergelijke problemen (ik schreef hierover op Habré: 1, 2), maar uiteindelijk heb ik mijn eigen open source-oplossing gemaakt. In dit artikel bespreek ik de voordelen van de service mesh-aanpak en deel ik een nieuwe tool voor de implementatie ervan.

Gedistribueerde tracering is een veel voorkomende oplossing voor het probleem van het vinden van fouten in gedistribueerde systemen. Maar wat als deze aanpak voor het verzamelen van informatie over netwerkinteracties nog niet in het systeem is geïmplementeerd, of, erger nog, in een deel van het systeem al goed werkt, maar voor een deel niet, omdat het niet aan oude diensten is toegevoegd? ? Om de exacte oorzaak van een probleem te bepalen, is het noodzakelijk om een ​​volledig beeld te hebben van wat er in het systeem gebeurt. Het is vooral belangrijk om te begrijpen welke microservices betrokken zijn bij belangrijke bedrijfskritische trajecten.

Hier kan de service mesh-benadering ons te hulp komen, die alle machines voor het verzamelen van netwerkinformatie op een lager niveau zal behandelen dan de diensten zelf. Met deze aanpak kunnen we al het verkeer onderscheppen en direct analyseren. Bovendien hoeven applicaties er niet eens iets van te weten.

Service mesh-benadering

Het belangrijkste idee van de service mesh-benadering is om nog een infrastructuurlaag over het netwerk toe te voegen, waardoor we alles kunnen doen met interactie tussen diensten. De meeste implementaties werken als volgt: aan elke microservice wordt een extra zijspancontainer met een transparante proxy toegevoegd, waar al het inkomende en uitgaande verkeer van de service doorheen gaat. En dit is precies de plek waar we klantbalancering kunnen uitvoeren, beveiligingsbeleid kunnen toepassen, beperkingen kunnen opleggen aan het aantal verzoeken en belangrijke informatie kunnen verzamelen over de interactie van services in de productie.

Netramesh - lichtgewicht service mesh-oplossing

Ð ÐμÑÐμниÑ

Er zijn al verschillende implementaties van deze aanpak: Istio и linkerd2. Ze bieden veel functies out-of-the-box. Maar tegelijkertijd gaat er een grote overhead aan middelen gepaard. Bovendien geldt dat hoe groter het cluster is waarin een dergelijk systeem opereert, hoe meer middelen er nodig zullen zijn om de nieuwe infrastructuur in stand te houden. Bij Avito exploiteren we kubernetes-clusters die duizenden service-instances bevatten (en hun aantal blijft snel groeien). In de huidige implementatie verbruikt Istio ~300 MB RAM per service-instantie. Door het grote aantal mogelijkheden heeft transparante balancering ook invloed op de totale responstijd van diensten (tot 10 ms).

Als gevolg hiervan hebben we gekeken naar welke mogelijkheden we nu precies nodig hadden, en besloten dat de belangrijkste reden waarom we dergelijke oplossingen begonnen te implementeren de mogelijkheid was om op transparante wijze traceringsinformatie uit het hele systeem te verzamelen. We wilden ook controle hebben over de interactie van services en verschillende manipulaties uitvoeren met de headers die tussen services worden overgedragen.

Naar aanleiding hiervan zijn wij tot ons besluit gekomen:  Netramesh.

Netramesh

Netramesh is een lichtgewicht service mesh-oplossing met de mogelijkheid om oneindig te schalen, ongeacht het aantal services in het systeem.

De belangrijkste doelstellingen van de nieuwe oplossing waren een lage overhead aan resources en hoge prestaties. Een van de belangrijkste kenmerken was dat we meteen op transparante wijze traceringsbereiken naar ons Jaeger-systeem wilden kunnen sturen.

Tegenwoordig worden de meeste cloudoplossingen geïmplementeerd in Golang. En daar zijn uiteraard redenen voor. Het schrijven van netwerkapplicaties in Golang die asynchroon met I/O werken en indien nodig over cores schalen is handig en vrij eenvoudig. En wat ook heel belangrijk is, de prestaties zijn voldoende om dit probleem op te lossen. Daarom hebben wij ook voor Golang gekozen.

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

Wij hebben onze inspanningen gericht op het bereiken van maximale productiviteit. Voor een oplossing die naast elk exemplaar van de service wordt geïmplementeerd, is een klein verbruik van RAM- en CPU-tijd vereist. En natuurlijk moet de reactievertraging ook klein zijn.

Laten we eens kijken welke resultaten we hebben behaald.

RAM

Netramesh verbruikt ~10Mb zonder verkeer en maximaal 50Mb met een belasting van maximaal 10000 RPS per exemplaar.

Istio Envoy-proxy verbruikt altijd ~300 MB in onze clusters met duizenden exemplaren. Hierdoor kan het niet worden geschaald naar het hele cluster.

Netramesh - lichtgewicht service mesh-oplossing

Netramesh - lichtgewicht service mesh-oplossing

Met Netramesh hebben we een ~10x vermindering van het geheugenverbruik bereikt.

CPU

Het CPU-gebruik is onder belasting relatief gelijk. Het hangt af van het aantal verzoeken per tijdseenheid aan het zijspan. Waarden bij 3000 verzoeken per seconde op piek:

Netramesh - lichtgewicht service mesh-oplossing

Netramesh - lichtgewicht service mesh-oplossing

Er is nog een belangrijk punt: Netramesh - een oplossing zonder besturingsvlak en zonder belasting verbruikt geen CPU-tijd. Met Istio werken zijspannen altijd de service-eindpunten bij. Als gevolg hiervan kunnen we deze foto zonder belasting zien:

Netramesh - lichtgewicht service mesh-oplossing

We gebruiken HTTP/1 voor de communicatie tussen services. De toename van de responstijd voor Istio bij proxying via Envoy bedroeg 5-10 ms, wat behoorlijk veel is voor services die klaar zijn om binnen een milliseconde te reageren. Met Netramesh is deze tijd afgenomen tot 0.5-2 ms.

Schaalbaarheid

De kleine hoeveelheid bronnen die elke proxy verbruikt, maakt het mogelijk om deze naast elke service te plaatsen. Netramesh is met opzet gemaakt zonder een besturingsvlakcomponent om elke zijspan eenvoudigweg lichtgewicht te houden. Bij service mesh-oplossingen distribueert het besturingsvlak vaak service-ontdekkingsinformatie naar elke zijspan. Daarnaast komt er informatie over time-outs en balanceringsinstellingen. Met dit alles kun je veel nuttige dingen doen, maar helaas worden de zijspannen groter.

Service ontdekken

Netramesh - lichtgewicht service mesh-oplossing

Netramesh voegt geen extra mechanismen toe voor servicedetectie. Al het verkeer wordt transparant via Netra Sidecar verzonden.

Netramesh ondersteunt het HTTP/1-applicatieprotocol. Om dit te definiëren wordt een configureerbare lijst met poorten gebruikt. Normaal gesproken heeft het systeem verschillende poorten waarlangs HTTP-communicatie plaatsvindt. Voor interactie tussen services en externe verzoeken gebruiken we bijvoorbeeld 80, 8890, 8080. In dit geval kunnen ze worden ingesteld met behulp van een omgevingsvariabele NETRA_HTTP_PORTS.

Als u Kubernetes als orkestrator en het Service-entiteitsmechanisme voor intra-clustercommunicatie tussen services gebruikt, blijft het mechanisme precies hetzelfde. Eerst verkrijgt de microservice een service-IP-adres met behulp van kube-dns en opent er een nieuwe verbinding mee. Deze verbinding wordt eerst tot stand gebracht met de lokale netra-zijspan en alle TCP-pakketten komen aanvankelijk bij netra aan. Vervolgens brengt netra-zijspan een verbinding tot stand met de oorspronkelijke bestemming. NAT op pod IP op het knooppunt blijft precies hetzelfde als zonder netra.

Gedistribueerde tracering en doorsturen van context

Netramesh biedt de functionaliteit die nodig is om traceringsreeksen over HTTP-interacties te verzenden. Netra-sidecar parseert het HTTP-protocol, meet vertragingen bij verzoeken en haalt de benodigde informatie uit HTTP-headers. Uiteindelijk krijgen we alle sporen in één Jaeger-systeem. Voor een fijnmazige configuratie kunt u ook de omgevingsvariabelen gebruiken die door de officiële bibliotheek worden geleverd Jaeger Go-bibliotheek.

Netramesh - lichtgewicht service mesh-oplossing

Netramesh - lichtgewicht service mesh-oplossing

Maar er is een probleem. Totdat services een speciale uber-header genereren en verzenden, zullen we geen verbonden traceringsreeksen in het systeem zien. En dit is wat we nodig hebben om snel de oorzaak van problemen te vinden. Ook hier heeft Netramesh een oplossing. Proxy's lezen HTTP-headers en genereren er een als ze niet de uber trace-ID bevatten. Netramesh slaat ook informatie over inkomende en uitgaande verzoeken op in een zijspan en matcht deze door deze te verrijken met de benodigde uitgaande verzoekheaders. Het enige dat u in de services hoeft te doen, is slechts één header verzenden X-Request-Id, die kan worden geconfigureerd met behulp van een omgevingsvariabele NETRA_HTTP_REQUEST_ID_HEADER_NAME. Om de grootte van de context in Netramesh te bepalen, kunt u de volgende omgevingsvariabelen instellen: NETRA_TRACING_CONTEXT_EXPIRATION_MILLISECONDS (de tijd waarvoor de context wordt opgeslagen) en NETRA_TRACING_CONTEXT_CLEANUP_INTERVAL (frequentie van het opschonen van de context).

Het is ook mogelijk om meerdere paden op uw systeem te combineren door ze te markeren met een speciaal sessietoken. Met Netra kunt u installeren HTTP_HEADER_TAG_MAP om HTTP-headers om te zetten in overeenkomstige traceringstags. Dit kan vooral handig zijn bij het testen. Nadat u de functionele test heeft doorstaan, kunt u zien welk deel van het systeem werd beïnvloed door te filteren op de bijbehorende sessiesleutel.

De aanvraagbron bepalen

Om te bepalen waar het verzoek vandaan komt, kunt u de functionaliteit gebruiken om automatisch een header bij de bron toe te voegen. Een omgevingsvariabele gebruiken NETRA_HTTP_X_SOURCE_HEADER_NAME U kunt een headernaam opgeven die automatisch wordt geïnstalleerd. Door het gebruiken van NETRA_HTTP_X_SOURCE_VALUE u kunt de waarde instellen waarop de X-Source-header wordt ingesteld voor alle uitgaande verzoeken.

Hierdoor kan de distributie van deze nuttige header uniform over het netwerk worden verdeeld. Vervolgens kunt u het gebruiken in services en toevoegen aan logboeken en statistieken.

Verkeersroutering en Netramesh-internals

Netramesh bestaat uit twee hoofdcomponenten. De eerste, netra-init, stelt netwerkregels in om verkeer te onderscheppen. Hij gebruikt iptables-omleidingsregels om het verkeer op zijspan, het tweede hoofdbestanddeel van Netramesh, geheel of gedeeltelijk te onderscheppen. U kunt configureren welke poorten moeten worden onderschept voor inkomende en uitgaande TCP-sessies: INBOUND_INTERCEPT_PORTS, OUTBOUND_INTERCEPT_PORTS.

De tool heeft ook een interessante functie: probabilistische routering. Als u Netramesh uitsluitend gebruikt voor het verzamelen van traceringsbereiken, kunt u in een productieomgeving bronnen besparen en probabilistische routering inschakelen met behulp van variabelen NETRA_INBOUND_PROBABILITY и NETRA_OUTBOUND_PROBABILITY (van 0 naar 1). De standaardwaarde is 1 (al het verkeer wordt onderschept).

Na succesvolle onderschepping accepteert Netra Sidecar de nieuwe verbinding en het nieuwe gebruik SO_ORIGINAL_DST socket-optie om de oorspronkelijke bestemming te krijgen. Netra opent vervolgens een nieuwe verbinding met het oorspronkelijke IP-adres en brengt tweerichtings-TCP-communicatie tussen de partijen tot stand, waarbij wordt geluisterd naar al het passerende verkeer. Als de poort is gedefinieerd als HTTP, probeert Netra deze te parseren en te traceren. Als het parseren van HTTP mislukt, valt Netra terug op TCP en proxy's op transparante wijze de bytes.

Een afhankelijkheidsgrafiek maken

Nadat ik een grote hoeveelheid traceringsinformatie in Jaeger heb ontvangen, wil ik een volledige grafiek krijgen van de interacties in het systeem. Maar als uw systeem behoorlijk belast is en zich miljarden traceringsreeksen per dag verzamelen, wordt het verzamelen ervan niet zo'n gemakkelijke taak. Er is een officiële manier om dit te doen: vonk-afhankelijkheden. Het duurt echter uren om een ​​volledige grafiek te maken en u zult de volledige dataset van de afgelopen XNUMX uur van Jaeger moeten downloaden.

Als u Elasticsearch gebruikt om traceerreeksen op te slaan, kunt u gebruiken een eenvoudig Golang-hulpprogramma, waarmee binnen enkele minuten dezelfde grafiek wordt opgebouwd met behulp van de functies en mogelijkheden van Elasticsearch.

Netramesh - lichtgewicht service mesh-oplossing

Hoe Netramesh te gebruiken

Netra kan eenvoudig worden toegevoegd aan elke service waarop elke Orchestrator wordt uitgevoerd. Je kunt een voorbeeld zien hier.

Op dit moment heeft Netra niet de mogelijkheid om zijspannen automatisch te implementeren bij services, maar er zijn plannen voor implementatie.

De toekomst van Netramesh

hoofd doel Netramesh is het bereiken van minimale resourcekosten en hoge prestaties, waarbij basismogelijkheden worden geboden voor waarneembaarheid en controle van communicatie tussen diensten.

In de toekomst zal Netramesh naast HTTP ook andere applicatielaagprotocollen ondersteunen. L7-routering zal in de nabije toekomst beschikbaar zijn.

Gebruik Netramesh als u soortgelijke problemen tegenkomt en schrijf ons met vragen en suggesties.

Bron: www.habr.com

Voeg een reactie