Het configuratiebeheersysteem van het Qrator-filternetwerk

Het configuratiebeheersysteem van het Qrator-filternetwerk

TL;DR: Beschrijving van de client-serverarchitectuur van ons interne netwerkconfiguratiebeheersysteem, QControl. De basis is een tweelaags transportprotocol dat werkt met in gzip verpakte berichten zonder decompressie tussen eindpunten. Verspreide routers en eindpunten ontvangen configuratie-updates, en het protocol maakt de installatie van gelokaliseerde tussenrelais mogelijk. Het systeem is opgebouwd volgens het principe differentiƫle backup ('recent-stable', hieronder uitgelegd) en maakt gebruik van de JMESpath-querytaal samen met de Jinja-sjabloneerder voor het renderen van configuratiebestanden.

Qrator Labs beheert een wereldwijd gedistribueerd netwerk voor het neutraliseren van aanvallen. Ons netwerk werkt volgens het anycast-principe, en subnetten worden aangekondigd via BGP. Als een BGP anycast-netwerk, fysiek gepositioneerd in meerdere regio's van de aarde, kunnen we illegitiem verkeer dichter bij de internetkern — Tier-1 operators — verwerken en filteren.

Aan de andere kant is het niet eenvoudig om een geografisch gedistribueerd netwerk te zijn. Communicatie tussen de netwerk-punten van aanwezigheid is cruciaal voor de beveiligingsdienstverlener om een consistent netwerkconfiguratie van alle knooppunten te waarborgen, deze tijdig bij te werken. Om de hoogst mogelijke kwaliteit van de primaire dienst voor de consument te bieden, moesten we een manier vinden om configuratiegegevens betrouwbaar tussen continenten te synchroniseren.

In het begin was er het Woord. Het werd al snel een communicatieprotocol dat behoefte had aan een update.


De hoeksteen van het bestaan van QControl en tegelijkertijd de belangrijkste reden voor de aanzienlijke tijd en middelen die nodig zijn om een dergelijk protocol op te bouwen, is de noodzaak om een enkele, betrouwbare configuratiebron te verkrijgen en uiteindelijk onze punten van aanwezigheid met deze te synchroniseren. Het opslagmechanisme zelf was slechts een van de vele vereisten tijdens de ontwikkeling van QControl. Daarnaast hadden we integraties nodig met bestaande en geplande diensten op de punten van aanwezigheid (TP), slimme (en aanpasbare) manieren voor gegevensvalidatie en toegangsgroepen. Bovendien wilden we zo'n systeem beheren met commando's en niet door aanpassingen aan bestanden. Voor QControl werden gegevens praktisch handmatig naar de punten van aanwezigheid verzonden. Als een van de punten van aanwezigheid niet beschikbaar was en we vergaten deze later bij te werken, raakte de configuratie uit sync — dit kostte tijd om alles weer op orde te krijgen.

Uiteindelijk hebben we het volgende schema bedacht:
Het configuratiebeheersysteem van het Qrator-filternetwerk
De configuratieserver is verantwoordelijk voor gegevensvalidatie en opslag, de router heeft verschillende eindpunten die configuratie-updates ontvangen en doorgeven van klanten en het ondersteuningsteam naar de server, en van de server naar de punten van aanwezigheid.

De kwaliteit van de internetverbinding verschilt nog steeds aanzienlijk op verschillende plekken op de wereld — ter illustratie van deze stelling, laten we eens kijken naar een eenvoudige MTR van Praag, TsjechiĆ« naar Singapore en Hongkong.

Het configuratiebeheersysteem van het Qrator-filternetwerk
MTR van Praag naar Singapore

Het configuratiebeheersysteem van het Qrator-filternetwerk
Hetzelfde naar Hongkong

Hoge latencies betekenen lagere snelheden. Bovendien is er pakketverlies. De bandbreedte compenseert deze problematiek niet, wat altijd in overweging moet worden genomen bij het bouwen van gedecentraliseerde systemen.

