
TL;DR: Our internal network configuration management system, QControl, is based on a client-server architecture. At its core is a two-level transport protocol that operates with messages packaged in gzip without decompression between endpoints. Distributed routers and endpoints receive configuration updates, while the protocol allows for the establishment of localized intermediate relays. The system is built on the principle of ('recent-stable', explained below) and utilizes the JMESpath query language along with the Jinja templating engine for rendering configuration files.
Qrator Labs manages a globally distributed DDoS mitigation network. Our network operates on an anycast principle, and subnets are announced via BGP. As a BGP anycast network physically located in multiple regions of the Earth, we can process and filter illegitimate traffic closer to the core of the internet — Tier-1 operators.
On the other hand, being a geographically distributed network is not easy. Communication between network points of presence is critically important for the security service provider to have a consistent configuration across all network nodes, updating them in a timely manner. Therefore, in order to provide the highest possible level of the core service to the consumer, we needed to find a way to reliably synchronize configuration data across continents.
In the beginning was the Word. It quickly became a communication protocol that needed updating.
QControli olemus ja põhjus, miks kulutame palju aega ja ressursse sellise protokolli loomisele, on vajadus omada ühtset usaldusväärset konfiguratsiooniallikat ning lõpuks sünkroonida meie kohaloleku punktid sellega. Andmete salvestamine oli vaid üks mitmest nõudest QControli arendamisel. Lisaks oli meil vaja integreerimist olemasolevate ja kavandatavate teenustega kohaloleku punktides (KP), nutikaid (ja kohandatavaid) andmete valideerimise viise ning juurdepääsu piiramist. Samuti soovisime juhtida sellist süsteemi käsudega, mitte failide muutmise teel. Enne QControli saadeti andmed kohaloleku punktidesse peaaegu käsitsi. Kui mõni kohaloleku punkt oli kergesti kättesaamatu ja me unustasime hiljem selle uuendamise, oli konfiguratsioon desünkroniseeritud — tuli kulutada aega selle taastamiseks.
Seetõttu tulime välja järgmise skeemiga:

