SĂ„, ni samlar in mĂ€tvĂ€rden. Precis som vi. Vi samlar ocksĂ„ in mĂ€tvĂ€rden. SjĂ€lvklart sĂ„dana som Ă€r viktiga för affĂ€ren. Idag kommer vi att berĂ€tta om den första lĂ€nken i vĂ„rt övervakningssystem â en statsd-kompatibel aggregationsserver. , varför vi skrev den och varför vi övergav brubeck.

FrÄn vÄra tidigare artiklar (, ) kan man förstÄ att vi tills för en tid sedan samlade in etiketterna med hjÀlp av . Den Àr skriven i C. Ur kodens synvinkel Àr den enkel som en kork (detta Àr viktigt nÀr du vill bidra) och, viktigast av allt, klarar den utan större problem av vÄra volymer pÄ 2 miljoner mÀtvÀrden per sekund (MPS) i toppen. Dokumentationen pÄstÄr sig stödja 4 miljoner MPS med en asterisk. Det betyder att du kommer att fÄ den angivna siffran om du konfigurerar nÀtverket korrekt pÄ Linux. (Vi vet inte hur mÄnga MPS man fÄr om man lÀmnar nÀtverket som det Àr). Trots dessa fördelar hade vi flera allvarliga klagomÄl pÄ brubeck.
KlagomĂ„l 1. Github â projektets utvecklare â har slutat att stödja den: publicera patchar och fixar, ta emot vĂ„ra och (inte bara vĂ„ra) PR. Under de senaste mĂ„naderna (nĂ„gon gĂ„ng frĂ„n februari-mars 2018) har aktiviteten ökat igen, men före det var det nĂ€stan tvĂ„ Ă„r av total tystnad. Dessutom utvecklas projektet , vilket kan bli ett allvarligt hinder för att införa nya funktioner.
KlagomÄl 2. Noggrannheten i berÀkningarna. Brubeck samlar in endast 65536 vÀrden för aggregation. I vÄrt fall kan det komma mycket fler vÀrden under aggregationsperioden (30 sekunder) för vissa mÀtvÀrden (1 527 392 i toppen). Som ett resultat av sÄdan sampling verkar max- och minvÀrdena vara vÀrdelösa. Till exempel sÄ hÀr:

Som det var

