Bioyino - distribueret, skalerbar metric-aggregator

Så du indsamler metrics. Som vi er. Vi indsamler også metrics. Selvfølgelig nødvendigt for erhvervslivet. I dag vil vi tale om det allerførste link i vores overvågningssystem - en statsd-kompatibel aggregeringsserver bioyino, hvorfor vi skrev det, og hvorfor vi forlod brubeck.

Bioyino - distribueret, skalerbar metric-aggregator

Fra vores tidligere artikler (1, 2) kan du finde ud af, at vi indtil et stykke tid indsamlede mærker vha Brubeck. Det er skrevet i C. Fra et kodesynspunkt er det så simpelt som et stik (dette er vigtigt, når du vil bidrage), og vigtigst af alt, det håndterer vores volumener på 2 millioner metrics per second (MPS) på peak uden problemer. Dokumentationen angiver støtte til 4 millioner MPS med en stjerne. Det betyder, at du får det angivne tal, hvis du konfigurerer netværket korrekt på Linux. (Vi ved ikke, hvor mange MPS du kan få, hvis du forlader netværket som det er). På trods af disse fordele havde vi flere alvorlige klager over brubeck.

Påstand 1. Github, udvikleren af ​​projektet, stoppede med at støtte det: udgivelse af patches og rettelser, acceptere vores og (ikke kun vores) PR. I de sidste par måneder (et sted fra februar-marts 2018) er aktiviteten genoptaget, men inden da var der næsten 2 år med fuldstændig ro. Derudover er projektet under udvikling til interne Gihub-behov, hvilket kan blive en alvorlig hindring for introduktionen af ​​nye funktioner.

Påstand 2. Nøjagtighed af beregninger. Brubeck indsamler i alt 65536 værdier til aggregering. I vores tilfælde, for nogle målinger, kan der i aggregeringsperioden (30 sekunder) ankomme meget flere værdier (1 på toppen). Som et resultat af denne prøvetagning ser maksimum- og minimumværdierne ud til at være ubrugelige. For eksempel sådan her:

Bioyino - distribueret, skalerbar metric-aggregator
Som det var

Bioyino - distribueret, skalerbar metric-aggregator
Hvordan det skulle have været

Af samme grund er beløb generelt opgjort forkert. Tilføj her en fejl med et 32-bit float-overløb, som generelt sender serveren til segfault, når den modtager en tilsyneladende uskyldig metrisk, og alt bliver fantastisk. Fejlen er i øvrigt ikke rettet.

Og endelig Påstand X. I skrivende stund er vi klar til at præsentere det for alle 14 mere eller mindre fungerende statistiske implementeringer, som vi var i stand til at finde. Lad os forestille os, at en enkelt infrastruktur er vokset så meget, at det ikke længere er nok at acceptere 4 millioner MPS. Eller selvom det ikke er vokset endnu, men metrics er allerede så vigtige for dig, at selv korte, 2-3 minutters dyk i diagrammerne allerede kan blive kritiske og forårsage anfald af uoverstigelig depression blandt ledere. Da behandling af depression er en utaknemmelig opgave, er der behov for tekniske løsninger.

For det første fejltolerance, så et pludseligt problem på serveren ikke forårsager en psykiatrisk zombieapokalypse på kontoret. For det andet skalering til at kunne acceptere mere end 4 millioner MPS uden at grave dybt ned i Linux-netværksstakken og roligt vokse "i bredden" til den nødvendige størrelse.

Da vi havde plads til skalering, besluttede vi at starte med fejltolerance. "OM! Fejltolerance! Det er simpelt, vi kan gøre det,” tænkte vi og lancerede 2 servere, der rejste en kopi af brubeck på hver. For at gøre dette var vi nødt til at kopiere trafik med målinger til begge servere og endda skrive til dette lille nytte. Vi løste fejltoleranceproblemet med dette, men... ikke særlig godt. Til at begynde med virkede alt fantastisk: hver brubeck indsamler sin egen version af aggregering, skriver data til Graphite en gang hvert 30. sekund og overskriver det gamle interval (dette gøres på grafitsiden). Hvis en server pludselig svigter, har vi altid en anden med sin egen kopi af de samlede data. Men her er problemet: Hvis serveren fejler, vises en "sav" på graferne. Det skyldes, at brubecks 30-sekunders intervaller ikke er synkroniserede, og i et styrtøjeblik overskrives et af dem ikke. Når den anden server starter, sker det samme. Ganske tåleligt, men jeg vil have det bedre! Problemet med skalerbarhed er heller ikke forsvundet. Alle metrics "flyver" stadig til en enkelt server, og derfor er vi begrænset til de samme 2-4 millioner MPS, afhængigt af netværksniveauet.

