Architettura di equilibriu di carica di rete in Yandex.Cloud

Architettura di equilibriu di carica di rete in Yandex.Cloud
Hola, sò Sergey Elantsev, aghju sviluppatu equilibratore di carica di a rete in Yandex.Cloud. Nanzu, aghju guidatu u sviluppu di l'equilibriu L7 per u portale Yandex - i culleghi scherzeghjanu chì ùn importa ciò chì facciu, risulta esse un balancer. Diceraghju à i lettori Habr cumu gestisce a carica in una piattaforma di nuvola, ciò chì vedemu cum'è l'uttellu ideale per ottene stu scopu, è cumu andemu versu a custruzione di stu strumentu.

Prima, presentemu qualchi termini:

  • VIP (Virtual IP) - l'indirizzu IP di l'equilibriu
  • Server, backend, instance - una macchina virtuale cù una applicazione in esecuzione
  • RIP (Real IP) - indirizzu IP di u servitore
  • Healthcheck - cuntrollà a preparazione di u servitore
  • Zona di Disponibilità, AZ - infrastruttura isolata in un centru di dati
  • Regione - una unione di diversi AZ

L'equilibriu di carica risolve trè funzioni principali: realizanu l'equilibriu stessu, migliurà a tolleranza di difetti di u serviziu, è simplificà a so scala. A tolleranza à i difetti hè assicurata da a gestione automatica di u trafficu: l'equilibratore monitoreghja u statu di l'applicazione è esclude da l'istanze di equilibriu chì ùn passanu micca u cuntrollu di vita. A scala hè assicurata da a distribuzione uniforme di a carica à traversu l'istanze, è ancu di l'aghjurnà a lista di l'istanze nantu à a mosca. Se l'equilibriu ùn hè micca abbastanza uniforme, certi casi riceveranu una carica chì supera u so limitu di capacità, è u serviziu diventerà menu affidabile.

Un balancer di carica hè spessu classificatu da a capa di protokollu da u mudellu OSI nantu à quale corre. U Cloud Balancer opera à u livellu TCP, chì currisponde à a quarta capa, L4.

Passemu à una panoramica di l'architettura di l'equilibriu Cloud. Aumenteremu gradualmente u livellu di dettagliu. Dividemu i cumpunenti di l'equilibriu in trè classi. A classe di u pianu di cunfigurazione hè rispunsevule per l'interazzione di l'utilizatori è guarda u statu di destinazione di u sistema. U pianu di cuntrollu guarda u statu attuale di u sistema è gestisce i sistemi da a classe di u pianu di dati, chì sò direttamente rispunsevuli di furnisce u trafficu da i clienti à i vostri casi.

Pianu di dati

U trafficu finisci nantu à i dispositi caru chjamati routers di cunfini. Per aumentà a tolleranza di difetti, parechji tali dispusitivi operanu simultaneamente in un centru di dati. In seguitu, u trafficu va à i balancers, chì annunzianu l'indirizzi IP anycast à tutti l'AZ via BGP per i clienti. 

Architettura di equilibriu di carica di rete in Yandex.Cloud

