Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Architektur vun engem Reseau Last Balancer an Yandex.Cloud
Hallo, ech sinn Sergey Elantsev, ech entwéckelen Reseau Last Balancer an Yandex.Cloud. Virdrun hunn ech d'Entwécklung vum L7 Balancer fir de Yandex Portal gefouert - Kollegen e Witz datt egal wat ech maachen, et ass e Balancer. Ech wäert dem Habr Lieser soen wéi een d'Laascht an enger Cloud Plattform verwalten, wat mir als dat idealt Tool gesinn fir dëst Zil z'erreechen, a wéi mir eis Richtung bauen dëst Tool.

Als éischt, loosst eis e puer Begrëffer virstellen:

  • VIP (Virtuell IP) - Balancer IP Adress
  • Server, Backend, Instanz - eng virtuell Maschinn déi eng Applikatioun leeft
  • RIP (Real IP) - Server IP Adress
  • Healthcheck - Iwwerpréift Server Bereetschaft
  • Disponibilitéit Zone, AZ - isoléiert Infrastruktur an engem Rechenzentrum
  • Regioun - eng Unioun vun verschiddenen AZ

Load Balancer léisen dräi Haaptaufgaben: Si maachen d'Balance selwer aus, verbesseren d'Feeltoleranz vum Service a vereinfachen seng Skaléieren. Feeler Toleranz gëtt duerch automatesch Verkéiersmanagement gesuergt: de Balancer iwwerwaacht den Zoustand vun der Applikatioun an schléisst Fäll aus dem Balance, déi de Livenesscheck net passéieren. Skaléieren gëtt gesuergt andeems d'Laascht gläichméisseg iwwer Instanzen verdeelt gëtt, souwéi d'Lëscht vun den Instanzen aktualiséieren. Wann d'Balance net eenheetlech genuch ass, kréien e puer vun den Instanzen eng Belaaschtung déi hir Kapazitéitlimit iwwerschreift, an de Service gëtt manner zouverlässeg.

E Lastbalancer gëtt dacks klasséiert duerch d'Protokollschicht vum OSI Modell op deem et leeft. De Cloud Balancer funktionéiert um TCP Niveau, wat der véierter Schicht entsprécht, L4.

Loosst eis op en Iwwerbléck iwwer d'Cloud Balancer Architektur goen. Mir wäerte graduell den Detailniveau erhéijen. Mir deelen d'Balancerkomponenten an dräi Klassen. D'Config Fliger Klass ass verantwortlech fir d'Benotzerinteraktioun a späichert den Zilzoustand vum System. D'Kontrollplaner späichert den aktuellen Zoustand vum System a geréiert Systemer aus der Dateplaneklass, déi direkt verantwortlech sinn fir de Verkéier vu Clienten op Är Instanzen ze liwweren.

Daten Fliger

De Verkéier endet op deier Apparater genannt Grenzrouter. Fir Feeler Toleranz ze erhéijen, funktionnéiere verschidde sou Geräter gläichzäiteg an engem Datenzenter. Als nächst geet de Verkéier op d'Balancer, déi allcast IP Adressen un all AZ iwwer BGP fir Clienten annoncéieren. 

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Traffic gëtt iwwer ECMP iwwerdroen - dëst ass eng Routingstrategie no där et e puer gläich gutt Strecken zum Zil kann sinn (an eisem Fall ass d'Zil d'Ziel IP Adress) a Päck kënnen laanscht jiddereng vun hinnen geschéckt ginn. Mir ënnerstëtzen och d'Aarbecht an e puer Disponibilitéitszonen no folgendem Schema: Mir reklaméieren eng Adress an all Zone, de Verkéier geet op déi nootste a geet net iwwer seng Grenzen. Méi spéit am Post wäerte mir méi detailléiert kucken wat mam Traffic geschitt.

Configuréieren Fliger

 
De Schlësselkomponent vum Configuratiounsplang ass d'API, duerch déi Basis Operatioune mat Balancer duerchgefouert ginn: Schafung, Läschen, Ännerung vun der Zesummesetzung vun Instanzen, Erhalen vun Gesondheetscheckresultater, etc. Engersäits ass dëst e REST API, an op der aner, mir an der Cloud benotzen ganz oft de Kader gRPC, also mir "iwwersetzen" REST zu gRPC an dann benotzen nëmmen gRPC. All Ufro féiert zu der Schafung vun enger Serie vun asynchronen idempotenten Aufgaben, déi op engem gemeinsame Pool vu Yandex.Cloud Aarbechter ausgefouert ginn. Aufgaben sinn esou geschriwwe ginn, datt se zu all Moment suspendéiert an dann nei gestart ginn. Dëst garantéiert Skalierbarkeet, Widderhuelbarkeet a Logbicher vun Operatiounen.

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Als Resultat wäert d'Aufgab vun der API eng Ufro un de Balancer Service Controller maachen, deen am Go geschriwwen ass. Et kann Balancer addéieren an ewechhuelen, d'Zesummesetzung vun Backends an Astellungen änneren. 

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

