Wat weten we over microservices

Hallo! Mijn naam is Vadim Madison, ik leid de ontwikkeling van het Avito System Platform. Er is meer dan eens gezegd hoe we binnen het bedrijf overgaan van een monolithische architectuur naar een microservices-architectuur. Het is tijd om te delen hoe we onze infrastructuur hebben getransformeerd om het maximale uit microservices te halen en te voorkomen dat we erin verdwalen. Hoe PaaS ons hierbij helpt, hoe we de implementatie hebben vereenvoudigd en het maken van een microservice tot één klik hebben teruggebracht - lees verder. Niet alles waarover ik hieronder schrijf, is volledig geïmplementeerd in Avito, een deel ervan is de manier waarop we ons platform ontwikkelen.

(En aan het einde van dit artikel zal ik het hebben over de mogelijkheid om een ​​driedaags seminar bij te wonen van microservice-architectuurexpert Chris Richardson).

Wat weten we over microservices

Hoe we tot microservices kwamen

Avito is een van de grootste geclassificeerde sites ter wereld; er worden dagelijks meer dan 15 miljoen nieuwe advertenties op gepubliceerd. Onze backend accepteert meer dan 20 verzoeken per seconde. Momenteel beschikken we over enkele honderden microservices.

Wij bouwen al enkele jaren aan een microservice-architectuur. Hoe precies - onze collega's in detail vertelde op onze sectie op RIT++ 2017. Op CodeFest 2017 (zie. video), legden Sergey Orlov en Mikhail Prokopchuk gedetailleerd uit waarom we de transitie naar microservices nodig hadden en welke rol Kubernetes hierin speelde. Welnu, nu doen we er alles aan om de schaalkosten die inherent zijn aan een dergelijke architectuur te minimaliseren.

Aanvankelijk creëerden we geen ecosysteem dat ons volledig zou helpen bij het ontwikkelen en lanceren van microservices. Ze verzamelden eenvoudigweg verstandige open source-oplossingen, lanceerden deze thuis en nodigden de ontwikkelaar uit om ermee aan de slag te gaan. Als gevolg hiervan ging hij naar een tiental plaatsen (dashboards, interne diensten), waarna hij sterker werd in zijn verlangen om de code op de oude manier te knippen, in een monoliet. De groene kleur in de onderstaande diagrammen geeft aan wat de ontwikkelaar op de een of andere manier met zijn eigen handen doet, en de gele kleur duidt op automatisering.

Wat weten we over microservices

In het PaaS CLI-hulpprogramma wordt nu met één opdracht een nieuwe service gemaakt en wordt een nieuwe database met nog eens twee toegevoegd en in Stage geïmplementeerd.

Wat weten we over microservices

Hoe het tijdperk van ‘microservice-fragmentatie’ te overwinnen

Met een monolithische architectuur werden ontwikkelaars, omwille van de consistentie van veranderingen in het product, gedwongen uit te zoeken wat er met hun buren aan de hand was. Bij het werken aan de nieuwe architectuur zijn servicecontexten niet langer van elkaar afhankelijk.

Om een ​​microservice-architectuur effectief te laten zijn, moeten er bovendien veel processen worden opgezet, namelijk:

• loggen;
• verzoek tot tracering (Jaeger);
• foutaggregatie (Sentry);
• statussen, berichten, gebeurtenissen van Kubernetes (Event Stream Processing);
• racelimiet / stroomonderbreker (u kunt Hystrix gebruiken);
• controle van de serviceconnectiviteit (we gebruiken Netramesh);
• monitoring (Grafana);
• montage (TeamCity);
• communicatie en notificatie (Slack, e-mail);
• het volgen van taken; (Jira)
• voorbereiding van documentatie.

Om ervoor te zorgen dat het systeem zijn integriteit niet verliest en effectief blijft tijdens het opschalen, hebben we de organisatie van microservices in Avito opnieuw bekeken.

Hoe wij microservices beheren

Het volgende helpt bij het implementeren van een uniform “partijbeleid” onder veel Avito-microservices:

  • infrastructuur in lagen verdelen;
  • Platform as a Service (PaaS)-concept;
  • alles monitoren wat er met microservices gebeurt.

