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
Fra våre tidligere artikler (
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
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:
Som det var
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
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 (
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.
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
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
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å
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.
Deaktivering av en av nodene og redistribuering av innkommende beregninger.
Statistikk over utgående beregninger: bare én node sender alltid - raid-sjefen.
Statistikk over driften av hver node, tar hensyn til feil i ulike systemmoduler.
Detaljering av innkommende beregninger (beregningsnavn er skjult).
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