De Service späichert säin Zoustand an der Yandex Datebank, eng verdeelt verwaltete Datebank déi Dir geschwënn benotze kënnt. An Yandex.Cloud, wéi mir schonn erzielt, d'Hënnfudderkonzept gëllt: wa mir eis Servicer selwer benotzen, da wäerten eis Clientë se och frou benotzen. Yandex Datebank ass e Beispill vun der Ëmsetzung vun esou engem Konzept. Mir späicheren all eis Donnéeën an YDB, a mir mussen net iwwer d'Erhalen an d'Skaléierung vun der Datebank denken: dës Problemer gi fir eis geléist, mir benotzen d'Datebank als Service.

Loosst eis zréck op de Balancer Controller. Seng Aufgab ass d'Informatioun iwwer de Balancer ze späicheren an eng Aufgab ze schécken fir d'Bereetschaft vun der virtueller Maschinn un de Healthcheck Controller ze kontrolléieren.

Healthcheck Controller

Et kritt Ufroe fir d'Kontrollregelen z'änneren, späichert se an YDB, verdeelt Aufgaben ënner Healcheck-Knäppchen an aggregéiert d'Resultater, déi dann an d'Datebank gespäichert ginn an un de Loadbalancer Controller geschéckt ginn. Et schéckt ofwiesselnd eng Ufro fir d'Zesummesetzung vum Stärekoup am Datefliger op de Loadbalancer-Node z'änneren, déi ech hei ënnen diskutéieren.

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Loosst eis méi iwwer Gesondheetschecken schwätzen. Si kënnen an e puer Klassen ënnerdeelt ginn. Auditen hu verschidden Erfollegskriterien. TCP Kontrollen mussen erfollegräich eng Verbindung bannent enger fixer Zäit opbauen. HTTP Kontrollen erfuerderen souwuel eng erfollegräich Verbindung an eng Äntwert mat engem 200 Statuscode.

Och Schecken ënnerscheeden sech an der Handlungsklasse - si sinn aktiv a passiv. Passiv Kontrollen iwwerwaachen einfach wat mam Traffic geschitt ouni speziell Handlungen ze huelen. Dëst funktionnéiert net ganz gutt op L4, well et hänkt vun der Logik vun de Protokoller op héijer Niveau of: op L4 gëtt et keng Informatioun iwwer wéi laang d'Operatioun gedauert huet oder ob d'Verbindung fäerdeg war gutt oder schlecht. Aktiv Kontrollen erfuerderen de Balancer fir Ufroen un all Serverinstanz ze schécken.

Déi meescht Laaschtbalancer maachen d'Livenesschecken selwer. Bei Cloud hu mir décidéiert dës Deeler vum System ze trennen fir d'Skalierbarkeet ze erhéijen. Dës Approche erlaabt eis d'Zuel vun de Balancer ze erhéijen, wärend d'Zuel vun de Gesondheetscheck-Ufroen un de Service behalen. Kontrollen ginn duerch getrennte Gesondheetscheckknäppchen duerchgefouert, iwwer déi Kontrollziler zerstéiert a replizéiert ginn. Dir kënnt keng Kontrolle vun engem Host ausféieren, well et kann ausfalen. Da kréie mir net den Zoustand vun den Instanzen, déi hien iwwerpréift huet. Mir maachen Kontrollen op jiddereng vun den Instanzen aus op d'mannst dräi Healthcheck Noden. Mir schneiden d'Ziler vun de Kontrollen tëscht Noden mat konsequenten Hashing Algorithmen.

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Trennung vu Balance a Gesondheetscheck kann zu Probleemer féieren. Wann de Healthcheck Node Ufroe fir d'Instanz mécht, de Balancer ëmgoen (deen de Moment net de Verkéier servéiert), da entsteet eng komesch Situatioun: d'Ressource schéngt lieweg ze sinn, awer de Traffic wäert et net erreechen. Mir léisen dëse Problem op dës Manéier: mir si garantéiert de Gesondheetscheckverkéier duerch Balancer ze initiéieren. An anere Wierder, de Schema fir Pakete mat Verkéier vu Clienten a vu Gesondheetschecken ze bewegen ënnerscheet sech minimal: a béide Fäll wäerten d'Päckchen d'Balancer erreechen, déi se un d'Zilressourcen liwweren.