Infrastructuurabstractielagen omvatten drie lagen. Laten we van boven naar beneden gaan.

A. Boven - servicegaas. In eerste instantie hebben we Istio geprobeerd, maar het bleek dat het te veel bronnen gebruikt, wat te duur is voor onze volumes. Daarom ontwikkelde senior ingenieur in het architectuurteam Alexander Lukyanchenko zijn eigen oplossing - Netramesh (beschikbaar in Open Source), die we momenteel in productie gebruiken en die meerdere malen minder bronnen verbruikt dan Istio (maar niet alles doet waar Istio op kan bogen).
B. Middelmatig - Kubernetes. We implementeren en exploiteren er microservices op.
C. Onderkant - blank metaal. Wij gebruiken geen clouds of zaken als OpenStack, maar vertrouwen volledig op bare metal.

Alle lagen worden gecombineerd door PaaS. En dit platform bestaat op zijn beurt uit drie delen.

I. Generatoren, bestuurd via een CLI-hulpprogramma. Zij is het die de ontwikkelaar helpt om op de juiste manier en met minimale inspanning een microservice te creëren.

II. Geconsolideerde verzamelaar met controle over alle tools via een gemeenschappelijk dashboard.

III. Opslag. Maakt verbinding met planners die automatisch triggers instellen voor belangrijke acties. Dankzij zo’n systeem wordt er geen enkele taak gemist omdat iemand vergeten is een taak in Jira in te richten. Hiervoor gebruiken wij een interne tool genaamd Atlas.

Wat weten we over microservices

De implementatie van microservices in Avito wordt ook uitgevoerd volgens één schema, wat de controle erover in elke fase van ontwikkeling en release vereenvoudigt.

Hoe werkt een standaard ontwikkelingspijplijn voor microservices?

Over het algemeen ziet de keten voor het maken van microservices er als volgt uit:

CLI-push → Continue integratie → Bakken → Implementeren → Kunstmatige tests → Canarische tests → Squeeze Testing → Productie → Onderhoud.

Laten we het precies in deze volgorde doornemen.

CLI-push

• Het creëren van een microservice.
We hebben lang moeite gedaan om elke ontwikkelaar te leren hoe hij microservices moest maken. Dit omvatte het schrijven van gedetailleerde instructies in Confluence. Maar de regelingen veranderden en werden aangevuld. Het resultaat is dat er aan het begin van het traject een knelpunt ontstond: het kostte veel meer tijd om microservices te lanceren, en toch ontstonden er vaak problemen tijdens de creatie ervan.

Uiteindelijk hebben we een eenvoudig CLI-hulpprogramma gebouwd dat de basisstappen bij het maken van een microservice automatiseert. In feite vervangt het de eerste git-push. Dit is wat ze precies doet.

— Creëert een dienst volgens een sjabloon — stap voor stap, in de “wizard”-modus. We hebben templates voor de belangrijkste programmeertalen in de Avito backend: PHP, Golang en Python.

- Eén opdracht tegelijk implementeert een omgeving voor lokale ontwikkeling op een specifieke machine. - Minikube wordt gelanceerd, Helm-diagrammen worden automatisch gegenereerd en gelanceerd in lokale kubernetes.

— Verbindt de vereiste database. De ontwikkelaar hoeft het IP-adres, de login en het wachtwoord niet te kennen om toegang te krijgen tot de database die hij nodig heeft - of dit nu lokaal, in Stage of in productie is. Bovendien wordt de database onmiddellijk ingezet in een fouttolerante configuratie en met balancering.

— Het voert zelf live-montage uit. Laten we zeggen dat een ontwikkelaar iets in een microservice heeft gecorrigeerd via zijn IDE. Het hulpprogramma ziet veranderingen in het bestandssysteem en bouwt op basis daarvan de applicatie opnieuw op (voor Golang) en start opnieuw op. Voor PHP sturen we eenvoudigweg de map binnen de kubus door en wordt live-herladen “automatisch” verkregen.