U trafficu hè trasmessu nantu à ECMP - questu hè una strategia di routing secondu chì ci ponu esse parechje rotte ugualmente boni à u target (in u nostru casu, u target serà l'indirizzu IP di destinazione) è i pacchetti ponu esse mandati longu à qualsiasi di elli. Supportemu ancu u travagliu in parechje zoni di dispunibilità secondu u schema seguente: publicitemu un indirizzu in ogni zona, u trafficu và à a più vicina è ùn supera micca i so limiti. Più tardi in u post, guardemu in più dettagliu ciò chì succede à u trafficu.

Pianu di cunfigurazione

 
U cumpunente chjave di u pianu di cunfigurazione hè l'API, per mezu di quale l'operazioni basiche cù balancers sò realizati: creazione, eliminazione, cambià a cumpusizioni di istanze, ottene risultati di cuntrolli di salute, etc. altru, noi in u Cloud assai spessu aduprà u framework gRPC, cusì "traducemu" REST à gRPC è dopu aduprà solu gRPC. Ogni dumanda porta à a creazione di una seria di travaglii idempotenti asincroni chì sò eseguiti nantu à una piscina cumuna di i travagliadori Yandex.Cloud. I travaglii sò scritti in tale manera chì ponu esse suspesi in ogni mumentu è poi riavviatu. Questu assicura scalabilità, ripetibilità è logu di operazioni.

Architettura di equilibriu di carica di rete in Yandex.Cloud

In u risultatu, u compitu da l'API farà una dumanda à u cuntrollu di u serviziu di equilibriu, chì hè scrittu in Go. Pò aghjunghje è sguassate balancers, cambià a cumpusizioni di backends è paràmetri. 

Architettura di equilibriu di carica di rete in Yandex.Cloud

U serviziu guarda u so statu in Yandex Database, una basa di dati amministrata distribuita chì puderete prestu aduprà. In Yandex.Cloud, cum'è avemu digià dettu, u cuncettu di l'alimentariu per i cani s'applica: se noi stessi utilizemu i nostri servizii, allora i nostri clienti seranu ancu felici di usà. Yandex Database hè un esempiu di l'implementazione di un tali cuncettu. Guardamu tutti i nostri dati in YDB, è ùn avemu micca bisognu di pensà à mantene è scalate a basa di dati: sti prublemi sò risolti per noi, usemu a basa di dati cum'è serviziu.

Riturnemu à u controller di equilibriu. U so compitu hè di salvà l'infurmazioni nantu à u balancer è mandà un compitu per verificà a prontezza di a macchina virtuale à u cuntrollu di salute.

Controller di salute

Riceve richieste per cambià e regule di cuntrollu, i salva in YDB, distribuisce i travaglii trà i nodi di salute è aggregate i risultati, chì sò poi salvati in a basa di dati è mandati à u controller di loadbalancer. À u turnu, manda una dumanda per cambià a cumpusizioni di u cluster in u pianu di dati à u loadbalancer-node, chì discuteraghju quì sottu.

Architettura di equilibriu di carica di rete in Yandex.Cloud

Parlemu di più nantu à i cuntrolli di salute. Puderanu esse divisu in parechje classi. L'auditi anu criterii di successu differenti. I cuntrolli TCP anu bisognu di stabilisce cun successu una cunnessione in una quantità fissa di tempu. I cuntrolli HTTP necessitanu una cunnessione successu è una risposta cù un codice di statutu 200.

Inoltre, i cuntrolli sò diffirenti in a classa di azzione - sò attivi è passivi. I cuntrolli passivi simpricimenti monitoranu ciò chì succede cù u trafficu senza piglià alcuna azzione speciale. Questu ùn viaghja micca bè in L4 perchè dipende da a logica di i protokolli di livellu più altu: nantu à L4 ùn ci hè micca infurmazione nantu à quantu tempu l'operazione hà pigliatu o s'ellu u cumpletu di a cunnessione era bonu o cattivu. I cuntrolli attivi necessitanu chì l'equilibratore invià e dumande à ogni istanza di u servitore.

A maiò parte di i bilanciatori di carica realizanu stessi cuntrolli di vita. In Cloud, avemu decisu di separà queste parti di u sistema per aumentà a scalabilità. Stu approcciu ci permetterà di aumentà u nùmeru di balancers mentre mantene u numeru di dumande di salute à u serviziu. I cuntrolli sò eseguiti da nodi di cuntrollu di salute separati, attraversu i quali i miri di cuntrollu sò spartiti è replicati. Ùn pudete micca fà cuntrolli da un ospite, perchè pò fallu. Allora ùn averemu micca u statu di i casi chì hà verificatu. Eseguimu cuntrolli nantu à qualsiasi istanze da almenu trè nodi di cuntrollu di salute. Spartitemu i scopi di cuntrolli trà i nodi utilizendu algoritmi di hashing coerenti.

Architettura di equilibriu di carica di rete in Yandex.Cloud

A separazione di l'equilibriu è u cuntrollu di salute pò purtà à prublemi. Se u nodu di cuntrollu di salute fa dumande à l'istanza, sguassendu u balancer (chì ùn hè micca attualmente serve u trafficu), allora una situazione strana si presenta: a risorsa pare esse vivu, ma u trafficu ùn ghjunghje micca. Risolvemu stu prublema in questu modu: simu garantiti per inizià u trafficu di cuntrollu di salute per mezu di balancers. In altri palori, u schema per u muvimentu di pacchetti cù u trafficu da i clienti è da i cuntrolli di salute hè minimamente diversu: in i dui casi, i pacchetti ghjunghjeranu à i equilibratori, chì li daranu à e risorse di destinazione.

A diferenza hè chì i clienti facenu dumande à VIP, mentre chì i cuntrolli di salute facenu dumande à ogni RIP individuale. Un prublema interessante hè quì: demu à i nostri utilizatori l'uppurtunità di creà risorse in rete IP grisa. Imaginemu chì ci sò dui pruprietarii di nuvola diffirenti chì anu ammucciatu i so servizii daretu à i balancers. Ognunu di elli hà risorse in a subnet 10.0.0.1/24, cù i stessi indirizzi. Avete bisognu à esse capace di distinguelli in qualchì manera, è quì avete bisognu à immerse in a struttura di a reta virtuale Yandex.Cloud. Hè megliu truvà più dettagli in video da about:cloud event, hè impurtante per noi avà chì a reta hè multi-layered è hà tunnellati chì ponu esse distinti da l'id di subnet.

I nodi di Healthcheck cuntattanu i equilibratori cù l'indirizzi chjamati quasi-IPv6. Un quasi-indirizzu hè un indirizzu IPv6 cù un indirizzu IPv4 è l'ID di subnet d'utilizatore incrustatu in ellu. U trafficu ghjunghje à u balancer, chì estrae l'indirizzu di risorsa IPv4 da ellu, sustituisci IPv6 cù IPv4 è manda u pacchettu à a reta di l'utilizatori.

U trafficu inversu passa u listessu modu: u balancer vede chì a destinazione hè una reta grisa da i controlli di salute, è cunvertisce IPv4 à IPv6.

VPP - u core di u pianu di dati

L'equilibriu hè implementatu cù a tecnulugia Vector Packet Processing (VPP), un framework da Cisco per u processamentu batch di u trafficu di a rete. In u nostru casu, u quadru travaglia nantu à a libreria di gestione di u dispositivu di a rete di u spaziu di l'utilizatori - Data Plane Development Kit (DPDK). Questu assicura un rendimentu elevatu di trasfurmazioni di pacchetti: assai menu interruzioni si verificanu in u kernel, è ùn ci sò micca cambiamenti di cuntestu trà u spaziu di u kernel è u spaziu di l'utilizatori. 

VPP va ancu più luntanu è sprime ancu più prestazioni fora di u sistema cumminendu pacchetti in batch. I guadagni di rendiment venenu da l'usu aggressivu di cache nantu à i processori muderni. I dui cache di dati sò usati (i pacchetti sò processati in "vettori", a dati hè vicinu à l'altru) è i cache d'istruzzioni: in VPP, u processu di pacchetti segue un graficu, i nodi di quale cuntenenu funzioni chì facenu a listessa attività.