De volledige configuratie van een punt van aanwezigheid is een aanzienlijke hoeveelheid gegevens die over onbetrouwbare verbindingen naar veel ontvangers moet worden verzonden. Gelukkig, hoewel de configuratie voortdurend wijzigt, gebeurt dit in kleine porties.

Ontwerp recent-stable

Men kan zeggen dat het opzetten van een gedistribueerd netwerk op basis van incrementele updates een vrij voor de hand liggende oplossing is. Maar er zijn veel problemen verbonden aan diffs. We moeten alle diffs tussen referentiepunten bewaren en ook in staat zijn om deze op te sturen als iemand een deel van de gegevens heeft gemist. Elk bestemmingspunt moet ze in een strikte volgorde toepassen. Gewoonlijk kan deze operatie behoorlijk wat tijd in beslag nemen bij meerdere bestemmingspunten. De ontvanger moet ook in staat zijn om gemiste delen op te vragen en uiteraard moet het centrale systeem zo'n verzoek correct beantwoorden door alleen de gemiste gegevens te sturen.

Uiteindelijk zijn we tot een vrij interessante oplossing gekomen — we hebben slechts ƩƩn referentielaag, vast, laten we het stable noemen, en slechts ƩƩn diff voor deze laag — recent. Elke recent is gebaseerd op de laatst gevormde stable en is voldoende voor het reconstrueren van de configuratiegegevens. Zodra een verse recent de bestemming bereikt, is de oude al niet meer nodig.

Het blijft alleen nog de vraag om regelmatig de recente stable-configuratie te verzenden, bijvoorbeeld omdat de recent te groot is geworden. Ook is het belangrijk dat we al deze updates in broadcast/multicast modus verzenden, zonder ons zorgen te maken over individuele ontvangers en hun vermogen om datablokken samen te voegen. Zodra we zeker weten dat iedereen de correcte stable heeft — sturen we alleen de nieuwe recent. Is het nodig om aan te geven dat dit werkt? Het werkt. Stable wordt opgeslagen op de configuratieserver en bij de ontvangers, recent wordt aangemaakt op basis van behoefte.

Architectuur van een tweelaags transport

Waarom hebben we ons transport op twee niveaus gebouwd? Het antwoord is vrij simpel — we wilden de routering scheiden van de high-level logica, geĆÆnspireerd door het OSI-model met zijn transportlaag en applicatielaag. Voor het transportprotocol hebben we Thrift gekozen, en voor het high-level formaat van besturingsberichten hebben we het msgpack-serialisatieformaat gebruikt. Daarom kijkt de router (die multicast/broadcast/relay uitvoert) niet naar de inhoud van msgpack, pakt het niet uit en verpakt het niet opnieuw, en voert alleen de datatransmissie uit.

Thrift (van het Engelse 'spaarzaamheid', uitgesproken als [θrift]) is een interface beschrijvings taal die wordt gebruikt voor het definiëren en creëren van diensten voor verschillende programmeertalen. Het is een framework voor remote procedure calls (RPC). Het combineert een softwarepijplijn met een codegeneratie-engine voor de ontwikkeling van diensten die in verschillende mate effectief en eenvoudig werken tussen talen.

We hebben het Thrift-framework gekozen vanwege RPC en de ondersteuning voor meerdere talen. Zoals altijd waren de client en server de gemakkelijke onderdelen. De router bleek echter een uitdaging, gedeeltelijk door het gebrek aan een kant-en-klare oplossing tijdens onze ontwikkeling.

Het configuratiebeheersysteem van het Qrator-filternetwerkEr zijn andere opties, zoals protobuf / gRPC, maar toen we ons project begonnen was gRPC nog vrij nieuw en durfden we het niet aan boord te nemen.

Natuurlijk konden we (en hadden we eigenlijk moeten doen) onze eigen fiets bouwen. Het zou eenvoudiger zijn geweest om een protocol te creƫren voor wat we nodig hadden, omdat client-serverarchitectuur relatief eenvoudig te implementeren is in vergelijking met het bouwen van een router op Thrift. Desondanks is er een traditionele bias tegen zelfgeschreven protocollen en implementaties van populaire bibliotheken (en niet zonder reden), bovendien wordt er altijd de vraag gesteld: 'Hoe gaan we dit naar andere talen porten?'. Dus hebben we meteen het idee van de fiets afgewezen.