— Genereert autotests. In de vorm van blanco's, maar redelijk geschikt voor gebruik.

• Implementatie van microservices.

Voor ons was het implementeren van een microservice een hele klus. Het volgende was nodig:

I. Dockerbestand.

II. Configuratie
III. Helmdiagram, dat op zichzelf omslachtig is en het volgende omvat:

— de kaarten zelf;
- Sjablonen;
— specifieke waarden rekening houdend met verschillende omgevingen.

We hebben de pijn weggenomen bij het herwerken van Kubernetes-manifesten, zodat ze nu automatisch worden gegenereerd. Maar het allerbelangrijkste: ze hebben de implementatie tot het uiterste vereenvoudigd. Vanaf nu hebben we een Dockerfile en de ontwikkelaar schrijft de volledige configuratie in één kort app.toml-bestand.

Wat weten we over microservices

Ja, en in app.toml zelf is er even niets te doen. We specificeren waar en hoeveel exemplaren van de service moeten worden gegenereerd (op de ontwikkelserver, bij staging, in productie) en geven de afhankelijkheden ervan aan. Let op de lijngrootte = "klein" in het [engine] blok. Dit is de limiet die via Kubernetes aan de dienst wordt toegewezen.

Vervolgens worden op basis van de configuratie automatisch alle benodigde Helm-diagrammen gegenereerd en worden verbindingen met de databases gemaakt.

• Basisvalidatie. Dergelijke controles zijn ook geautomatiseerd.
Moet volgen:
— is er een Dockerfile;
— is er app.toml;
— is er documentatie beschikbaar?
– is de afhankelijkheid in orde?
— of er waarschuwingsregels zijn ingesteld.
Tot het laatste punt: de eigenaar van de dienst bepaalt zelf welke productstatistieken hij moet monitoren.

• Opstellen van documentatie.
Nog steeds een probleemgebied. Het lijkt het meest voor de hand liggend, maar tegelijkertijd is het ook een ‘vaak vergeten’ plaat, en daarmee een kwetsbare schakel in de keten.
Het is noodzakelijk dat er documentatie is voor elke microservice. Het bevat de volgende blokken.

I. Korte beschrijving van de dienst. Letterlijk een paar zinnen over wat het doet en waarom het nodig is.

II. Link naar architectuurdiagram. Het is belangrijk dat het met een snelle blik gemakkelijk te begrijpen is, bijvoorbeeld of u Redis gebruikt voor caching of als de belangrijkste gegevensopslag in de persistente modus. In Avito is dit voorlopig een link naar Confluence.

III. Runboek. Een korte handleiding over het starten van de service en de fijne kneepjes van het gebruik ervan.

NS. FAQ, waarbij het goed zou zijn om te anticiperen op de problemen die uw collega's kunnen tegenkomen bij het werken met de dienst.

V. Beschrijving van eindpunten voor de API. Als u plotseling de bestemmingen niet heeft opgegeven, zullen collega's wiens microservices gerelateerd zijn aan de uwe, vrijwel zeker daarvoor betalen. Nu gebruiken we Swagger en onze oplossing hiervoor kort genoemd.

VI. Etiketten. Of markeringen die laten zien tot welk product, functionaliteit of structurele divisie van het bedrijf de dienst behoort. Ze helpen u bijvoorbeeld snel inzicht te krijgen in de vraag of u functionaliteit bezuinigt die uw collega's een week geleden voor dezelfde bedrijfseenheid hebben uitgerold.

VII. Eigenaar of eigenaren van de service. In de meeste gevallen kunnen deze (of deze) automatisch worden bepaald met behulp van PaaS, maar voor de zekerheid eisen we dat de ontwikkelaar deze handmatig specificeert.

Ten slotte is het een goede gewoonte om documentatie te beoordelen, vergelijkbaar met codebeoordeling.