Per esempiu, u processu di pacchetti IP in VPP si trova in l'ordine seguente: prima, l'intestazione di i pacchetti sò analizati in u node di analisi, è dopu sò mandati à u node, chì trasmette i pacchetti in più sicondu i tavule di routing.

Un pocu hardcore. L'autori di VPP ùn tolleranu micca cumprumessi in l'usu di cache di processore, cusì u codice tipicu per processà un vettore di pacchetti cuntene vectorization manual: ci hè un ciclu di trasfurmazioni in quale una situazione cum'è "avemu quattru pacchetti in a fila" hè trattatu, dopu u listessu per dui, dopu - per unu. Istruzzioni di prefetch sò spessu usati per carica dati in cache per accelerà l'accessu à elli in iterazioni successive.

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);
}

Allora, Healthchecks parlanu nantu à IPv6 à u VPP, chì li trasforma in IPv4. Questu hè fattu da un node in u graficu, chì chjamemu NAT algoritmicu. Per u trafficu inversu (è a cunversione da IPv6 à IPv4) ci hè u stessu node NAT algoritmicu.

Architettura di equilibriu di carica di rete in Yandex.Cloud

U trafficu direttu da i clienti di l'equilibriu passa per i nodi di u graficu, chì realizanu l'equilibriu stessu. 