Konfiguratsiooniserver vastutab andmete valideerimise ja ladustamise eest, ruuteril on mitmed lõpp-punktid, mis saavad ja edastavad konfiguratsioonipä_UPDATE_d klientidelt ja tugimeeskonnalt serverile ning serverilt kohaloleku punktidesse.
Internetiühenduse kvaliteet varieerub endiselt oluliselt eri nurkades maailmas — et illustreerida seda väidet, uurime lihtsat MTR-d Praha, Tšehhi Vabariigist Singapuri ja Hongkongi.
MTR Praha ja Singapuri vahel
Sama Hongkongi suunas
Suured viivitused tähendavad madalamat kiirus. Lisaks on andmepakettide kadu. Kanalite laius ei kompenseeri seda probleemi, mis tuleb alati arvesse võtta detsentraliseeritud süsteemide loomisel.
Kohaloleku punkti täiskonfiguratsioon on märkimisväärne andmemaht, mis tuleb edastada paljudele vastuvõtjatele ebakindlate ühenduste kaudu. Õnneks muutub konfiguratsioon pidevalt, kuid see juhtub väikeste portsjonitena.
recent-stable disain
Võib öelda, et jaotatud võrgu ülesehitamine inkrementaalsete uuenduste põhimõttel on piisavalt ilmne lahendus. Kuid difffidega on seotud palju probleeme. Me peame säilitama kõik difid tugipunktide vahel ning suutma neid edastada juhul, kui keegi on osa andmeid kaotanud. Iga sihtkoht peab neid rakendama rangelt määratud järjestuses. Tavaliselt võib selline operatsioon mitme sihtkoha korral võtta kaua aega. Saaja peab olema ka võimeline küsima puuduvad osad ja loomulikult peab keskmine osa sellele päringule korrektselt vastama, saates ainult puuduvaid andmeid.
Lõpuks jõudsime üsna huvitava lahenduseni — meil on ainult üks fikseeritud tugikiht, nimetame seda stable, ja ainult üks diff selle jaoks — recent. Iga recent põhineb viimasel loodud stable'il ja on piisav konfiguratsioonide andmete uuendamiseks. Kui värske recent sihtkohta jõuab, ei ole vana enam vajalik.
Jäänud on vaid aeg-ajalt saata värske stable konfiguratsioon, näiteks kuna recent on muutunud liiga suureks. Samuti on oluline, et me saadame kõik need uuendused raadiosaatmine/multikaudist, muretsemata üksikute saajate üle ja nende võime üle andmeosade kogumiseks. Kui oleme veendunud, et kõigil on õige stable — saadame ainult uusi recent. Kas tasub rõhutada, et see töötab? Töötab. Stable salvestatakse konfiguratsiooniserveris ja saajates, recent luuakse vajadusel.
Kahe taseme transpordiarhitektuur
Miks me ehitasime oma transpordi kahes kihis? Vastus on üsna lihtne — soovisime eraldada marsruutimise kõrgtasemest loogikast, inspireerides end OSI mudelist oma transporditaseme ja rakendustaseme kaudu. Transportprotokollina kasutasime Thrift'i ja kõrgtaseme juhtsõnumite vorminguks msgpack seerimisvormingut. Just seetõttu ei vaata ruuter (mida tehakse multicast/raadiosaatmine/suhtlemine) msgpack'i sisse, ei dekompresseeri ega kompressi sisu tagasi ja teeb ainult andmete edastamist.
Thrift (inglise keeles 'kasutuste ring') on liidese kirjeldamise keel, mida kasutatakse teenuste määratlemiseks ja loomiseks erinevates programmeerimiskeeltes. See on kaugkutsesüsteemide (RPC) raamistik. See ühendab endas programmeerimissegu koos koodigeneratsiooni mootori teenuste väljatöötamiseks, mis töötavad eri keelte vahel suhteliselt tõhusalt ja lihtsalt.
Valisime Thrift raamistikku RPC ja mitme keele toe tõttu. Nagu tavaliselt, osutusid kergemaks osadeks klient ja server. Kuid ruuter osutus keerukaks pähkliks, osaliselt valmis lahenduse puudumise tõttu meie arenduse ajal.
On olemas ka teisi võimalusi, nagu protobuf / gRPC, kuid kui me meie projekti alustasime, oli gRPC veel piisavalt noor ja me ei julgenud seda kasutada.
Muidugi oleksime võinud (ja tegelikult oleks pidanud) ehitama oma jalgratta. Protokolli loomine selleks, mida me vajame, oleks olnud lihtsam, kuna kliendi-serveri arhitektuur on võrreldes Thrift'il põhineva ruuteri ülesehitusega suhteliselt sirgjooneline. Niisiis, suur osa eelarvamusest isetehtud protokollide ja populaarsete raamatukogude rakenduste suhtes on täiesti olemas; lisaks tõstatatakse arutelu käigus alati küsimus: 'Kuidas me selle teistele keeltele portime?'. Seetõttu viskasime kohe jalgratta ideed kõrvale.
Msgpack on JSON analoog, kuid kiirem ja väiksem. See on binaarne andmeseriasioonivorming, mis võimaldab andmevahetust mitme keele vahel.
Esimesel tasemel on meil Thrift koos miinimum vajalikku teabega ruuteri jaoks sõnumi edastamiseks. Teisel tasemel on pakitud struktuurid msgpack.
Valisime msgpack'i, kuna see on kiiremini ja kompaktsem kui JSON. Kuid veelgi olulisem on see, et see toetab kohandatud andmetüüpe, mis võimaldab meil kasutada ägedaid funktsioone, nagu toorete binaaride edastamine või erilised objekti tähistamine andmete puudumise korral, mis oli meie 'recent-stable' skeemi jaoks oluline.
JMESPath
JMESPath on JSON'i päringute keel.
Just这样 выглядит описание, которое мы получаем из официальной документации JMESPath, но на самом деле, он дает гораздо больше. JMESPath позволяет искать и фильтровать поддеревья в произвольной древовидной структуре, а также применять изменения к данным на лету. Он позволяет добавлять специальные фильтры и процедуры преобразования данных. Хотя он, конечно, требует напряжения головного мозга для понимания.
Jinja
Для некоторых потребителей необходимо превращать конфигурацию в файл — поэтому мы используем шаблонный движок, и Jinja является очевидным выбором. С его помощью мы генерируем конфигурационный файл из шаблона и данных, полученных в точке назначения.
Для генерации файла конфигурации нам нужен запрос JMESPath, шаблон для местоположения файла в файловой системе, шаблон для самого конфигурационного файла. Также на этом этапе неплохо уточнить права доступа к файлу. Все это удалось успешно скомбинировать в одном файле — перед началом шаблона конфигурации мы ставим заголовок в формате YAML, описывающий остальное.
Näiteks:
---
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) }}
Чтобы сделать конфигурационный файл для нового сервиса, мы добавляем только новый файл шаблона. Не требуются никакие изменения исходного кода или программного обеспечения на точках присутствия.
Что изменилось после введения QControl в операционную деятельность? Первое и самое важное — это согласованная и надежная доставка обновлений конфигурации по всем узлам сети. Второе — это получение мощного инструмента проверки конфигурации и внесения изменений нашей командой поддержки, а также потребителями услуги.
Все это мы смогли сделать, задействуя схему обновлений recent-stable для упрощения коммуникации между конфигурационным сервером и получателями конфигурации. Используя двухуровневый протокол для поддержки независимого от содержимого способа маршрутизации данных. Успешно интегрировав основанный на Jinja движок генерации конфигурации в распределенную сеть фильтрации. Эта система поддерживает широкий набор способов конфигурации для нашей распределенной и разношерстной периферии.
Спасибо за помощь в написании материала. , , .
поста.
Allikas: habr.com