Den Ënnerscheed ass datt Clienten Ufroe bei VIP maachen, während Gesondheetschecken Ufroe fir all eenzel RIP maachen. En interessante Problem entsteet hei: Mir ginn eise Benotzer d'Méiglechkeet Ressourcen a groe IP Netzwierker ze kreéieren. Loosst eis virstellen datt et zwee verschidde Wollekebesëtzer sinn déi hir Servicer hannert Balancer verstoppt hunn. Jidderee vun hinnen huet Ressourcen am 10.0.0.1/24 Subnet, mat de selwechte Adressen. Dir musst fäeg sinn se iergendwéi z'ënnerscheeden, an hei musst Dir an d'Struktur vum Yandex.Cloud virtuelle Netzwierk tauchen. Et ass besser fir méi Detailer erauszefannen Video vun iwwer: Cloud Event, Et ass wichteg fir eis elo datt d'Netzwierk Multi-Layer ass an Tunnelen huet, déi duerch Subnet ID z'ënnerscheeden kënnen.

Healthcheck Node kontaktéiert Balancer mat sougenannten quasi-IPv6 Adressen. Eng Quasi-Adress ass eng IPv6 Adress mat enger IPv4 Adress a Benotzer-Subnet ID dran agebonnen. De Verkéier erreecht de Balancer, deen d'IPv4 Ressource Adress dovun extrahéiert, ersetzt IPv6 mat IPv4 a schéckt de Paket an de Benotzer Netzwierk.

De Réckverkéier geet dee selwechte Wee: de Balancer gesäit datt d'Destinatioun e groe Netzwierk vu Gesondheetschecker ass, an konvertéiert IPv4 op IPv6.

VPP - d'Häerz vun der Daten Fliger

De Balancer gëtt mat Vector Packet Processing (VPP) Technologie implementéiert, e Kader vu Cisco fir Batchveraarbechtung vum Netzwierkverkéier. An eisem Fall funktionnéiert de Kader uewen op der User-Space Network Device Management Bibliothéik - Data Plane Development Kit (DPDK). Dëst garantéiert eng héich Paketveraarbechtungsleistung: vill manner Ënnerbriechungen geschéien am Kernel, an et gi keng Kontextschalter tëscht Kernelraum a Benotzerraum. 

VPP geet nach méi wäit an dréckt nach méi Leeschtung aus dem System andeems Dir Packagen a Chargen kombinéiert. D'Leeschtungsgewënn kommen aus der aggressiver Notzung vu Cache op modernen Prozessoren. Béid Datecache gi benotzt (Päckchen ginn an "Vecteure" veraarbecht, d'Daten sinn no beieneen) an Instruktiounscaches: am VPP follegt d'Packetveraarbechtung eng Grafik, d'Noden vun deenen Funktiounen enthalen déi déiselwecht Aufgab ausféieren.

Zum Beispill geschitt d'Veraarbechtung vun IP-Päckchen am VPP an der folgender Uerdnung: als éischt ginn d'Packet-Header am Parsing-Node parséiert, an dann gi se an den Node geschéckt, deen d'Päckchen weider no Routingtabellen weiderginn.

E bëssen Hardcore. D'Autoren vu VPP toleréiere keng Kompromësser am Gebrauch vu Prozessor-Caches, sou datt typesch Code fir e Vektor vu Pakete veraarbecht gëtt manuell Vektoriséierung: et gëtt eng Veraarbechtungsschleife, an där eng Situatioun wéi "mir hu véier Paketen an der Schlaang" veraarbecht gëtt, dann d'selwecht fir zwee, dann - fir een. Prefetch Instruktioune ginn dacks benotzt fir Daten an Cache ze lueden fir den Zougang zu hinnen a spéider Iteratiounen ze beschleunegen.

n_left_from = frame->n_vectors;
while (n_left_from > 0)
{
    vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    // ...
    while (n_left_from >= 4 && n_left_to_next >= 2)
    {
        // processing multiple packets at once
        u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        // ...
        /* Prefetch next iteration. */
        {
            vlib_buffer_t *p2, *p3;

            p2 = vlib_get_buffer (vm, from[2]);
            p3 = vlib_get_buffer (vm, from[3]);

            vlib_prefetch_buffer_header (p2, LOAD);
            vlib_prefetch_buffer_header (p3, LOAD);

            CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
            CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
        }
        // actually process data
        /* verify speculative enqueues, maybe switch current next frame */
        vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
                to_next, n_left_to_next,
                bi0, bi1, next0, next1);
    }

    while (n_left_from > 0 && n_left_to_next > 0)
    {
        // processing packets by one
    }

    // processed batch
    vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}