Continue integratie

  • Voorbereiden van opslagplaatsen.
  • Een pijplijn maken in TeamCity.
  • Rechten instellen.
  • Zoek naar service-eigenaren. Er is hier sprake van een hybride schema: handmatige markering en minimale automatisering van PaaS. Een volautomatisch schema mislukt wanneer diensten ter ondersteuning worden overgedragen aan een ander ontwikkelteam of bijvoorbeeld als de dienstontwikkelaar stopt.
  • Een dienst registreren in Atlas (zie hierboven). Met al zijn eigenaren en afhankelijkheden.
  • Het controleren van migraties. Wij controleren of deze potentieel gevaarlijk zijn. In een ervan verschijnt bijvoorbeeld een alter-tabel of iets anders dat de compatibiliteit van het gegevensschema tussen verschillende versies van de service kan verbreken. Vervolgens wordt de migratie niet uitgevoerd, maar in een abonnement geplaatst – de PaaS moet de service-eigenaar signaleren wanneer het veilig is om deze te gebruiken.

Bakken

De volgende fase is het verpakken van services vóór implementatie.

  • Het bouwen van de applicatie. Volgens de klassiekers - in een Docker-image.
  • Genereren van Helm-grafieken voor de service zelf en gerelateerde bronnen. Inclusief voor databases en cache. Ze worden automatisch gemaakt in overeenstemming met de app.toml-configuratie die is gegenereerd tijdens de CLI-push-fase.
  • Tickets maken voor beheerders om poorten te openen (wanneer nodig).
  • Unittests uitvoeren en codedekking berekenen. Als de codedekking onder de opgegeven drempel ligt, zal de service hoogstwaarschijnlijk niet verder gaan - naar implementatie. Als het op de rand van acceptabel staat, krijgt de service een "pessimiserende" coëfficiënt toegewezen: als er in de loop van de tijd geen verbetering in de indicator optreedt, ontvangt de ontwikkelaar een melding dat er geen vooruitgang is op het gebied van tests ( en daar moet iets aan gedaan worden).
  • Houd rekening met geheugen- en CPU-beperkingen. We schrijven microservices voornamelijk in Golang en draaien deze in Kubernetes. Vandaar een subtiliteit die verband houdt met de eigenaardigheid van de Golang-taal: standaard worden bij het starten alle kernen op de machine gebruikt, als je de GOMAXPROCS-variabele niet expliciet instelt, en wanneer verschillende van dergelijke services op dezelfde machine worden gestart, beginnen ze om te concurreren om hulpbronnen en zich met elkaar te bemoeien. De onderstaande grafieken laten zien hoe de uitvoeringstijd verandert als u de applicatie zonder conflicten en in de race om bronnen-modus uitvoert. (Bronnen van grafieken zijn hier).

Wat weten we over microservices

Uitvoeringstijd, minder is beter. Maximaal: 643 ms, minimaal: 42 ms. De foto is klikbaar.

Wat weten we over microservices

Tijd voor een operatie, minder is beter. Maximaal: 14091 ns, minimaal: 151 ns. De foto is klikbaar.

Tijdens de voorbereidingsfase van de assemblage kunt u deze variabele expliciet instellen of u kunt de bibliotheek gebruiken automaxprocs van de jongens van Uber.

Aanwenden

• Conventies controleren. Voordat u serviceassemblages gaat leveren aan de beoogde omgevingen, moet u het volgende controleren:
- API-eindpunten.
— Naleving van API-eindpuntreacties met het schema.
— Logformaat.
— Headers instellen voor verzoeken aan de service (momenteel wordt dit gedaan door netramesh)
— Het eigenaartoken instellen bij het verzenden van berichten naar de gebeurtenisbus. Dit is nodig om de connectiviteit van diensten op de bus te volgen. Je kunt zowel idempotente data naar de bus sturen, wat de connectiviteit van diensten niet vergroot (wat goed is), als zakelijke data die de connectiviteit van diensten versterkt (wat heel slecht is!). En op het moment dat deze connectiviteit een probleem wordt, helpt het begrijpen van wie de bus schrijft en leest om de diensten goed te scheiden.

Er zijn nog niet veel congressen in Avito, maar hun aanbod breidt zich uit. Hoe meer van dergelijke overeenkomsten beschikbaar zijn in een vorm die het team kan begrijpen en begrijpen, hoe gemakkelijker het is om de consistentie tussen microservices te behouden.

