Hola, sò Sergey Elantsev, aghju sviluppatu
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.
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.
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.
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à
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.
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.
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
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.
U trafficu direttu da i clienti di l'equilibriu passa per i nodi di u graficu, chì realizanu l'equilibriu stessu.
U primu node hè sessione sticky. Conserva l'hash of
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.
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.
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.
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
Ricertamenti, a liberazione publica di Yandex Load Balancer hè stata fatta. Esplora
Source: www.habr.com