Msgpack is een alternatief voor JSON, maar sneller en compacter. Het is een binaire gegevensserialisatie-indeling die het mogelijk maakt om gegevens tussen verschillende talen uit te wisselen.

Op het eerste niveau hebben we Thrift met de minimaal benodigde informatie voor de router om berichten door te sturen. Op het tweede niveau zijn er de verpakte msgpack-structuren.

We hebben voor msgpack gekozen omdat het sneller en compacter is in vergelijking met JSON. Maar belangrijker nog, het ondersteunt aangepaste gegevens typen, waardoor we toffe functies kunnen gebruiken zoals het verzenden van pure binaire gegevens of speciale objecten die de afwezigheid van gegevens aanduiden, wat belangrijk was voor ons 'recent-stable'-schema.

JMESPath
JMESPath is een querytaal voor JSON.
Dit is hoe de beschrijving eruit ziet die we uit de officiƫle JMESPath-documentatie krijgen, maar in werkelijkheid biedt het veel meer. JMESPath stelt ons in staat om subbomen in een willekeurige boomstructuur te zoeken en te filteren, evenals om wijzigingen aan de gegevens on-the-fly toe te passen. Bovendien kunnen we speciale filters en datatransformaties toevoegen. Hoewel het natuurlijk een denkwijze vereist om het te begrijpen.

Jinja
Voor sommige gebruikers moeten we de configuratie omzetten naar een bestand - daarom gebruiken we een sjabloonengine en Jinja is de voor de hand liggende keuze. Hiermee genereren we een configuratiebestand uit een sjabloon en gegevens die op de bestemming zijn verkregen.

Voor het genereren van een configuratiebestand hebben we een JMESPath-query, een sjabloon voor de locatie van het bestand in het bestandssysteem, en een sjabloon voor de configuratie zelf nodig. Het is ook een goed idee om op dit moment de toegangsrechten voor het bestand te verduidelijken. Dit alles hebben we met succes weten te combineren in ƩƩn bestand - voor het begin van het configuratiesjabloon plaatsen we een YAML-header die de rest beschrijft.

Bijvoorbeeld:

---
selector: "[@][?@.fft._meta.version == `42`] | items([0].fft_config || `{}`)"
destination_filename: "fft/{{ match[0] }}.json"
file_mode: 0644
reload_daemons: [fft]
...
{{ dict(match[1]) | json(indent=2, sort_keys=True) }}

Om een configuratiebestand voor de nieuwe service te maken, voegen we alleen een nieuw sjabloonbestand toe. Er zijn geen wijzigingen aan de broncode of software op de aanwezige punten nodig.

Wat is er veranderd na de invoering van QControl in de bedrijfsvoering? Het eerste en belangrijkste is de consistente en betrouwbare levering van configuratie-updates aan alle knooppunten in het netwerk. Ten tweede is er een krachtig hulpmiddel voor configuratiecontrole en wijzigingsverwerking voor ons supportteam en de gebruikers van de dienst verkregen.

Dit alles hebben we bereikt door de recent-stable update schema in te voeren om de communicatie tussen de configuratieserver en de ontvangers van de configuratie te vereenvoudigen. We gebruiken een tweelaagsprotocol ter ondersteuning van een onafhankelijk van inhoud routeringsmethode voor gegevens. We hebben met succes een op Jinja gebaseerde configuratiegeneratie-engine geĆÆntegreerd in een gedistribueerd filteringnetwerk. Dit systeem ondersteunt een breed scala aan configuratiemethoden voor onze gedistribueerde en diverse randapparatuur.

Dank voor de hulp bij het schrijven van het materiaal VolanDamrod, sereniteit, NoN.

Engelse versie post.

Bron: habr.com

Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers šŸ”„ Koop betrouwbare webhosting met bescherming tegen DDoS, VPS VDS servers | ProHoster