Synthetische testen

• Testen met gesloten lus. Hiervoor gebruiken we nu open source Zweefvlieg.io. Eerst registreert het de werkelijke belasting van de service en emuleert het vervolgens – gewoon in een gesloten lus.

• Stress testen. Wij proberen alle diensten optimaal te laten presteren. En alle versies van elke service moeten worden onderworpen aan belastingtests. Op deze manier kunnen we de huidige prestaties van de service en het verschil met eerdere versies van dezelfde service begrijpen. Als de prestaties na een service-update anderhalf keer zijn gedaald, is dit een duidelijk signaal voor de eigenaren: je moet in de code graven en de situatie corrigeren.
We gebruiken de verzamelde gegevens bijvoorbeeld om automatisch schalen correct te implementeren en uiteindelijk te begrijpen hoe schaalbaar de service is.

Tijdens de loadtests controleren we of het resourceverbruik aan de gestelde limieten voldoet. En we richten ons vooral op de extremen.

a) We kijken naar de totale belasting.
- Te klein - hoogstwaarschijnlijk werkt iets helemaal niet als de belasting meerdere keren plotseling daalt.
- Te groot - optimalisatie vereist.

b) We kijken naar de grenswaarde volgens RPS.
Hier kijken we naar het verschil tussen de huidige versie en de vorige en het totale aantal. Als een dienst bijvoorbeeld 100 rps produceert, dan is deze ofwel slecht geschreven, ofwel is dit de specificiteit ervan, maar dit is in ieder geval een reden om de dienst van heel dichtbij te bekijken.
Als er daarentegen te veel RPS zijn, dan is er misschien een soort bug en zijn sommige eindpunten gestopt met het uitvoeren van de payload, en wordt een andere eenvoudigweg geactiveerd return true;

Kanarie testen

Nadat we de synthetische tests hebben doorstaan, testen we de microservice op een klein aantal gebruikers. We beginnen voorzichtig, met een klein deel van het beoogde publiek van de dienst: minder dan 0,1%. In dit stadium is het erg belangrijk dat de juiste technische en productstatistieken worden meegenomen in de monitoring, zodat ze het probleem zo snel mogelijk in de service zichtbaar maken. De minimale tijd voor een kanarietest is 5 minuten, de hoofdtijd is 2 uur. Bij complexe diensten stellen wij de tijd handmatig in.
Wij analyseren:
— taalspecifieke statistieken, in het bijzonder php-fpm-werknemers;
— fouten in Sentry;
— reactiestatussen;
— responstijd, exact en gemiddeld;
— latentie;
— uitzonderingen, verwerkt en onverwerkt;
— productstatistieken.

Knijp testen

Knijptesten worden ook wel ‘knijptesten’ genoemd. De naam van de techniek werd geïntroduceerd in Netflix. De essentie ervan is dat we eerst één instantie vullen met echt verkeer tot het punt van mislukking en zo de limiet ervan bepalen. Vervolgens voegen we nog een instantie toe en laden dit paar - opnieuw tot het maximum; we zien hun plafond en delta bij de eerste “knijp”. En dus verbinden we één exemplaar tegelijk en berekenen het patroon van veranderingen.
Testgegevens door middel van ‘knijpen’ vloeien ook naar een gemeenschappelijke metrische database, waar we de kunstmatige belastingsresultaten ermee verrijken, of er zelfs ‘synthetische stoffen’ mee vervangen.

Productie

• Schalen. Wanneer we een dienst uitrollen naar productie, houden we in de gaten hoe deze schaalt. Onze ervaring is dat het monitoren van alleen CPU-indicatoren niet effectief is. Automatisch schalen met RPS-benchmarking in zijn pure vorm werkt, maar alleen voor bepaalde diensten, zoals online streaming. Daarom kijken we eerst naar toepassingsspecifieke productstatistieken.