SĂ„ som det borde ha varit
Av samma anledning rÀknas summor överhuvudtaget felaktigt. LÀgg till en bugg med överflöde av 32-bitars flyttal, som helt enkelt fÄr servern att krascha vid mottagande av en till synes oskyldig mÀtning, och det blir verkligen utmÀrkt. Buggen har för övrigt inte blivit ÄtgÀrdad.
Och slutligen, KlagomĂ„l X. Vid tidpunkten för artikelns skrivning Ă€r vi redo att presentationera alla 14 mer eller mindre fungerande implementationer av statsd, som vi kunnat hitta. LĂ„t oss förestĂ€lla oss att en viss avgrĂ€nsad infrastruktur har vuxit sĂ„ mycket att 4 miljoner MPS inte lĂ€ngre Ă€r tillrĂ€ckligt. Eller sĂ„ har den kanske Ă€nnu inte vuxit, men metrik för er Ă€r redan sĂ„ viktiga att Ă€ven korta, 2â3 minuters avbrott i graferna kan bli kritiska och orsaka okontrollerbar Ă„ngest hos cheferna. Eftersom behandling av Ă„ngest Ă€r en tacksam uppgift krĂ€vs tekniska lösningar.
För det första, redundans, sÄ att ett plötsligt problem pÄ servern inte utlöser en psykiatrisk zombieapokalyps pÄ kontoret. För det andra, skalbarhet, för att fÄ möjlighet att hantera mer Àn 4 miljoner MPS, utan att grÀva djupt i Linux nÀtverksstack och kunna vÀxa "brett" till önskad storlek.
Eftersom vi hade marginal för skalbarhet beslutade vi att börja med redundans. "Ă h! Redundans! Det Ă€r enkelt, det kan vi", tĂ€nkte vi och startade 2 servrar, dĂ€r vi sĂ€tter upp en kopia av brubeck pĂ„ varje. För detta behövde vi kopiera trafiken med metrik till bĂ„da servrar och till och med skriva en . Redundansproblemet löste vi sĂ„, men... inte sĂ€rskilt bra. Först verkade allt vara bra: var och en brubeck samlar sin variant av aggregering, skriver data till Graphite var 30:e sekund, skrivandes över det gamla intervallet (detta görs pĂ„ Graphite-sidan). Om en server skulle fallera har vi alltid en andra med en egen kopia av de aggregerade data. Men hĂ€r Ă€r problemet: om en server fallerar uppstĂ„r en "sĂ„g" i graferna. Detta beror pĂ„ att 30-sekundersintervallen vid brubeck inte Ă€r synkroniserade, och i ögonblicket av ett fall registreras inte en av dem. Vid uppstart av den andra servern sker samma sak. Ganska acceptabelt, men vi vill ha bĂ€ttre! Problemet med skalbarhet försvann inte heller. Alla metrik fortsĂ€tter att "flyga" till en enda server, och dĂ€rför Ă€r vi begrĂ€nsade av de samma 2â4 miljoner MPS beroende pĂ„ nĂ€tverkskapaciteten.
Om man tÀnker lite pÄ problemet och samtidigt grÀver snön med en spade, kan en sÄ uppenbar idé dyka upp: vi behöver statsd som kan fungera i distribuerat lÀge. Det vill sÀga, ett som har synkronisering mellan noderna baserat pÄ tid och mÀtdata. "SjÀlvklart finns det sÀkert redan en sÄdan lösning", sa vi och började googla... och hittade ingenting. Efter att ha grÀvt igenom dokumentationen för olika statsd ( den 11.12.2017), hittade vi faktiskt ingenting. Tydligen har varken utvecklarna eller anvÀndarna av dessa lösningar med Sà DANA mÀngder mÀtningar stött pÄ det Ànnu, annars hade de sÀkert kommit pÄ nÄgot.
Och hÀr kom vi ihÄg den "leksaks" statsd - bioyino, som vi skrev pÄ hackathonet just for fun (projektets namn genererade en script inför hackathonet) och insÄg att vi akut behövde vÄr egen statsd. Varför?
- För att det finns för fÄ kloner av statsd i vÀrlden,
- för att man kan sÀkerstÀlla önskad eller nÀrliggande tolerans mot fel och skalbarhet (inklusive synkronisering av aggregerade mÀtvÀrden mellan servrar och lösa problemet med konflikter vid sÀndning),
- för att man kan rÀkna mÀtningar mer exakt Àn vad brubeck gör,
- för att vi kan samla in mer detaljerad statistik, vilket brubeck knappt gav oss,
- för att vi fick chansen att programmera vÄr egen hyperperformance distributed scalable application, som inte kommer att helt Äterge arkitekturen av en annan sÄdan hyper... ni förstÄr.
Vad ska vi skriva pÄ? SjÀlvklart pÄ Rust. Varför?
- för att det redan fanns en prototyp av lösningen,
- för att artikelförfattaren vid den tidpunkten redan kÀnde till Rust och var sugen pÄ att skriva nÄgot för produktion med möjlighet att publicera det som open-source,
- för att sprÄk med GC inte passar oss pÄ grund av den typ av trafik vi fÄr (nÀstan realtime) och GC-pauser Àr nÀstan oacceptabla,
- för att vi behöver maximal prestanda, jÀmförbar med C,
- för att Rust erbjuder oss fearless concurrency, och om vi började skriva detta i C/C++, skulle vi fÄ Ànnu fler sÄrbarheter, buffertöverflöden, race conditions och andra skrÀmmande ord Àn vad brubeck redan har.
Det fanns ocksÄ ett argument mot Rust. Företaget hade ingen erfarenhet av att skapa projekt med Rust, och just nu planerar vi inte att anvÀnda det i huvudprojektet. DÀrför fanns det stora farhÄgor om att inget skulle fungera, men vi beslöt oss för att ta risken och pröva.
Tiden gick...
Till slut, efter flera misslyckade försök, var den första fungerande versionen klar. Vad fick vi? Vi fick nÄgot som detta.