Architettura di equilibriu di carica di rete in Yandex.Cloud

U primu node hè sessione sticky. Conserva l'hash of 5-tupla per e sessioni stabilite. 5-tuple include l'indirizzu è u portu di u cliente da quale l'infurmazione hè trasmessa, l'indirizzu è i porti di risorse dispunibili per riceve u trafficu, è ancu u protocolu di a rete. 

L'hash 5-tuple ci aiuta à fà menu calculu in u nodu di hashing coherente sussegwente, è ancu di gestisce megliu i cambiamenti di lista di risorse daretu à u balancer. Quandu un pacchettu per quale ùn ci hè micca sessione ghjunghje à u balancer, hè mandatu à u nodu di hashing coherente. Hè quì chì l'equilibriu si trova cù l'hashing consistente: selezziunà una risorsa da a lista di risorse "live" dispunibili. In seguitu, i pacchetti sò mandati à u node NAT, chì in realtà rimpiazza l'indirizzu di destinazione è recalculate i checksums. Comu pudete vede, seguimu e regule di VPP - cum'è piace, raggruppendu calculi simili per aumentà l'efficienza di cache di processore.

Hashing coerente

Perchè l'avemu sceltu è chì hè ancu? Prima, cunsideremu u compitu precedente - selezziunate una risorsa da a lista. 

Architettura di equilibriu di carica di rete in Yandex.Cloud

Cù hashing inconsistente, l'hash di u pacchettu entrante hè calculatu, è una risorsa hè sceltu da a lista da u restu di dividendu stu hash per u numeru di risorse. Sempre chì a lista ùn hè micca cambiata, stu schema funziona bè: sempre mandemu pacchetti cù u listessu 5-tuple à a listessa istanza. Se, per esempiu, qualchì risorsa hà cessatu di risponde à i cuntrolli di salute, allora per una parte significativa di i hashes a scelta cambierà. E cunnessioni TCP di u cliente seranu rotte: un pacchettu chì hà righjuntu prima l'istanza A pò cumincià à ghjunghje à l'istanza B, chì ùn hè micca familiarizatu cù a sessione per stu pacchettu.

L'hashing consistente risolve u prublema descrittu. A manera più faciule di spiegà stu cuncettu hè questu: imagine chì avete un anellu à quale distribuisce risorse per hash (per esempiu, per IP:port). Selezziunà una risorsa hè di vultà a rota da un angolo, chì hè determinatu da l'hash di u pacchettu.

Architettura di equilibriu di carica di rete in Yandex.Cloud

Questu minimizza a redistribuzione di u trafficu quandu a cumpusizioni di risorse cambia. L'eliminazione di una risorsa affetterà solu a parte di l'anellu di hashing coherente in quale era situata a risorsa. Aghjunghjendu una risorsa cambia ancu a distribuzione, ma avemu un node di sessione appiccicosa, chì ci permette micca di cambià e sessioni digià stabilite à novi risorse.

Avemu vistu ciò chì succede à u trafficu direttu trà u balancer è e risorse. Avà fighjemu u trafficu di ritornu. Segui u listessu mudellu cum'è u trafficu di cuntrollu - attraversu NAT algoritmicu, vale à dì, attraversu NAT 44 inversu per u trafficu di i clienti è attraversu NAT 46 per u trafficu di cuntrolli di salute. Aderemu à u nostru propiu schema: unificamu u trafficu di cuntrolli di salute è u trafficu di l'utilizatori reale.

Loadbalancer-node è cumpunenti assemblati