Als gevolg hiervan analyseren we bij het schalen:
- CPU- en RAM-indicatoren,
— het aantal verzoeken in de wachtrij,
- reactietijd,
— voorspelling op basis van verzamelde historische gegevens.

Bij het schalen van een service is het ook belangrijk om de afhankelijkheden ervan te monitoren, zodat we de eerste service in de keten niet schalen en de services waartoe deze toegang krijgt, onder belasting mislukken. Om een ​​acceptabele belasting voor de hele verzameling services vast te stellen, kijken we naar de historische gegevens van de ‘dichtstbijzijnde’ afhankelijke service (gebaseerd op een combinatie van CPU- en RAM-indicatoren, gekoppeld aan app-specifieke statistieken) en vergelijken we deze met de historische gegevens van de initialiserende service, enzovoort gedurende de hele ‘afhankelijkheidsketen’, van boven naar beneden.

service

Nadat de microservice in gebruik is genomen, kunnen we er triggers aan koppelen.

Hier volgen typische situaties waarin triggers optreden.
— Potentieel gevaarlijke migraties gedetecteerd.
— Er zijn beveiligingsupdates uitgebracht.
— De dienst zelf is al lange tijd niet meer bijgewerkt.
— De belasting van de dienst is merkbaar afgenomen of sommige productstatistieken vallen buiten het normale bereik.
— De dienst voldoet niet langer aan de nieuwe platformvereisten.

Sommige triggers zijn verantwoordelijk voor de stabiliteit van de werking, andere - als gevolg van systeemonderhoud - zijn bijvoorbeeld al een hele tijd niet meer ingezet en het basisimage heeft de veiligheidscontroles niet meer doorstaan.

Dashboard

Kortom, het dashboard is het controlepaneel van onze gehele PaaS.

  • Eén enkel informatiepunt over de dienst, met gegevens over de testdekking, het aantal afbeeldingen, het aantal productiekopieën, versies, enz.
  • Een hulpmiddel voor het filteren van gegevens op diensten en labels (markeringen van het behoren tot bedrijfseenheden, productfunctionaliteit, enz.)
  • Een tool voor integratie met infrastructuurtools voor tracering, logboekregistratie en monitoring.
  • Documentatie op één enkel punt.
  • Eén enkel gezichtspunt van alle gebeurtenissen binnen de services.

Wat weten we over microservices
Wat weten we over microservices
Wat weten we over microservices
Wat weten we over microservices

In totaal

Voordat PaaS werd geïntroduceerd, kon een nieuwe ontwikkelaar enkele weken besteden aan het begrijpen van alle tools die nodig zijn om een ​​microservice in productie te brengen: Kubernetes, Helm, onze interne TeamCity-functies, het op fouttolerante wijze opzetten van verbindingen met databases en caches, enz. het duurt een paar uur om de quickstart te lezen en de service zelf te maken.

Voor HighLoad++ 2018 heb ik een rapport over dit onderwerp gegeven, je kunt het bekijken video и presentatie.

Bonustrack voor wie tot het einde leest

Wij van Avito organiseren een interne driedaagse training voor ontwikkelaars van Chris Richardson, een expert in microservice-architectuur. Wij willen graag de kans geven om hieraan deel te nemen aan een van de lezers van dit bericht. Hier Het trainingsprogramma is geplaatst.

De training vindt plaats van 5 tot en met 7 augustus in Moskou. Dit zijn werkdagen die volledig bezet zullen zijn. Lunch en training vinden plaats op ons kantoor en de geselecteerde deelnemer betaalt zelf de reis- en accommodatiekosten.

U kunt zich aanmelden voor deelname in dit Google-formulier. Van u - het antwoord op de vraag waarom u de training moet bijwonen en informatie over hoe u contact met u kunt opnemen. Antwoord in het Engels, omdat Chris zelf de deelnemer kiest die de training gaat volgen.
We zullen de naam van de deelnemer aan de training bekendmaken in een update van dit bericht en op sociale netwerken Avito voor ontwikkelaars (AvitoTech in Facebook, VKontakte, tjilpen) uiterlijk 19 juli.

Bron: www.habr.com

Voeg een reactie