Bioyino - distribuert, skalerbar metrikkaggregator

Så du samler inn beregninger. Som vi er. Vi samler også inn beregninger. Selvfølgelig nødvendig for virksomheten. I dag skal vi snakke om den aller første lenken til overvåkingssystemet vårt - en statsd-kompatibel aggregeringsserver bioyino, hvorfor vi skrev det og hvorfor vi forlot brubeck.

Bioyino - distribuert, skalerbar metrikkaggregator

Fra våre tidligere artikler (1, 2) kan du finne ut at vi inntil en stund har samlet inn merker ved hjelp av Brubeck. Den er skrevet i C. Fra et kodesynspunkt er den så enkel som en plugg (dette er viktig når du ønsker å bidra) og, viktigst av alt, håndterer den volumene våre på 2 millioner metrikk per sekund (MPS) på topp. uten problemer. Dokumentasjonen oppgir støtte for 4 millioner MPS med en stjerne. Dette betyr at du får oppgitt tall hvis du konfigurerer nettverket riktig på Linux. (Vi vet ikke hvor mange MPS du kan få hvis du forlater nettverket som det er). Til tross for disse fordelene hadde vi flere alvorlige klager på brubeck.

Krav 1. Github, utvikleren av prosjektet, sluttet å støtte det: publisere patcher og rettelser, akseptere vår og (ikke bare vår) PR. De siste månedene (et sted fra februar-mars 2018) har aktiviteten kommet i gang igjen, men før det var det nesten 2 år med fullstendig ro. I tillegg er prosjektet under utvikling for interne Gihub-behov, som kan bli et alvorlig hinder for introduksjonen av nye funksjoner.

Krav 2. Nøyaktighet av beregninger. Brubeck samler inn totalt 65536 verdier for aggregering. I vårt tilfelle, for noen beregninger, i løpet av aggregeringsperioden (30 sekunder), kan det komme mye flere verdier (1 527 392 på toppen). Som et resultat av denne prøven virker maksimums- og minimumsverdiene ubrukelige. For eksempel slik:

Bioyino - distribuert, skalerbar metrikkaggregator
Som det var

Bioyino - distribuert, skalerbar metrikkaggregator
Hvordan det burde vært

Av samme grunn er beløp som regel feilberegnet. Legg her til en feil med et 32-bits flytende overløp, som vanligvis sender serveren til en feil når den mottar en tilsynelatende uskyldig metrikk, og alt blir bra. Feilen er forresten ikke fikset.

Og, til slutt, Krav X. I skrivende stund er vi klare til å presentere den for alle 14 mer eller mindre fungerende statistikkimplementeringer som vi var i stand til å finne. La oss forestille oss at en enkelt infrastruktur har vokst så mye at det ikke lenger er nok å akseptere 4 millioner MPS. Eller selv om den ikke har vokst ennå, men beregningene er allerede så viktige for deg at selv korte, 2-3 minutters fall i diagrammene allerede kan bli kritiske og forårsake anfall av uoverkommelig depresjon blant ledere. Siden behandling av depresjon er en utakknemlig oppgave, trengs tekniske løsninger.

For det første, feiltoleranse, slik at et plutselig problem på serveren ikke forårsaker en psykiatrisk zombieapokalypse på kontoret. For det andre, skalering for å kunne akseptere mer enn 4 millioner MPS, uten å grave dypt inn i Linux-nettverksstakken og rolig vokse "i bredden" til ønsket størrelse.

Siden vi hadde plass til skalering, bestemte vi oss for å starte med feiltoleranse. "OM! Feiltoleranse! Det er enkelt, vi kan gjøre det," tenkte vi og lanserte 2 servere, og hentet en kopi av brubeck på hver. For å gjøre dette måtte vi kopiere trafikk med beregninger til begge serverne og til og med skrive for dette lite verktøy. Vi løste feiltoleranseproblemet med dette, men... ikke veldig bra. Til å begynne med virket alt bra: hver brubeck samler sin egen versjon av aggregering, skriver data til Graphite en gang hvert 30. sekund, og overskriver det gamle intervallet (dette gjøres på grafittsiden). Hvis en server plutselig svikter, har vi alltid en annen med sin egen kopi av de aggregerte dataene. Men her er problemet: Hvis serveren svikter, vises en "sag" på grafene. Dette skyldes det faktum at brubecks 30-sekunders intervaller ikke er synkronisert, og i øyeblikket av en krasj blir ikke en av dem overskrevet. Når den andre serveren starter, skjer det samme. Ganske tålelig, men jeg vil ha bedre! Problemet med skalerbarhet har heller ikke forsvunnet. Alle beregninger "flyr" fortsatt til en enkelt server, og derfor er vi begrenset til de samme 2-4 millioner MPS, avhengig av nettverksnivå.

