Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Je verzamelt dus statistieken. Zoals we zijn. We verzamelen ook statistieken. Natuurlijk noodzakelijk voor het bedrijfsleven. Vandaag zullen we het hebben over de allereerste link van ons monitoringsysteem: een statsd-compatibele aggregatieserver bioyino, waarom we het schreven en waarom we Brubeck verlieten.

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Uit onze eerdere artikelen (1, 2) kun je ontdekken dat we tot enige tijd cijfers hebben verzameld met behulp van Brubeck. Het is geschreven in C. Vanuit codeoogpunt is het zo simpel als een plug (dit is belangrijk als je een bijdrage wilt leveren) en, belangrijker nog, het verwerkt onze volumes van 2 miljoen metrische gegevens per seconde (MPS) op piekmomenten. probleemloos. In de documentatie staat ondersteuning voor 4 miljoen MPS met een asterisk. Dit betekent dat u het aangegeven cijfer krijgt als u het netwerk correct configureert onder Linux. (We weten niet hoeveel MPS je kunt krijgen als je het netwerk laat zoals het is). Ondanks deze voordelen hadden we verschillende ernstige klachten over Brubeck.

Bewering 1. Github, de ontwikkelaar van het project, stopte met de ondersteuning ervan: het publiceren van patches en fixes, het accepteren van de onze en (niet alleen de onze) PR. De afgelopen maanden (ergens februari-maart 2018) is de activiteit hervat, maar daarvoor was er bijna 2 jaar volledige rust. Daarnaast wordt het project ontwikkeld voor interne Gihub-behoeften, wat een ernstig obstakel kan worden voor de introductie van nieuwe functies.

Bewering 2. Nauwkeurigheid van berekeningen. Brubeck verzamelt in totaal 65536 waarden voor aggregatie. In ons geval kunnen voor sommige statistieken tijdens de aggregatieperiode (30 seconden) veel meer waarden binnenkomen (1 op de piek). Als gevolg van deze bemonstering lijken de maximale en minimale waarden nutteloos. Bijvoorbeeld zoals dit:

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken
Zoals het was

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken
Hoe het had moeten zijn

Om dezelfde reden worden bedragen doorgaans verkeerd berekend. Voeg hier een bug toe met een 32-bit float-overflow, die de server doorgaans naar een segfault stuurt wanneer hij een ogenschijnlijk onschuldige metriek ontvangt, en alles wordt geweldig. De bug is overigens nog niet opgelost.

En tenslotte Claim X. Op het moment dat we dit schrijven zijn we klaar om het te presenteren aan alle 14 min of meer werkende statistische implementaties die we hebben kunnen vinden. Laten we ons voorstellen dat een enkele infrastructuur zo sterk is gegroeid dat het accepteren van 4 miljoen MPS niet langer voldoende is. Of zelfs als het nog niet is gegroeid, maar de cijfers al zo belangrijk voor je zijn dat zelfs korte dips van 2 tot 3 minuten in de hitlijsten al kritiek kunnen worden en periodes van onoverkomelijke depressie onder managers kunnen veroorzaken. Omdat de behandeling van depressie een ondankbare taak is, zijn er technische oplossingen nodig.

Ten eerste fouttolerantie, zodat een plotseling probleem op de server geen psychiatrische zombie-apocalyps op kantoor veroorzaakt. Ten tweede, opschalen om meer dan 4 miljoen MPS te kunnen accepteren, zonder diep in de Linux-netwerkstack te graven en rustig “in de breedte” te groeien tot de vereiste omvang.