Also, Healthchecks schwätzen iwwer IPv6 mam VPP, wat se an IPv4 verwandelt. Dëst gëtt vun engem Node an der Grafik gemaach, déi mir algorithmesch NAT nennen. Fir ëmgedréint Traffic (a Konversioun vun IPv6 op IPv4) gëtt et deeselwechten algorithmesche NAT Node.

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Direkte Verkéier vun de Balancer Clienten geet duerch d'Grafiknoden, déi d'Balance selwer ausféieren. 

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Den éischte Node ass plakeg Sessiounen. Et späichert den Hash vun 5-tupp fir etabléiert Sessiounen. 5-Tuple enthält d'Adress an den Hafen vum Client, aus deem d'Informatioun iwwerdroe gëtt, d'Adress an d'Ports vun de Ressourcen, déi verfügbar sinn fir den Traffic ze kréien, souwéi den Netzwierkprotokoll. 

De 5-Tupel Hash hëlleft eis manner Berechnung am spéideren konsequenten Hashing Node auszeféieren, souwéi besser Ressourcenlëscht Ännerungen hannert dem Balancer ze handhaben. Wann e Paket fir deen et keng Sessioun am Balancer ukommt, gëtt en an de konsequente Hashing Node geschéckt. Dëst ass wou d'Balance geschitt mat konsequenten Hashing: mir wielt eng Ressource aus der Lëscht vun verfügbaren "Live" Ressourcen. Als nächst ginn d'Päckchen op den NAT Node geschéckt, deen tatsächlech d'Destinatiounsadress ersetzt an d'Kontrollsummen nei berechent. Wéi Dir gesitt, verfollegen mir d'Regele vu VPP - gär gär, gruppéiere ähnlech Berechnungen fir d'Effizienz vun de Prozessor Cache ze erhéijen.

Konsequent Hashing

Firwat hu mir et gewielt a wat ass et iwwerhaapt? Als éischt, loosst eis déi viregt Aufgab betruechten - eng Ressource aus der Lëscht auswielen. 

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Mat inkonsistente Hashhing gëtt den Hash vum erakommende Paket berechent, an eng Ressource gëtt aus der Lëscht ausgewielt andeems de Rescht vun dësem Hash duerch d'Zuel vun de Ressourcen deelt. Soulaang d'Lëscht onverännert bleift, funktionnéiert dëse Schema gutt: mir schécken ëmmer Pakete mat deemselwechte 5-Tupel op déiselwecht Instanz. Wann, zum Beispill, e puer Ressourcen opgehalen op Gesondheetschecken ze reagéieren, da ännert sech fir e groussen Deel vun den Hashes d'Wiel. D'TCP-Verbindunge vum Client wäerte gebrach ginn: e Paket, dee virdru Instanz A erreecht huet, kann ufänken Instanz B z'erreechen, déi net mat der Sessioun fir dëse Paket vertraut ass.

Konsequent Hashing léist de beschriwwene Problem. Deen einfachste Wee fir dëst Konzept z'erklären ass dëst: stellt Iech vir datt Dir e Ring hutt, op deen Dir Ressourcen per Hash verdeelt (zum Beispill duerch IP: Port). Ressource Selektioun ass eng Rotatioun vum Rad duerch e Wénkel, deen duerch den Hash vum Paket bestëmmt gëtt.

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Dëst miniméiert d'Verdeelung vum Verkéier wann d'Zesummesetzung vun de Ressourcen ännert. D'Läschen vun enger Ressource beaflossen nëmmen den Deel vum konsequenten Hashingring an deem d'Ressource läit. Eng Ressource bäizefügen ännert och d'Verdeelung, awer mir hunn e Sticky Sessiounsknuet, wat eis erlaabt net schonn etabléiert Sessiounen op nei Ressourcen ze wiesselen.

Mir hunn gekuckt wat mam direkte Verkéier tëscht dem Balancer a Ressourcen geschitt. Loosst eis elo de Retourverkéier kucken. Et follegt datselwecht Muster wéi de Kontrollverkéier - duerch algorithmesch NAT, dat ass, duerch ëmgedréint NAT 44 fir Clientverkéier an duerch NAT 46 fir Gesondheetscheckverkéier. Mir halen un eisem eegene Schema: mir vereenegen de Gesondheetscheckverkéier an de richtege Benotzerverkéier.

Loadbalancer-Node a versammelt Komponenten