Hvis du tenker litt på problemet og samtidig graver opp snø med en spade, kan følgende åpenbare idé komme til hjernen: du trenger en statsd som kan fungere i distribuert modus. Det vil si en som implementerer synkronisering mellom noder i tid og beregninger. "Selvfølgelig eksisterer sannsynligvis en slik løsning allerede," sa vi og gikk til Google... Og de fant ingenting. Etter å ha gått gjennom dokumentasjonen for forskjellige statistikker (https://github.com/etsy/statsd/wiki#server-implementations per 11.12.2017. desember XNUMX), fant vi absolutt ingenting. Tilsynelatende har verken utviklerne eller brukerne av disse løsningene ennå støtt på SÅ mange beregninger, ellers ville de definitivt funnet på noe.

Og så husket vi "leketøyet" statsd - bioyino, som ble skrevet på Just for Fun hackathon (navnet på prosjektet ble generert av manuset før starten av hackathonet) og innså at vi trengte vår egen statistikk. For hva?

  • fordi det er for få statistikkkloner i verden,
  • fordi det er mulig å gi ønsket eller nær ønsket feiltoleranse og skalerbarhet (inkludert synkronisering av aggregerte beregninger mellom servere og løsning av problemet med å sende konflikter),
  • fordi det er mulig å beregne beregninger mer nøyaktig enn brubeck gjør,
  • fordi du kan samle inn mer detaljert statistikk selv, som brubeck praktisk talt ikke ga oss,
  • fordi jeg hadde en sjanse til å programmere min egen hyperperformance-distribuerte skala-labapplikasjon, som ikke helt vil gjenta arkitekturen til en annen lignende hyperfor ... vel, det er det.

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

  • fordi det allerede fantes en prototypeløsning,
  • fordi forfatteren av artikkelen allerede kjente Rust på den tiden og var ivrig etter å skrive noe i den for produksjon med muligheten til å legge den i åpen kildekode,
  • fordi språk med GC ikke er egnet for oss på grunn av trafikken som mottas (nesten sanntid) og GC-pauser er praktisk talt uakseptable,
  • fordi du trenger maksimal ytelse som kan sammenlignes med C
  • fordi Rust gir oss fryktløs samtidighet, og hvis vi begynte å skrive det i C/C++, ville vi ha raket inn enda flere sårbarheter, bufferoverløp, raseforhold og andre skumle ord enn brubeck.

Det var også et argument mot Rust. Selskapet hadde ingen erfaring med å lage prosjekter i Rust, og nå planlegger vi heller ikke å bruke det i hovedprosjektet. Derfor var det alvorlig frykt for at ingenting skulle ordne seg, men vi bestemte oss for å ta sjansen og prøvde.

Tiden gikk...

Til slutt, etter flere mislykkede forsøk, var den første fungerende versjonen klar. Hva skjedde? Dette er hva som skjedde.

Bioyino - distribuert, skalerbar metrikkaggregator

Hver node mottar sitt eget sett med beregninger og akkumulerer dem, og samler ikke beregninger for de typene der hele settet deres er nødvendig for endelig aggregering. Nodene er koblet til hverandre med en slags distribuert låseprotokoll, som lar deg velge blant dem den eneste (her gråt vi) som er verdig å sende metrikk til den store. Dette problemet blir for øyeblikket løst av Konsul, men i fremtiden strekker forfatterens ambisjoner seg til egen gjennomføring Raft, der den mest verdige vil selvfølgelig være konsensusledernoden. I tillegg til konsensus, sender noder ganske ofte (en gang per sekund som standard) til naboene de delene av forhåndsaggregerte beregninger som de klarte å samle inn i det sekundet. Det viser seg at skalering og feiltoleranse er bevart - hver node har fortsatt et komplett sett med metrikker, men metrikkene sendes allerede aggregert, via TCP og kodet inn i en binær protokoll, så dupliseringskostnadene reduseres betydelig sammenlignet med UDP. Til tross for det ganske store antallet innkommende beregninger, krever akkumulering veldig lite minne og enda mindre CPU. For våre svært komprimerbare mertics er dette bare noen få titalls megabyte med data. Som en ekstra bonus får vi ingen unødvendige dataomskrivinger i Graphite, slik tilfellet var med burbeck.

UDP-pakker med beregninger er ubalanserte mellom noder på nettverksutstyr gjennom en enkel Round Robin. Selvfølgelig analyserer ikke nettverksmaskinvaren innholdet i pakker og kan derfor trekke mye mer enn 4M pakker per sekund, for ikke å nevne beregninger som den ikke vet noe om i det hele tatt. Hvis vi tar i betraktning at beregningene ikke kommer en om gangen i hver pakke, ser vi ingen ytelsesproblemer på dette stedet. Hvis en server krasjer, oppdager nettverksenheten raskt (innen 1-2 sekunder) dette faktum og fjerner den krasjete serveren fra rotasjon. Som et resultat av dette kan passive (dvs. ikke-ledende) noder slås av og på praktisk talt uten å merke nedtrekk på diagrammene. Det maksimale vi taper er en del av beregningene som kom inn i siste sekund. Et plutselig tap/avstengning/bytte av en leder vil fortsatt skape en mindre anomali (30 sekunders intervallet er fortsatt ute av synkronisering), men hvis det er kommunikasjon mellom noder, kan disse problemene minimeres, for eksempel ved å sende ut synkroniseringspakker .

Litt om den indre strukturen. Applikasjonen er selvfølgelig flertrådet, men gjengearkitekturen er forskjellig fra den som brukes i brubeck. Trådene i brubeck er de samme - hver av dem er ansvarlig for både informasjonsinnsamling og aggregering. I bioyino er arbeiderne delt inn i to grupper: de som er ansvarlige for nettverket og de som er ansvarlige for aggregeringen. Denne divisjonen lar deg administrere applikasjonen mer fleksibelt avhengig av typen beregninger: der det kreves intensiv aggregering, kan du legge til aggregatorer, der det er mye nettverkstrafikk, kan du legge til antall nettverksflyter. For øyeblikket jobber vi på våre servere i 8 nettverk og 4 aggregeringsflyter.

Telledelen (ansvarlig for aggregering) er ganske kjedelig. Buffere fylt av nettverksstrømmer fordeles mellom tellende strømmer, hvor de deretter analyseres og aggregeres. På forespørsel gis beregninger for sending til andre noder. Alt dette, inkludert sending av data mellom noder og arbeid med Consul, utføres asynkront og kjører på rammeverket Tokyo.

Mye flere problemer under utviklingen ble forårsaket av nettverksdelen som var ansvarlig for å motta beregninger. Hovedmålet med å skille nettverksstrømmer i separate enheter var ønsket om å redusere tiden en strøm bruker no for å lese data fra stikkontakten. Alternativer som bruker asynkron UDP og vanlig recvmsg forsvant raskt: den første bruker for mye brukerplass CPU for hendelsesbehandling, den andre krever for mange kontekstsvitsjer. Derfor brukes den nå recvmmsg med store buffere (og buffere, herrer offiserer, er ingenting for dere!). Støtte for vanlig UDP er reservert for lette tilfeller der recvmmsg ikke er nødvendig. I multimeldingsmodus er det mulig å oppnå det viktigste: det store flertallet av tiden rakker nettverkstråden OS-køen - leser data fra stikkontakten og overfører dem til brukerromsbufferen, og bytter bare av og til til å gi den fylte bufferen til aggregatorer. Køen i stikkontakten akkumuleres praktisk talt ikke, antallet droppede pakker vokser praktisk talt ikke.

Note

I standardinnstillingene er bufferstørrelsen satt til å være ganske stor. Hvis du plutselig bestemmer deg for å prøve serveren selv, kan du støte på det faktum at etter å ha sendt et lite antall beregninger, vil de ikke komme til Graphite, forbli i nettverksstrømbufferen. For å jobbe med et lite antall beregninger, må du sette bufsize og task-queue-size til mindre verdier i konfigurasjonen.

Til slutt noen diagrammer for kartelskere.

Statistikk over antall innkommende beregninger for hver server: mer enn 2 millioner MPS.

Bioyino - distribuert, skalerbar metrikkaggregator

Deaktivering av en av nodene og redistribuering av innkommende beregninger.

Bioyino - distribuert, skalerbar metrikkaggregator

Statistikk over utgående beregninger: bare én node sender alltid - raid-sjefen.

Bioyino - distribuert, skalerbar metrikkaggregator

Statistikk over driften av hver node, tar hensyn til feil i ulike systemmoduler.

Bioyino - distribuert, skalerbar metrikkaggregator

Detaljering av innkommende beregninger (beregningsnavn er skjult).

Bioyino - distribuert, skalerbar metrikkaggregator

Hva planlegger vi å gjøre med alt dette videre? Selvfølgelig, skriv kode, fy...! Prosjektet var opprinnelig planlagt å være åpen kildekode og vil forbli slik gjennom hele levetiden. Våre umiddelbare planer inkluderer å bytte til vår egen versjon av Raft, endre peer-protokollen til en mer bærbar, introdusere ytterligere intern statistikk, nye typer beregninger, feilrettinger og andre forbedringer.

Selvfølgelig er alle velkommen til å hjelpe til i utviklingen av prosjektet: skape PR, Issues, hvis mulig vil vi svare, forbedre osv.

Når det er sagt, det er alt folkens, kjøp elefantene våre!



Kilde: www.habr.com

Legg til en kommentar