Omdat we ruimte hadden voor schaalvergroting, besloten we te beginnen met fouttolerantie. "OVER! Fouttolerantie! Het is simpel, we kunnen het”, dachten we en lanceerden twee servers, met op elke server een kopie van brubeck. Om dit te doen, moesten we verkeer met statistieken naar beide servers kopiëren en hier zelfs voor schrijven klein hulpprogramma. We hebben het fouttolerantieprobleem hiermee opgelost, maar... niet zo goed. In eerste instantie leek alles geweldig: elke brubeck verzamelt zijn eigen aggregatieversie, schrijft elke 30 seconden gegevens naar Graphite en overschrijft het oude interval (dit gebeurt aan de Graphite-kant). Als een server plotseling uitvalt, hebben we altijd een tweede met een eigen kopie van de verzamelde gegevens. Maar hier is het probleem: als de server uitvalt, verschijnt er een “zaag” in de grafieken. Dit komt door het feit dat de intervallen van 30 seconden van Brubeck niet gesynchroniseerd zijn en dat op het moment van een crash een ervan niet wordt overschreven. Wanneer de tweede server start, gebeurt hetzelfde. Redelijk draaglijk, maar ik wil beter! Het probleem van de schaalbaarheid is ook niet verdwenen. Alle statistieken ‘vliegen’ nog steeds naar één enkele server en daarom zijn we beperkt tot dezelfde 2-4 miljoen MPS, afhankelijk van het netwerkniveau.