Varje nod fĂ„r sin egen uppsĂ€ttning av metrik och samlar dem hos sig sjĂ€lv, utan att aggregera metriker för de typer dĂ€r full uppsĂ€ttning krĂ€vs för slutlig aggregering. Noderna Ă€r kopplade till varandra genom ett protokoll för distribuerad lĂ„sning (distributed lock), vilket gör det möjligt att vĂ€lja den enda (hĂ€r grĂ„ter vi), som Ă€r vĂ€rdig att skicka metrik till den Stora. Just nu löses detta problem med hjĂ€lp av , men i framtiden strĂ€cker författarens ambitioner sig till Raft, dĂ€r den vĂ€rdiga Ă€r sjĂ€lvklart konsensusnodens ledare. Förutom konsensus skickar noder ofta (standard en gĂ„ng per sekund) delar av de föraggregerade metrikerna till sina grannar, som de lyckats samla under denna sekund. Resultatet Ă€r att skalbarhet och felresistens bevaras â varje nod hĂ„ller fortfarande en full uppsĂ€ttning metriker, men metrikerna skickas nu som aggregerade, över TCP och med kodning i ett binĂ€rt protokoll, vilket minskar kostnaderna för duplicering jĂ€mfört med UDP avsevĂ€rt. Trots det ganska stora antalet inkommande metriker krĂ€ver insamlingen mycket lite minne och Ă€nnu mindre CPU. För vĂ„ra vĂ€l komprimerade metriker handlar det om endast nĂ„gra tiotal megabyte data. Ytterligare en bonus Ă€r att vi slipper onödiga skrivningar av data i Graphite, som det var fallet med burbeck.
UDP-paket med mĂ€tningar Ă€r fördelade mellan noderna pĂ„ nĂ€tverksutrustningen genom en enkel Round Robin. Naturligtvis analyserar inte nĂ€tverksutrustningen innehĂ„llet i paketen och kan dĂ€rför hantera mycket mer Ă€n 4M paket per sekund, för att inte tala om mĂ€tningarna som den överhuvudtaget inte kĂ€nner till. Om man tar hĂ€nsyn till att mĂ€tningarna inte kommer en och en i varje paket, sĂ„ förutser vi inga prestandaproblem pĂ„ denna punkt. Vid serverkrasch upptĂ€cker nĂ€tverksutrustningen snabbt (inom 1-2 sekunder) detta och tar bort den kraschade servern frĂ„n rotationen. Som ett resultat av detta kan passiva (dvs. som inte Ă€r ledande) noder slĂ„s pĂ„ och av praktiskt taget utan att man mĂ€rker av nedgĂ„ngar pĂ„ graferna. Max, vad vi förlorar â Ă€r en del av mĂ€tningarna som kommit under den senaste sekunden. Plötslig förlust/avstĂ€ngning/byte av ledare kommer fortfarande att visa en liten anomali (30-sekundersintervallet Ă€r fortfarande desynkroniserat), men med kommunikation mellan noderna kan vi minimera dessa problem, till exempel genom att skicka synkroniserande paket.
Lite om den interna strukturen. Applikationen Ă€r naturligtvis flerdimensionell, men trĂ„dararkitekturen skiljer sig frĂ„n den som anvĂ€nds i brubeck. TrĂ„darna i brubeck Ă€r likartade â var och en ansvarar samtidigt för insamling av information och aggregering. I bioyino Ă€r arbetsströmmarna (workers) uppdelade i tvĂ„ grupper: de som ansvarar för nĂ€tverket och de som ansvarar för aggregering. Denna uppdelning gör det möjligt att hantera applikationen mer flexibelt beroende pĂ„ typ av mĂ€tningar: dĂ€r intensiv aggregering krĂ€vs kan vi lĂ€gga till fler aggregatorer, dĂ€r det Ă€r mycket nĂ€tverkstrafik â öka antalet nĂ€tverksströmmar. För nĂ€rvarande arbetar vi pĂ„ vĂ„ra servrar med 8 nĂ€tverks- och 4 aggregerande strömmar.
Den berÀkningsdel (ansvarig för aggregering) Àr ganska trÄkig. De fyllda buffertarna frÄn nÀtverksströmmarna fördelas mellan berÀkningsströmmarna, dÀr de sedan parsar och aggregerar. Vid förfrÄgan returneras mÀtningarna för skickning till andra noder. Allt detta, inklusive överföring av data mellan noderna och arbete med Consul, utförs asynkront, pÄ ett ramverk .
Betydligt fler problem under utvecklingen orsakades av den nĂ€tverksdel som ansvarar för att ta emot mĂ€tvĂ€rden. Huvuduppgiften med att separera nĂ€tverksflöden i egna enheter var att minska den tid som flödet anvĂ€nder inte för att lĂ€sa data frĂ„n socket. Alternativen med asynkront UDP och vanligt recvmsg föll snabbt bort: den första anvĂ€nde för mycket CPU i user-space för hĂ€ndelsehantering, den andra â för mĂ„nga kontextbyten. DĂ€rför anvĂ€nds nu med stora buffertar (och buffrar, mina damer och herrar, Ă€r inte nĂ„got oviktigt!). Stöd för vanligt UDP har lĂ€mnats kvar för ot belastade fall dĂ€r det inte Ă€r nödvĂ€ndigt med recvmmsg. I multimeddelande-lĂ€get lyckas vi uppnĂ„ det viktigaste: majoriteten av tiden klarar nĂ€tverksflödet av att rensa operativsystemets kö â lĂ€ser data frĂ„n socket och flyttar dem till userspace-bufferten, bara sĂ€llan vĂ€xlar till att ge den fulla bufferten till aggregatörer. Kön i socket ansamlas praktiskt taget inte, antalet bortkastade paket ökar knappt.
AnmÀrkning
I standardinstÀllningarna Àr buffertstorleken tillrÀckligt stor. Om du av nÄgon anledning beslutar dig för att testa servern sjÀlv, kanske du stöter pÄ att efter att ha skickat en liten mÀngd mÀtvÀrden, kommer de inte att nÄ Graphite, utan stanna kvar i nÀtverksflödets buffert. För att hantera en liten mÀngd mÀtvÀrden behöver du stÀlla in bufsize och task-queue-size till mindre vÀrden i konfigurationsfilen.
Till sist â lite diagram för de som Ă€lskar diagram.
Statistik över antalet inkommande mÀtvÀrden per server: över 2 miljoner MPS.

StÀngning av en av noderna och omfördelning av inkommande mÀtvÀrden.

Statistik över utgĂ„ende mĂ€tvĂ€rden: endast en nod skickar alltid â raidbossen.

Statistik över varje nods arbete med hÀnsyn till fel i olika moduler i systemet.

Detaljerad information om inkommande mÀtvÀrden (namnen pÄ mÀtvÀrdena Àr dolda).

Vad planerar vi att göra med allt detta vidare? SjĂ€lvklart koda, blâŠ! Projektet var ursprungligen avsett att vara open-source och kommer att förbli sĂ„ under hela sin livstid. De nĂ€rmaste planerna inkluderar att gĂ„ över till vĂ„r egen version av Raft, byta peer-protokoll till ett mer portabelt, lĂ€gga till ytterligare intern statistik, nya typer av mĂ€tvĂ€rden, fixa buggar och andra förbĂ€ttringar.
SjÀlvklart Àr alla som vill hjÀlpa till att utveckla projektet vÀlkomna: skapa PR, Issues, och vi kommer att svara och förbÀttra nÀr vi kan, osv.
Och med det, som man sĂ€ger, thatâs all folks, köp vĂ„ra elefanter!

KĂ€lla: habr.com