A cumpusizioni di balancers è risorse in VPP hè informata da u serviziu locale - loadbalancer-node. Abbonate à u flussu di l'avvenimenti da u loadbalancer-controller è hè capace di tracciare a diffarenza trà u statu VPP attuale è u statu di destinazione ricevutu da u controller. Avemu un sistema chjusu: l'avvenimenti da l'API venenu à u controller di equilibriu, chì assigna compiti à u cuntrollu di salute per verificà a "vivenza" di e risorse. Chì, à u turnu, assigna compiti à u nodu di cuntrollu di salute è aggrega i risultati, dopu chì li manda torna à u controller di equilibriu. Loadbalancer-node abbona à l'avvenimenti da u controller è cambia u statu di u VPP. In un tali sistema, ogni serviziu cunnosce solu ciò chì hè necessariu di i servizii vicini. U numaru di cunnessione hè limitatu è avemu a capacità di operà è scala diversi segmenti indipindente.

Architettura di equilibriu di carica di rete in Yandex.Cloud

Chì prublemi sò stati evitati?

Tutti i nostri servizii in u pianu di cuntrollu sò scritti in Go è anu boni caratteristiche di scala è affidabilità. Go hà parechje biblioteche open source per custruisce sistemi distribuiti. Utilizemu attivamente GRPC, tutti i cumpunenti cuntenenu una implementazione open source di scuperta di serviziu - i nostri servizii monitoranu a prestazione di l'altri, ponu cambià a so cumpusizioni dinamicamente, è avemu ligatu questu cù l'equilibriu GRPC. Per i metrici, avemu ancu aduprà una soluzione open source. In u pianu di dati, avemu avutu un rendimentu decentu è una grande riserva di risorse: hè diventatu assai difficiuli di assemblà un stand nantu à quale pudemu cunfidà nantu à a prestazione di un VPP, invece di una carta di rete di ferru.

Problemi è suluzione

Chì ùn hà micca travagliatu cusì bè ? Go hà una gestione automatica di a memoria, ma i fughe di memoria sò sempre accadute. A manera più faciule di trattà cun elli hè di eseguisce goroutines è ricurdate di finisce. Takeaway: Fighjate u cunsumu di memoria di i vostri prugrammi Go. Spessu un bon indicatore hè u numeru di goroutines. Ci hè un plus in questa storia: in Go hè faciule d'ottene dati di runtime - cunsumu di memoria, u numeru di goroutines in esecuzione, è parechji altri parametri.

Inoltre, Go pò esse micca a megliu scelta per i testi funziunali. Sò abbastanza verbose, è l'approcciu standard di "eseguisce tuttu in CI in un batch" ùn hè micca assai adattatu per elli. U fattu hè chì e teste funziunali sò più esigenti di risorse è causanu timeouts reale. Per via di questu, i testi puderanu falla perchè u CPU hè occupatu cù teste di unità. Conclusioni: Sè pussibule, eseguite teste "pesanti" separatamente da e teste unità. 

L'architettura di l'avvenimentu di u microserviziu hè più cumplessa chè un monolitu: a cullizzioni di logs nantu à decine di macchine diverse ùn hè micca assai còmuda. Conclusioni: se fate microservizi, pensate immediatamente à a traccia.

I nostri piani

Lanceremu un equilibratore internu, un equilibratore IPv6, aghjunghje supportu per i script Kubernetes, cuntinueremu à sparghje i nostri servizii (attualmente solu healthcheck-node è healthcheck-ctrl sò sharded), aghjunghjenu novi cuntrolli di salute, è ancu implementà aggregazione intelligente di cuntrolli. Avemu cunsiderà a pussibilità di rende i nostri servizii ancu più indipendenti - per ch'elli cumunicanu micca direttamente cù l'altri, ma cù una fila di messagi. Un serviziu compatibile cù SQS hè apparsu recentemente in u Cloud Coda di missaghji Yandex.

Ricertamenti, a liberazione publica di Yandex Load Balancer hè stata fatta. Esplora documentazione à u serviziu, gestisce i balancers in una manera cunvene per voi è aumentate a tolleranza à i difetti di i vostri prughjetti!

Source: www.habr.com

Add a comment