Hallo, ek is Sergey Elantsev, ek ontwikkel
Kom ons stel eers 'n paar terme voor:
- VIP (Virtuele IP) - IP-adres van die balanseerder
- Bediener, backend, instansie - 'n virtuele masjien met 'n lopende toepassing
- RIP (Real IP) - bediener IP-adres
- Healthcheck - bedienergereedheidskontrole
- Beskikbaarheidsone, AZ - geïsoleerde infrastruktuur in die datasentrum
- Streek - 'n samesmelting van verskillende AZ'e
Lasbalanseerders los drie hooftake op: hulle voer die balansering self uit, verbeter die fouttoleransie van die diens en vereenvoudig die skaal daarvan. Foutverdraagsaamheid word verseker deur outomatiese verkeersbestuur: die balanseerder monitor die toestand van die toepassing en sluit gevalle van balansering uit wat nie die lewendheidstoets geslaag het nie. Skaal word verskaf deur eenvormige vragverspreiding oor gevalle, sowel as die opdatering van die lys van gevalle op die vlieg. As die balansering nie eens genoeg is nie, sal sommige van die gevalle bo hul gesondheidsperk gelaai word en die diens sal minder betroubaar word.
'n Lasbalanseerder word dikwels geklassifiseer deur die protokollaag van die OSI-model waarop dit loop. Die Cloud Balancer werk by die TCP-laag, wat ooreenstem met die vierde laag, L4.
Kom ons gaan aan na 'n oorsig van die argitektuur van die Wolkbalanseerder. Ons sal die vlak van detail geleidelik verhoog. Ons verdeel die balanseerderkomponente in drie klasse. Die konfigurasievlakklas is verantwoordelik vir gebruikersinteraksie en stoor die teikentoestand van die stelsel. Die beheervlak stoor die huidige toestand van die stelsel en bestuur stelsels vanaf die datavlakklas, wat direk verantwoordelik is vir die lewering van verkeer van kliënte na jou gevalle.
datavlak
Verkeer gaan na duur toestelle wat grensrouters genoem word. Om fouttoleransie in een datasentrum te verhoog, werk verskeie sulke toestelle gelyktydig. Dan kom die verkeer na balanseerders, wat enige uitsaai-IP-adres aan alle AZ'e aankondig via BGP vir kliënte.
Verkeer word oor ECMP versend - dit is 'n roetestrategie, waarvolgens daar verskeie ewe goeie roetes na die teiken kan wees (in ons geval sal die bestemmings-IP-adres die teiken wees) en pakkies kan deur enige van hulle gestuur word. Ons ondersteun ook werk in verskeie beskikbaarheidsones volgens die volgende skema: ons kondig die adres in elk van die sones aan, die verkeer gaan die naaste een binne en gaan nie verder as dit nie. Verder in die pos gaan ons van nader kyk na wat met verkeer gebeur.
konfigurasie-vliegtuig
Die sleutelkomponent van die konfigurasievlak is die API, waardeur die hoofbewerkings met balanseerders uitgevoer word: skep, verwydering, verandering van die samestelling van gevalle, verkryging van die resultate van gesondheidsondersoeke, ens. Aan die een kant is dit 'n REST API, en aan die ander kant gebruik ons baie dikwels die raamwerk in die Wolk gRPC, so ons "vertaal" REST na gRPC en gaan voort om net gRPC te gebruik. Enige versoek lei tot die skepping van 'n reeks asynchrone idempotente take wat op die gemeenskaplike poel van Yandex.Cloud-werkers loop. Take is so geskryf dat dit enige tyd opgeskort en dan weer begin kan word. Dit verseker skaalbaarheid, herhaalbaarheid en aantekening van bedrywighede.
As gevolg hiervan sal die taak van die API 'n versoek aan die diensbeheerder van die balanseerders rig, wat in Go geskryf is. Hy kan balanseerders byvoeg en verwyder, die samestelling van backends en instellings verander.
Die diens stoor sy toestand in Yandex-databasis, 'n verspreide bestuurde databasis wat u binnekort sal kan gebruik. In Yandex.Cloud, soos ons reeds
Ons keer terug na die balanseerder kontroleerder. Die taak daarvan is om inligting oor die balanseerder te stoor, die taak om die gereedheid van die virtuele masjien na te gaan, na die gesondheidskontroleerder te stuur.
Gesondheidskontroleerder
Dit ontvang versoeke om die kontrolereëls te verander, stoor dit na YDB, versprei take onder genesingstoets-nodusse en versamel die resultate, wat dan na die databasis gestoor en na die loadbalancer-beheerder gestuur word. Hy stuur op sy beurt 'n versoek om die samestelling van die groepering in die datavlak te verander na die loadbalancer-node, wat ek hieronder sal bespreek.
Kom ons praat meer oor gesondheidsondersoeke. Hulle kan in verskeie klasse verdeel word. Toetse het verskillende sukseskriteria. TCP-tjeks moet binne 'n vasgestelde tyd 'n verbinding suksesvol tot stand bring. HTTP-kontroles vereis beide 'n suksesvolle verbinding en 'n antwoord met 'n 200-statuskode.
Tjeks verskil ook in die klas van aksie - hulle is aktief en passief. Passiewe kontrole kyk eenvoudig wat met die verkeer gebeur sonder om enige spesiale stappe te doen. Dit werk nie baie goed op L4 nie, want dit hang af van die logika van die hoërlaagprotokolle: op L4 is daar geen inligting oor hoe lank die operasie geneem het en of die beëindiging van die verbinding goed of sleg was nie. Aktiewe tjeks vereis dat die balanseerder versoeke na elke bedienergeval stuur.
Die meeste lasbalanseerders doen self lewendheidskontroles. Ons by die Wolk het besluit om hierdie dele van die stelsel te skei om skaalbaarheid te verbeter. Hierdie benadering sal ons in staat stel om die aantal balanseerders te vermeerder, terwyl die aantal gesondheidskontrole-versoeke aan die diens gehandhaaf word. Kontroles word uitgevoer deur afsonderlike gesondheidsondersoeknodusse, waaroor kontrole-teikens verdeel en herhaal word. U kan nie kontroles vanaf een gasheer doen nie, aangesien dit kan misluk. Dan kry ons nie die toestand van die gevalle wat hy nagegaan het nie. Ons doen kontrole op enige van die gevalle vanaf ten minste drie gesondheidsondersoek-nodusse. Ons verdeel teikens tussen nodusse deur konsekwente hashing-algoritmes te gebruik.
Skei balansering en gesondheidsondersoek kan tot probleme lei. As die gesondheidstoets-nodus versoeke aan die instansie rig en die balanseerder (wat tans nie verkeer bedien nie) omseil, dan ontstaan 'n vreemde situasie: dit lyk of die hulpbron lewendig is, maar die verkeer sal dit nie bereik nie. Ons los hierdie probleem op die volgende manier op: ons is gewaarborg om gesondheidskontrole-verkeer deur balanseerders te begin. Met ander woorde, die skema vir die verskuiwing van pakkies met verkeer van kliënte en van gesondheidsondersoeke verskil minimaal: in beide gevalle sal die pakkies by die balanseerders uitkom, wat hulle aan die teikenhulpbronne sal lewer.
Die verskil is dat kliënte versoeke vir BBP's rig, terwyl gesondheidsondersoeke na elke individuele RIP gaan. Hier ontstaan 'n interessante probleem: ons gee ons gebruikers die vermoë om hulpbronne in grys IP-netwerke te skep. Stel jou voor dat daar twee verskillende wolkeienaars is wat hul dienste agter balanseerders versteek het. Elkeen van hulle het hulpbronne op die 10.0.0.1/24 subnet, en met dieselfde adresse. Jy moet hulle op een of ander manier kan onderskei, en hier moet jy in die Yandex.Cloud virtuele netwerktoestel duik. Meer besonderhede kan gevind word in
Healthcheck nodusse het toegang tot balanseerders met behulp van sogenaamde kwasi-IPv6-adresse. 'n Kwasi-adres is 'n IPv6-adres wat die gebruiker se IPv4-adres en subnet-ID binne-in het. Die verkeer kom na die balanseerder, wat die hulpbron se IPv4-adres daaruit onttrek, IPv6 met IPv4 vervang en die pakkie na die gebruiker se netwerk stuur.
Omgekeerde verkeer is dieselfde: die balanseerder sien dat die bestemming 'n grys netwerk van gesondheidkontroleurs is, en skakel IPv4 om na IPv6.
VPP is die hart van die datavlak
Die lasbalanseerder word geïmplementeer op die Vector Packet Processing (VPP) tegnologie, 'n Cisco-raamwerk vir pakketverwerking van netwerkverkeer. In ons geval werk die raamwerk bo-op die gebruiker-ruimte netwerk toestel bestuur biblioteek - Data Plane Development Kit (DPDK). Dit bied hoë pakketverwerkingsprestasie: daar is baie minder onderbrekings in die kern, daar is geen kontekswisselaars tussen kernspasie en gebruikersruimte nie.
VPP gaan selfs verder en druk nog meer werkverrigting uit die stelsel deur pakkies in bondels te kombineer. Prestasiewinste kom uit die aggressiewe gebruik van moderne verwerkerkas. Beide datakas word gebruik (pakkies word deur "vektore" verwerk, die data is naby aan mekaar), en instruksiekas: in VPP volg pakkieverwerking 'n grafiek, in die nodusse waarvan daar funksies is wat een taak verrig.
Die verwerking van IP-pakkies in VPP vind byvoorbeeld in die volgende volgorde plaas: eerstens word die pakkieopskrifte in die ontledingsnodus ontleed, en dan word dit na die nodus gestuur, wat die pakkies verder aanstuur volgens die roeteringstabelle.
Bietjie hardcore. VPP-outeurs kompromitteer nie die gebruik van verwerkerkas, so tipiese pakketvektorverwerkingskode bevat handvektorisering: daar is 'n verwerkingslus wat die situasie verwerk soos "ons het vier pakkies in die tou", dan - dieselfde vir twee, dan - vir een. Voorafhaal-instruksies word dikwels gebruik om data in kas te laai om toegang daartoe in die volgende herhalings te bespoedig.
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);
}
Dus, Healthchecks kry toegang tot VPP oor IPv6, wat hulle in IPv4 verander. Dit word gedoen deur die knooppunt van die grafiek, wat ons algoritmiese NAT noem. Vir omgekeerde verkeer (en vertaling van IPv6 na IPv4) is daar dieselfde algoritmiese NAT-nodus.
Direkte verkeer van die balanseerder se kliënte gaan deur die nodusse van die grafiek, wat self die balansering uitvoer.
Die eerste nodus is taai sessies. Dit bevat 'n hash van
Die 5-tuple hash help ons om minder berekeninge te doen in die daaropvolgende konsekwente hash node, en ook beter te hanteer hulpbronlys veranderinge agter die balancer. Wanneer 'n pakkie by die balanseerder aankom waarvoor daar geen sessie is nie, word dit na die konsekwente hashing-nodus gestuur. Dit is waar balansering plaasvind deur konsekwente hashing te gebruik: ons kies 'n hulpbron uit die lys van beskikbare "lewendige" hulpbronne. Vervolgens word die pakkies na die NAT-nodus gestuur, wat eintlik die bestemmingsadres vervang en die kontrolesomme herbereken. Soos u kan sien, volg ons die reëls van VPP - hou daarvan, groepeer soortgelyke berekeninge om die doeltreffendheid van verwerkerkas te verhoog.
Konsekwente hashing
Hoekom het ons dit gekies en waaroor gaan dit? Om mee te begin, oorweeg die vorige taak - kies 'n hulpbron uit die lys.
Met inkonsekwente hash word 'n hash uit die inkomende pakkie bereken, en die hulpbron word uit die lys gekies deur die res van hierdie hash te deel deur die aantal hulpbronne. Solank die lys onveranderd bly, werk hierdie skema goed: ons stuur altyd pakkies met dieselfde 5-tuple na dieselfde instansie. As een of ander hulpbron byvoorbeeld opgehou het om op gesondheidsondersoeke te reageer, sal die keuse vir 'n beduidende deel van die hashes verander. Die kliënt sal TCP-verbindings verloor: 'n pakkie wat voorheen instansie A getref het, kan instansie B begin tref, wat nie vertroud is met die sessie vir hierdie pakkie nie.
Konsekwente hashing los die beskryf probleem op. Die maklikste manier om hierdie konsep te verduidelik, is soos volg: stel jou voor dat jy 'n ring het waarheen jy hulpbronne deur hash versprei (byvoorbeeld deur IP:poort). Die keuse van hulpbron is die rotasie van die wiel met 'n hoek, wat bepaal word deur die hash uit die pakket.
Dit verminder die herverdeling van verkeer wanneer die samestelling van hulpbronne verander word. Die verwydering van 'n hulpbron sal slegs die deel van die konsekwente hash-ring beïnvloed waarop die hulpbron was. Die byvoeging van 'n hulpbron verander ook die verspreiding, maar ons het 'n taai sessienodus wat ons toelaat om nie reeds gevestigde sessies na nuwe hulpbronne oor te skakel nie.
Ons het gekyk na wat gebeur met direkte verkeer tussen die balanseerder en hulpbronne. Kom ons gaan nou met retoerverkeer. Dit volg dieselfde patroon as kontroleverkeer - deur algoritmiese NAT, dit wil sê deur omgekeerde NAT 44 vir kliëntverkeer en deur NAT 46 vir gesondheidskontrole-verkeer. Ons hou by ons eie skema: ons verenig gesondheidskontrole-verkeer en werklike gebruikersverkeer.
Loadbalancer-node en saamgestelde komponente
Die samestelling van balanseerders en hulpbronne in VPP word gerapporteer deur die plaaslike diens - loadbalancer-node. Dit teken in op die gebeurtenisstroom vanaf die loadbalancer-beheerder, kan die verskil bou tussen die huidige VPP-toestand en die teikentoestand wat van die kontroleerder ontvang word. Ons kry 'n geslote stelsel: gebeure van die API kom na die balanseerderbeheerder, wat die take vir die gesondheidkontrole-kontroleerder stel om die "lewendheid" van hulpbronne na te gaan. Dit plaas op sy beurt take in die gesondheidkontrole-node en versamel die resultate, waarna dit aan die balanseerder-beheerder teruggee. Loadbalancer-node teken in op gebeure van die kontroleerder en verander die toestand van die VPP. In so 'n stelsel weet elke diens net wat hy van naburige dienste moet weet. Die aantal verbindings is beperk en ons het die vermoë om verskillende segmente onafhanklik te bedryf en te skaal.
Watter probleme is vermy?
Al ons beheervliegtuigdienste is in Go geskryf en het goeie skaalbaarheid en betroubaarheid. Go het baie oopbronbiblioteke vir die bou van verspreide stelsels. Ons gebruik GRPC aktief, alle komponente bevat 'n oopbron-implementering van diensontdekking - ons dienste monitor mekaar se prestasie, kan hul samestelling dinamies verander, en ons het dit met GRPC-balansering verbind. Vir metrieke gebruik ons ook 'n oopbron-oplossing. In die datavlak het ons ordentlike werkverrigting en 'n groot marge hulpbronne gekry: dit blyk baie moeilik te wees om 'n staander saam te stel waarop ons kan rus teen die prestasie van VPP, en nie 'n ysternetwerkkaart nie.
Probleme en oplossings
Wat het nie goed gewerk nie? Go het outomatiese geheuebestuur, maar geheuelekkasies vind wel plaas. Die maklikste manier om dit te hanteer, is om goroutines te hardloop en te onthou om hulle te beëindig. Gevolgtrekking: Kyk na die geheueverbruik van Go-programme. Dikwels is 'n goeie aanwyser die aantal goroutines. Daar is 'n pluspunt in hierdie storie: in Go is dit maklik om data oor looptyd te kry - oor geheueverbruik, oor die aantal lopende goroutines en oor baie ander parameters.
Go is ook dalk nie die beste keuse vir funksionele toetse nie. Hulle is nogal verbose, en die standaard "hardloop alles in CI in bondel" benadering is nie baie geskik vir hulle nie. Die feit is dat funksionele toetse meer veeleisend is op hulpbronne, en werklike time-outs kom daarmee voor. As gevolg hiervan kan toetse misluk omdat die SVE besig is met eenheidstoetse. Gevolgtrekking: voer "swaar" toetse afsonderlik van eenheidstoetse uit, waar moontlik.
'n Mikrodiensgebeurtenisargitektuur is meer ingewikkeld as 'n monoliet: dit is nie baie gerieflik om logs op dosyne verskillende masjiene te gryp nie. Gevolgtrekking: as jy mikrodienste doen, dink dadelik aan opsporing.
Ons planne
Ons sal 'n interne balanseerder, 'n IPv6-balanseerder bekendstel, ondersteuning vir Kubernetes-scenario's byvoeg, voortgaan om ons dienste te versnipper (tans word slegs healthcheck-node en healthcheck-ctrl versplinter), nuwe gesondheidskontroles byvoeg en slimkontrole-aggregasie implementeer. Ons oorweeg die moontlikheid om ons dienste nog meer onafhanklik te maak – sodat hulle nie direk met mekaar kommunikeer nie, maar deur 'n boodskap-tou te gebruik. The Cloud het onlangs 'n SQS-versoenbare diens bekendgestel
Onlangs het die publieke vrystelling van Yandex Load Balancer plaasgevind. Leer
Bron: will.com