Hvis du tænker lidt over problemet og samtidig graver sne op med en skovl, kan følgende åbenlyse idé dukke op: du har brug for en statsd, der kan fungere i distribueret tilstand. Det vil sige en, der implementerer synkronisering mellem noder i tid og metrikker. "Selvfølgelig eksisterer en sådan løsning sandsynligvis allerede," sagde vi og gik til Google... Og de fandt intet. Efter at have gennemgået dokumentationen for forskellige statsd (https://github.com/etsy/statsd/wiki#server-implementations pr. 11.12.2017. december XNUMX), fandt vi absolut intet. Tilsyneladende har hverken udviklerne eller brugerne af disse løsninger endnu stødt på SÅ mange målinger, ellers ville de helt sikkert finde på noget.

Og så huskede vi på "legetøjet" statsd - bioyino, som blev skrevet på Just for Fun hackathon (navnet på projektet blev genereret af scriptet før starten af ​​hackathonet) og indså, at vi havde et presserende behov for vores egen statistik. For hvad?

  • fordi der er for få statsd kloner i verden,
  • fordi det er muligt at levere den ønskede eller tæt på den ønskede fejltolerance og skalerbarhed (herunder synkronisering af aggregerede metrics mellem servere og løsning af problemet med afsendelse af konflikter),
  • fordi det er muligt at beregne metrics mere nøjagtigt end Brubeck gør,
  • fordi du selv kan indsamle mere detaljerede statistikker, som brubeck praktisk talt ikke har leveret til os,
  • fordi jeg havde en chance for at programmere min egen hyperperformance distributedscalelabplication, som ikke helt vil gentage arkitekturen fra en anden lignende hyperfor ... ja, det er det.

Hvad skal man skrive på? Selvfølgelig i Rust. Hvorfor?

  • fordi der allerede var en prototypeløsning,
  • fordi forfatteren af ​​artiklen allerede kendte Rust på det tidspunkt og var ivrig efter at skrive noget i den til produktion med mulighed for at sætte den i open source,
  • fordi sprog med GC ikke er egnede for os på grund af arten af ​​den modtagne trafik (næsten realtid), og GC-pauser er praktisk talt uacceptable,
  • fordi du har brug for maksimal ydeevne, der kan sammenlignes med C
  • fordi Rust giver os frygtløs samtidighed, og hvis vi begyndte at skrive det i C/C++, ville vi have indtaget endnu flere sårbarheder, bufferoverløb, raceforhold og andre skræmmende ord end brubeck.

Der var også et argument mod Rust. Virksomheden havde ingen erfaring med at lave projekter i Rust, og nu planlægger vi heller ikke at bruge det i hovedprojektet. Derfor var der alvorlig frygt for, at intet ville fungere, men vi besluttede at tage en chance og prøvede.

Tiden gik...

Endelig, efter flere mislykkede forsøg, var den første fungerende version klar. Hvad skete der? Dette er, hvad der skete.

Bioyino - distribueret, skalerbar metric-aggregator

Hver node modtager sit eget sæt af metrics og akkumulerer dem, og aggregerer ikke metrics for de typer, hvor deres fulde sæt er påkrævet for den endelige aggregering. Noderne er forbundet med hinanden ved hjælp af en slags distribueret låseprotokol, som giver dig mulighed for at vælge blandt dem den eneste (her græd vi), der er værdig til at sende metrics til den Store. Dette problem er i øjeblikket ved at blive løst af Konsul, men i fremtiden strækker forfatterens ambitioner sig til egen implementering Raft, hvor den mest værdige naturligvis vil være konsensuslederknudepunktet. Ud over konsensus sender noder ret ofte (en gang i sekundet som standard) til deres naboer de dele af forudaggregerede metrics, som de formåede at indsamle i det sekund. Det viser sig, at skalering og fejltolerance er bevaret - hver node har stadig et komplet sæt af metrikker, men metrikken sendes allerede aggregeret, via TCP og kodet ind i en binær protokol, så duplikeringsomkostningerne er væsentligt reduceret sammenlignet med UDP. På trods af det ret store antal indgående målinger kræver akkumulering meget lidt hukommelse og endnu mindre CPU. For vores meget komprimerbare mertics er dette kun et par snesevis af megabyte data. Som en ekstra bonus får vi ingen unødvendige dataomskrivninger i Graphite, som det var tilfældet med burbeck.

UDP-pakker med metrics er ubalancerede mellem noder på netværksudstyr gennem en simpel Round Robin. Naturligvis analyserer netværkshardwaren ikke indholdet af pakker og kan derfor trække meget mere end 4M pakker i sekundet, for ikke at nævne metrics, som den overhovedet ikke ved noget om. Hvis vi tager i betragtning, at metrikken ikke kommer en ad gangen i hver pakke, så forudser vi ingen ydeevneproblemer på dette sted. Hvis en server går ned, opdager netværksenheden hurtigt (inden for 1-2 sekunder) dette faktum og fjerner den nedbrudte server fra rotation. Som et resultat af dette kan passive (dvs. ikke-ledende) noder tændes og slukkes praktisk talt uden at bemærke nedtrækninger på diagrammet. Det maksimale, vi mister, er en del af de målinger, der kom ind i sidste sekund. Et pludseligt tab/nedlukning/skift af en leder vil stadig skabe en mindre anomali (intervallet på 30 sekunder er stadig ude af synkronisering), men hvis der er kommunikation mellem noder, kan disse problemer minimeres, for eksempel ved at udsende synkroniseringspakker .

Lidt om den indre struktur. Applikationen er selvfølgelig multithreaded, men gevindarkitekturen er anderledes end den, der bruges i brubeck. Trådene i brubeck er de samme - hver af dem er ansvarlige for både informationsindsamling og aggregering. I bioyino er arbejderne opdelt i to grupper: dem, der er ansvarlige for netværket og dem, der er ansvarlige for aggregering. Denne opdeling giver dig mulighed for mere fleksibelt at administrere applikationen afhængigt af typen af ​​metrikker: hvor intensiv aggregering er påkrævet, kan du tilføje aggregatorer, hvor der er meget netværkstrafik, kan du tilføje antallet af netværksflows. I øjeblikket arbejder vi på vores servere i 8 netværk og 4 aggregeringsflows.

Den tælle (ansvarlig for aggregering) delen er ret kedelig. Buffere fyldt med netværksflows fordeles blandt tælleflows, hvor de efterfølgende parses og aggregeres. Efter anmodning gives der målinger for afsendelse til andre noder. Alt dette, inklusive afsendelse af data mellem noder og arbejde med Consul, udføres asynkront og kører på rammen Tokyo.

Meget flere problemer under udviklingen blev forårsaget af netværksdelen, der var ansvarlig for at modtage metrics. Hovedmålet med at adskille netværksstrømme i separate enheder var ønsket om at reducere den tid, et flow bruger nej at læse data fra stikkontakten. Indstillinger ved hjælp af asynkron UDP og almindelig recvmsg forsvandt hurtigt: den første bruger for meget brugerplads CPU til hændelsesbehandling, den anden kræver for mange kontekstskift. Derfor bruges den nu recvmmsg med store buffere (og buffere, mine herrer officerer, er ikke noget for jer!). Understøttelse af almindelig UDP er forbeholdt lettere tilfælde, hvor recvmmsg ikke er nødvendig. I multimeddelelsestilstand er det muligt at opnå det vigtigste: Langt det meste af tiden rakker netværkstråden OS-køen - læser data fra stikket og overfører dem til brugerrumsbufferen, og skifter kun lejlighedsvis til at give den fyldte buffer til aggregatorer. Køen i stikket akkumuleres praktisk talt ikke, antallet af tabte pakker vokser praktisk talt ikke.

Bemærk

I standardindstillingerne er bufferstørrelsen sat til at være ret stor. Hvis du pludselig beslutter dig for selv at prøve serveren, kan du støde på det faktum, at efter at have sendt et lille antal målinger, vil de ikke ankomme i Graphite, forbliver i netværksstreambufferen. For at arbejde med et lille antal metrics skal du indstille bufsize og task-queue-size til mindre værdier i konfigurationen.

Til sidst nogle diagrammer for diagramelskere.

Statistik over antallet af indgående metrics for hver server: mere end 2 millioner MPS.

Bioyino - distribueret, skalerbar metric-aggregator

Deaktivering af en af ​​noderne og omfordeling af indgående metrics.

Bioyino - distribueret, skalerbar metric-aggregator

Statistik over udgående metrics: kun én node sender altid - raid-chefen.

Bioyino - distribueret, skalerbar metric-aggregator

Statistik over driften af ​​hver knude, under hensyntagen til fejl i forskellige systemmoduler.

Bioyino - distribueret, skalerbar metric-aggregator

Detaljering af indgående metrics (metriknavne er skjulte).

Bioyino - distribueret, skalerbar metric-aggregator

Hvad planlægger vi at gøre med alt dette næste gang? Selvfølgelig, skriv kode, for fanden...! Projektet var oprindeligt planlagt til at være open source og vil forblive det hele dets levetid. Vores umiddelbare planer omfatter skift til vores egen version af Raft, ændring af peer-protokollen til en mere bærbar, introduktion af yderligere interne statistikker, nye typer målinger, fejlrettelser og andre forbedringer.

Alle er naturligvis velkomne til at hjælpe til i udviklingen af ​​projektet: Skab PR, Issues, hvis muligt vil vi reagere, forbedre mv.

Når det er sagt, så er det alt folkens, køb vores elefanter!



Kilde: www.habr.com

Tilføj en kommentar