Als je een beetje over het probleem nadenkt en tegelijkertijd sneeuw opgraaft met een schop, dan kan het volgende voor de hand liggende idee in je opkomen: je hebt statistieken nodig die in de gedistribueerde modus kunnen werken. Dat wil zeggen, een die synchronisatie tussen knooppunten in tijd en statistieken implementeert. “Natuurlijk bestaat zo’n oplossing waarschijnlijk al”, zeiden we en gingen naar Google…. En ze vonden niets. Na het doornemen van de documentatie voor verschillende statistieken (https://github.com/etsy/statsd/wiki#server-implementations vanaf 11.12.2017 december XNUMX) hebben we absoluut niets gevonden. Blijkbaar zijn noch de ontwikkelaars, noch de gebruikers van deze oplossingen nog ZO veel statistieken tegengekomen, anders zouden ze zeker iets bedenken.

En toen herinnerden we ons de 'speelgoed'-statistieken - bioyino, die was geschreven tijdens de Just for Fun-hackathon (de naam van het project werd vóór de start van de hackathon door het script gegenereerd) en beseften dat we dringend onze eigen statistieken nodig hadden. Waarvoor?

  • omdat er te weinig statsd-klonen in de wereld zijn,
  • omdat het mogelijk is om de gewenste of bijna de gewenste fouttolerantie en schaalbaarheid te bieden (inclusief het synchroniseren van geaggregeerde statistieken tussen servers en het oplossen van het probleem van het verzenden van conflicten),
  • omdat het mogelijk is om statistieken nauwkeuriger te berekenen dan Brubeck,
  • omdat u zelf meer gedetailleerde statistieken kunt verzamelen, die brubeck ons ​​praktisch niet heeft verstrekt,
  • omdat ik de kans kreeg om mijn eigen hyperperformance gedistribueerde schaallab-applicatie te programmeren, die de architectuur van een andere soortgelijke hyperfor niet volledig zal herhalen... nou ja, dat is alles.

Waar moet je op schrijven? Natuurlijk, in Roest. Waarom?

  • omdat er al een prototypeoplossing bestond,
  • omdat de auteur van het artikel Rust destijds al kende en er graag iets in wilde schrijven voor productie met de mogelijkheid om het in open-source te zetten,
  • omdat talen met GC voor ons niet geschikt zijn vanwege de aard van het ontvangen verkeer (bijna realtime) en GC-pauzes praktisch onaanvaardbaar zijn,
  • omdat je maximale prestaties nodig hebt die vergelijkbaar zijn met C
  • omdat Rust ons onbevreesde gelijktijdigheid biedt, en als we het in C/C++ zouden gaan schrijven, zouden we nog meer kwetsbaarheden, bufferoverflows, racecondities en andere enge woorden hebben binnengehaald dan brubeck.

Er was ook een argument tegen Rust. Het bedrijf had geen ervaring met het maken van projecten in Rust, en nu zijn we ook niet van plan het in het hoofdproject te gebruiken. Daarom waren er ernstige angsten dat niets zou lukken, maar we besloten een gokje te wagen en het te proberen.

Verstreken tijd...

Eindelijk, na verschillende mislukte pogingen, was de eerste werkende versie klaar. Wat is er gebeurd? Dit is wat er gebeurde.

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Elk knooppunt ontvangt zijn eigen set metrieken en verzamelt deze, en voegt geen metrieken samen voor de typen waarvoor de volledige set nodig is voor de uiteindelijke aggregatie. De knooppunten zijn met elkaar verbonden door een soort gedistribueerd slotprotocol, waarmee je de enige kunt selecteren (hier riepen we) die het waard is om statistieken naar de Grote te sturen. Dit probleem wordt momenteel opgelost door Consul, maar in de toekomst strekken de ambities van de auteur zich uit tot eigen implementatie Raft, waarbij de meest waardige persoon natuurlijk het knooppunt van de consensusleider zal zijn. Naast consensus sturen knooppunten vrij vaak (standaard één keer per seconde) die delen van vooraf geaggregeerde statistieken naar hun buren die ze in die seconde hebben verzameld. Het blijkt dat de schaalbaarheid en fouttolerantie behouden blijven: elk knooppunt beschikt nog steeds over een volledige set metrieken, maar de metrieken worden al geaggregeerd verzonden, via TCP en gecodeerd in een binair protocol, zodat de duplicatiekosten aanzienlijk worden verlaagd in vergelijking met UDP. Ondanks het vrij grote aantal binnenkomende statistieken vereist accumulatie zeer weinig geheugen en zelfs minder CPU. Voor onze zeer samendrukbare mertics is dit slechts enkele tientallen megabytes aan gegevens. Als extra bonus krijgen we geen onnodige gegevensherschrijvingen in Graphite, zoals het geval was bij Burbeck.

UDP-pakketten met statistieken zijn onevenwichtig tussen knooppunten op netwerkapparatuur via een eenvoudige Round Robin. Uiteraard parseert de netwerkhardware de inhoud van pakketten niet en kan daarom veel meer dan 4 miljoen pakketten per seconde ophalen, om nog maar te zwijgen van meetgegevens waar het helemaal niets van weet. Als we er rekening mee houden dat de statistieken niet één voor één in elk pakket voorkomen, verwachten we op dit punt geen prestatieproblemen. Als een server crasht, detecteert het netwerkapparaat dit snel (binnen 1-2 seconden) en verwijdert het de gecrashte server uit de rotatie. Als resultaat hiervan kunnen passieve (d.w.z. niet-leider) knooppunten praktisch aan en uit worden gezet zonder dat er tekenen van dalingen op de kaarten optreden. Het maximum dat we verliezen, maakt deel uit van de statistieken die op de laatste seconde binnenkwamen. Een plotseling verlies/uitschakeling/wissel van een leider zal nog steeds een kleine anomalie veroorzaken (het interval van 30 seconden is nog steeds niet gesynchroniseerd), maar als er communicatie tussen knooppunten is, kunnen deze problemen worden geminimaliseerd, bijvoorbeeld door het verzenden van synchronisatiepakketten .

Iets over de interne structuur. De applicatie is uiteraard multithreaded, maar de threading-architectuur is anders dan die gebruikt in brubeck. De draden in Brubeck zijn hetzelfde: elk van hen is verantwoordelijk voor zowel het verzamelen als aggregeren van informatie. Bij bioyino zijn de werknemers verdeeld in twee groepen: degenen die verantwoordelijk zijn voor het netwerk en degenen die verantwoordelijk zijn voor de aggregatie. Door deze indeling kunt u de applicatie flexibeler beheren, afhankelijk van het type metriek: waar intensieve aggregatie vereist is, kunt u aggregators toevoegen, waar er veel netwerkverkeer is, kunt u het aantal netwerkstromen toevoegen. Op dit moment werken we op onze servers in 8 netwerk- en 4 aggregatiestromen.

Het tellen (verantwoordelijk voor aggregatie) is behoorlijk saai. Buffers gevuld door netwerkstromen worden verdeeld over telstromen, waar ze vervolgens worden ontleed en geaggregeerd. Op verzoek worden statistieken gegeven voor verzending naar andere knooppunten. Dit alles, inclusief het verzenden van gegevens tussen knooppunten en het werken met Consul, wordt asynchroon uitgevoerd en draait op het framework Tokyo.

Veel meer problemen tijdens de ontwikkeling werden veroorzaakt door het netwerkgedeelte dat verantwoordelijk was voor het ontvangen van statistieken. Het belangrijkste doel van het scheiden van netwerkstromen in afzonderlijke entiteiten was de wens om de tijd die een stroom doorbrengt te verkorten geen om gegevens uit de socket te lezen. Opties die gebruik maken van asynchrone UDP en reguliere recvmsg verdwenen snel: de eerste verbruikt te veel CPU van de gebruikersruimte voor gebeurtenisverwerking, de tweede vereist te veel contextwisselingen. Daarom wordt het nu gebruikt recvmmsg met grote buffers (en buffers, heren agenten, dat is niets voor u!). Ondersteuning voor reguliere UDP is gereserveerd voor lichte gevallen waarin recvmmsg niet nodig is. In de multimessage-modus is het mogelijk om het belangrijkste te bereiken: het overgrote deel van de tijd harkt de netwerkthread de wachtrij van het besturingssysteem - leest gegevens uit de socket en brengt deze over naar de gebruikersruimtebuffer, waarbij slechts af en toe wordt overgeschakeld naar het geven van de gevulde buffer aan aggregatoren. De wachtrij in de socket stapelt zich praktisch niet op, het aantal gevallen pakketten groeit praktisch niet.

Noot

In de standaardinstellingen is de buffergrootte behoorlijk groot ingesteld. Als u plotseling besluit de server zelf te proberen, kunt u tegen het feit aanlopen dat na het verzenden van een klein aantal statistieken deze niet in Graphite aankomen en in de netwerkstreambuffer achterblijven. Om met een klein aantal statistieken te werken, moet u bufsize en task-queue-size op kleinere waarden instellen in de configuratie.

Eindelijk enkele kaarten voor kaartliefhebbers.

Statistieken over het aantal binnenkomende statistieken voor elke server: meer dan 2 miljoen MPS.

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Een van de knooppunten uitschakelen en binnenkomende statistieken opnieuw distribueren.

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Statistieken over uitgaande statistieken: slechts één knooppunt verzendt altijd: de raid-baas.

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Statistieken van de werking van elk knooppunt, rekening houdend met fouten in verschillende systeemmodules.

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Detaillering van binnenkomende statistieken (statistieknamen zijn verborgen).

Bioyino - gedistribueerde, schaalbare aggregator voor statistieken

Wat zijn we van plan met dit alles hierna te doen? Schrijf natuurlijk code, verdomme...! Het project was oorspronkelijk bedoeld als open source en dat zal gedurende de hele levensduur zo blijven. Onze onmiddellijke plannen omvatten het overstappen naar onze eigen versie van Raft, het veranderen van het peer-protocol naar een meer draagbaar protocol, het introduceren van aanvullende interne statistieken, nieuwe soorten statistieken, bugfixes en andere verbeteringen.

Uiteraard is iedereen welkom om te helpen bij de ontwikkeling van het project: PR creëren, Issues bedenken, indien mogelijk reageren, verbeteren, etc.

Dat gezegd hebbende, dat is alles, koop onze olifanten!



Bron: www.habr.com

Voeg een reactie