D'Zesummesetzung vun de Balancer a Ressourcen am VPP gëtt vum lokalen Service gemellt - Loadbalancer-Node. Et abonnéiert op de Stroum vun Eventer vum Loadbalancer-Controller an ass fäeg den Ënnerscheed tëscht dem aktuellen VPP-Status an dem Zilstaat vum Controller ze plotten. Mir kréien e zouenen System: Eventer vun der API kommen op de Balancer Controller, deen Aufgaben dem Healthcheck Controller zougewisen huet fir d'"Liveness" vun de Ressourcen ze kontrolléieren. Dat, am Tour, gëtt Aufgaben un de Gesondheetscheck-Node zou an aggregéiert d'Resultater, duerno schéckt se se zréck an de Balancer Controller. Loadbalancer-Node abonnéiert op Eventer vum Controller an ännert den Zoustand vum VPP. An esou engem System weess all Service nëmmen wat iwwer Nopeschservicer néideg ass. D'Zuel vun de Verbindungen ass limitéiert a mir hunn d'Fäegkeet verschidde Segmenter onofhängeg ze bedreiwen an ze skaléieren.

Architektur vun engem Reseau Last Balancer an Yandex.Cloud

Wéi eng Problemer goufen vermeit?

All eis Servicer am Kontrollplang sinn a Go geschriwwen an hunn gutt Skaléieren an Zouverlässegkeet Charakteristiken. Go huet vill Open Source Bibliothéike fir verdeelt Systemer ze bauen. Mir benotzen aktiv GRPC, all Komponenten enthalen eng Open Source Implementatioun vun Service Entdeckung - eis Servicer iwwerwaachen d'Performance vuneneen, kënnen hir Zesummesetzung dynamesch änneren, a mir hunn dëst mat GRPC Balance verbonnen. Fir Metriken benotze mir och eng Open Source Léisung. Am Datefliger hu mir eng uerdentlech Leeschtung an eng grouss Ressourcereserven: et war ganz schwéier e Stand ze sammelen, op deem mir op d'Leeschtung vun engem VPP vertrauen kënnen, anstatt eng Eisen Netzwierkkaart.

Problemer an Léisungen

Wat huet net sou gutt geklappt? Go huet automatesch Erënnerung Gestioun, mee Erënnerung Fuite passéieren nach. Deen einfachste Wee fir mat hinnen ze këmmeren ass d'Goroutinen ze lafen an drun ze erënneren datt se ofgeschloss sinn. Takeaway: Kuckt d'Erënnerungsverbrauch vun Äre Go Programmer. Oft ass e gudde Indikator d'Zuel vu Goroutinen. Et gëtt e Plus an dëser Geschicht: am Go ass et einfach Runtimedaten ze kréien - Erënnerungsverbrauch, d'Zuel vun de Lafen Goroutinen a vill aner Parameteren.

Och Go ass vläicht net déi bescht Wiel fir funktionell Tester. Si sinn zimlech verbose, an d'Standard Approche fir "Alles am CI an enger Partie ze lafen" ass net ganz gëeegent fir si. D'Tatsaach ass datt funktionell Tester méi Ressource erfuerderlech sinn a real Timeouts verursaachen. Wéinst dësem kënnen Tester versoen well d'CPU mat Eenheetstester beschäftegt ass. Fazit: Wa méiglech, maacht "schwéier" Tester getrennt vun Eenheetstester. 

Microservice Event Architektur ass méi komplex wéi e Monolith: Logbicher op Dosende vu verschiddene Maschinnen sammelen ass net ganz bequem. Fazit: Wann Dir Mikroservicer maacht, denkt direkt un Tracing.

Eis Pläng

Mir wäerten en internen Balancer starten, en IPv6 Balancer, Ënnerstëtzung fir Kubernetes Scripten addéieren, weider eis Servicer zerstéieren (am Moment sinn nëmmen Healthcheck-Node a Healthcheck-ctrl zerstéiert), nei Gesondheetschecken addéieren, an och intelligent Aggregatioun vu Schecken implementéieren. Mir iwwerleeën d'Méiglechkeet eis Servicer nach méi onofhängeg ze maachen - sou datt se net direkt matenee kommunizéieren, mee mat enger Messageschlaang. En SQS-kompatibel Service ass viru kuerzem an der Cloud opgetaucht Yandex Message Queue.

Viru kuerzem ass d'ëffentlech Verëffentlechung vum Yandex Load Balancer stattfonnt. Entdeckt Dokumentatioun zum Service, verwalten Balancer op eng Manéier déi Iech bequem ass an d'Feeltoleranz vun Äre Projeten erhéijen!

Source: will.com

Setzt e Commentaire