Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu
Ta članek vam bo pomagal razumeti, kako deluje uravnoteženje obremenitve v Kubernetesu, kaj se zgodi pri skaliranju dolgoživih povezav in zakaj bi morali razmisliti o uravnoteženju na strani odjemalca, če uporabljate HTTP/2, gRPC, RSockets, AMQP ali druge dolgožive protokole . 

Malo o tem, kako se promet prerazporeja v Kubernetesu 

Kubernetes ponuja dve priročni abstrakciji za uvajanje aplikacij: storitve in uvedbe.

Razmestitve opisujejo, kako in koliko kopij vaše aplikacije naj se izvaja v danem trenutku. Vsaka aplikacija je nameščena kot Pod in ji je dodeljen naslov IP.

Storitve so po funkciji podobne izenačevalniku obremenitve. Zasnovani so za porazdelitev prometa med več sklopi.

Poglejmo, kako izgleda.

  1. V spodnjem diagramu lahko vidite tri primerke iste aplikacije in izravnalnika obremenitve:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  2. Izravnalnik obremenitve se imenuje storitev in mu je dodeljen naslov IP. Vsaka dohodna zahteva je preusmerjena na enega od sklopov:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  3. Scenarij razmestitve določa število primerkov aplikacije. Skoraj nikoli vam ne bo treba razširiti neposredno pod:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  4. Vsakemu modulu je dodeljen svoj naslov IP:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Storitve je koristno zamisliti kot zbirko naslovov IP. Vsakič, ko dostopate do storitve, je eden od naslovov IP izbran s seznama in uporabljen kot ciljni naslov.

Izgleda takole.

  1. Storitvi je prejeta zahteva curl 10.96.45.152:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  2. Storitev kot cilj izbere enega od treh pod naslovov:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  3. Promet je preusmerjen na določen pod:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Če je vaša aplikacija sestavljena iz frontenda in backenda, potem boste imeli tako storitev kot uvajanje za vsako.

Ko čelni del pošlje zahtevo zaledju, mu ni treba natančno vedeti, koliko podov služi zaledju: lahko je eden, deset ali sto.

Prav tako sprednji del ne ve ničesar o naslovih podov, ki služijo zadnjemu delu.

Ko sprednji del pošlje zahtevo zalednemu delu, uporabi naslov IP zaledne storitve, ki se ne spremeni.

Tukaj je, kako to izgleda.

  1. Pod 1 zahteva notranjo zaledno komponento. Namesto da izbere določeno za zaledje, pošlje zahtevo storitvi:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  2. Storitev izbere enega od zalednih sklopov kot ciljni naslov:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  3. Promet poteka od Poda 1 do Poda 5 po izboru servisa:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  4. Pod 1 ne ve natančno, koliko podov kot pod 5 se skriva za storitvijo:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Toda kako točno storitev razdeli zahteve? Zdi se, kot da se uporablja krožno uravnoteženje? Ugotovimo. 

Uravnoteženje v storitvah Kubernetes

Storitve Kubernetes ne obstajajo. Za storitev, ki ji je dodeljen naslov IP in vrata, ni postopka.

To lahko preverite tako, da se prijavite v katero koli vozlišče v gruči in zaženete ukaz netstat -ntlp.

Ne boste mogli niti najti naslova IP, dodeljenega storitvi.

IP naslov storitve se nahaja v nadzorni plasti, v krmilniku, in zapisan v bazi podatkov - itd. Isti naslov uporablja druga komponenta - kube-proxy.
Kube-proxy prejme seznam naslovov IP za vse storitve in ustvari nabor pravil iptables na vsakem vozlišču v gruči.

Ta pravila pravijo: "Če vidimo naslov IP storitve, moramo spremeniti ciljni naslov zahteve in ga poslati enemu od podov."

IP naslov storitve se uporablja samo kot vstopna točka in ga ne streže noben proces, ki posluša ta naslov IP in vrata.

Poglejmo si to

  1. Razmislite o skupini treh vozlišč. Vsako vozlišče ima sklope:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  2. Vezani stroki, pobarvani v bež barvi, so del servisa. Ker storitev ne obstaja kot proces, je prikazana sivo:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  3. Prvi sklop zahteva storitev in mora iti na enega od povezanih sklopov:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  4. Toda storitev ne obstaja, proces ne obstaja. Kako deluje?

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  5. Preden zahteva zapusti vozlišče, gre skozi pravila iptables:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  6. Pravila iptables vedo, da storitev ne obstaja, in zamenjajo njen naslov IP z enim od naslovov IP podov, povezanih s to storitvijo:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  7. Zahteva prejme veljaven naslov IP kot ciljni naslov in je normalno obdelana:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  8. Odvisno od topologije omrežja zahteva na koncu doseže pod:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Ali lahko iptables uravnava obremenitev?

Ne, iptables se uporabljajo za filtriranje in niso bili zasnovani za uravnoteženje.

Vendar pa je mogoče napisati nabor pravil, ki delujejo kot psevdo-balanser.

In točno to je implementirano v Kubernetesu.

Če imate tri pode, bo kube-proxy napisal naslednja pravila:

  1. Izberite prvi pod z verjetnostjo 33%, sicer pojdite na naslednje pravilo.
  2. Izberite drugo z verjetnostjo 50%, sicer pojdite na naslednje pravilo.
  3. Izberite tretje pod.

Posledica tega sistema je, da je vsak sklop izbran z verjetnostjo 33 %.

Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

In ni nobenega zagotovila, da bo Pod 2 izbran naslednji za Pod 1.

Obvestilo: iptables uporablja statistični modul z naključno porazdelitvijo. Tako algoritem uravnoteženja temelji na naključni izbiri.

Zdaj, ko razumete, kako storitve delujejo, si poglejmo bolj zanimive scenarije storitev.

Dolgotrajne povezave v Kubernetesu se privzeto ne prilagajajo

Vsako zahtevo HTTP od frontenda do backenda streže ločena povezava TCP, ki se odpre in zapre.

Če frontend pošlje 100 zahtev na sekundo v backend, se odpre in zapre 100 različnih povezav TCP.

Čas obdelave zahteve in obremenitev lahko skrajšate tako, da odprete eno povezavo TCP in jo uporabite za vse nadaljnje zahteve HTTP.

Protokol HTTP ima funkcijo, ki se imenuje HTTP keep-alive ali ponovna uporaba povezave. V tem primeru se ena povezava TCP uporablja za pošiljanje in prejemanje več zahtev in odgovorov HTTP:

Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Ta funkcija privzeto ni omogočena: strežnik in odjemalec morata biti ustrezno konfigurirana.

Sama nastavitev je preprosta in dostopna za večino programskih jezikov in okolij.

Tukaj je nekaj povezav do primerov v različnih jezikih:

Kaj se zgodi, če uporabimo keep-alive v storitvi Kubernetes?
Predpostavimo, da tako frontend kot backend podpirata ohranjanje pri življenju.

Imamo eno kopijo frontenda in tri kopije backenda. Sprednji del naredi prvo zahtevo in odpre povezavo TCP z zaledjem. Zahteva doseže storitev, eden od zalednih sklopov je izbran kot ciljni naslov. Zaledje pošlje odgovor, sprednji del pa ga prejme.

Za razliko od običajne situacije, ko se povezava TCP po prejemu odgovora zapre, je zdaj odprta za nadaljnje zahteve HTTP.

Kaj se zgodi, če sprednji del pošlje več zahtev zaledju?

Za posredovanje teh zahtev bo uporabljena odprta povezava TCP, vse zahteve bodo šle v isto zaledje, kamor je šla prva zahteva.

Ali ne bi moral iptables prerazporediti prometa?

V tem primeru ne.

Ko je povezava TCP ustvarjena, gre skozi pravila iptables, ki izberejo določeno zaledje, kamor bo šel promet.

Ker so vse naslednje zahteve na že odprti povezavi TCP, se pravila iptables ne kličejo več.

Poglejmo, kako izgleda.

  1. Prvi pod pošlje zahtevo storitvi:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  2. Že veste, kaj bo sledilo. Storitev ne obstaja, vendar obstajajo pravila iptables, ki bodo obdelala zahtevo:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  3. Eden od zalednih sklopov bo izbran kot ciljni naslov:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  4. Zahteva doseže pod. Na tej točki bo vzpostavljena trajna povezava TCP med obema podoma:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  5. Vsaka naslednja zahteva iz prvega sklopa bo šla skozi že vzpostavljeno povezavo:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Rezultat je hitrejši odzivni čas in večja prepustnost, vendar izgubite možnost prilagajanja zaledja.

Tudi če imate v ozadju dva sklopa, bo promet vedno šel k enemu od njih s stalno povezavo.

Ali je to mogoče popraviti?

Ker Kubernetes ne ve, kako uravnotežiti trajne povezave, to nalogo prevzamete vi.

Storitve so zbirka naslovov IP in vrat, imenovanih končne točke.

Vaša aplikacija lahko od storitve pridobi seznam končnih točk in se odloči, kako porazdeliti zahteve med njimi. Z vsakim podom lahko odprete trajno povezavo in uravnotežite zahteve med temi povezavami z uporabo krožnega dela.

Ali uporabite več zapleteni algoritmi za uravnoteženje.

Koda na strani odjemalca, ki je odgovorna za uravnoteženje, mora slediti tej logiki:

  1. Pridobite seznam končnih točk od storitve.
  2. Odprite trajno povezavo za vsako končno točko.
  3. Ko je treba narediti zahtevo, uporabite eno od odprtih povezav.
  4. Redno posodabljajte seznam končnih točk, ustvarite nove ali zaprite stare trajne povezave, če se seznam spremeni.

Tako bo izgledalo.

  1. Namesto, da prvi sklop pošlje zahtevo storitvi, lahko izravnate zahteve na strani odjemalca:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  2. Napisati morate kodo, ki sprašuje, kateri podi so del storitve:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  3. Ko imate seznam, ga shranite na strani odjemalca in ga uporabite za povezavo s sklopi:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

  4. Odgovorni ste za algoritem za uravnoteženje obremenitve:

    Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Zdaj se postavlja vprašanje: ali se ta težava nanaša samo na vzdrževanje HTTP?

Izravnavanje obremenitve na strani odjemalca

HTTP ni edini protokol, ki lahko uporablja obstojne povezave TCP.

Če vaša aplikacija uporablja bazo podatkov, se povezava TCP ne odpre vsakič, ko morate narediti zahtevo ali pridobiti dokument iz baze podatkov. 

Namesto tega se odpre in uporabi obstojna povezava TCP z bazo podatkov.

Če je vaša baza podatkov razporejena v Kubernetes in je dostop zagotovljen kot storitev, boste naleteli na enake težave, kot so opisane v prejšnjem razdelku.

Ena replika baze podatkov bo bolj obremenjena kot druge. Kube-proxy in Kubernetes ne bosta pomagala pri uravnoteženju povezav. Poskrbeti morate za uravnoteženje poizvedb v vaši bazi podatkov.

Odvisno od knjižnice, ki jo uporabljate za povezavo z bazo podatkov, imate morda različne možnosti za rešitev te težave.

Spodaj je primer dostopa do gruče baze podatkov MySQL iz Node.js:

var mysql = require('mysql');
var poolCluster = mysql.createPoolCluster();

var endpoints = /* retrieve endpoints from the Service */

for (var [index, endpoint] of endpoints) {
  poolCluster.add(`mysql-replica-${index}`, endpoint);
}

// Make queries to the clustered MySQL database

Obstaja veliko drugih protokolov, ki uporabljajo trajne povezave TCP:

  • WebSockets in zavarovane WebSockets
  • HTTP / 2
  • gRPC
  • RSockets
  • AMQP

Večino teh protokolov bi morali že poznati.

Če pa so ti protokoli tako priljubljeni, zakaj ne obstaja standardizirana rešitev za uravnoteženje? Zakaj se mora logika stranke spremeniti? Ali obstaja izvorna rešitev Kubernetes?

Kube-proxy in iptables sta zasnovana tako, da pokrivata najpogostejše primere uporabe pri uvajanju v Kubernetes. To je zaradi udobja.

Če uporabljate spletno storitev, ki izpostavlja API REST, imate srečo – v tem primeru se trajne povezave TCP ne uporabljajo, lahko uporabite katero koli storitev Kubernetes.

Ko pa začnete uporabljati obstojne povezave TCP, boste morali ugotoviti, kako enakomerno porazdeliti obremenitev po zaledjih. Kubernetes ne vsebuje pripravljenih rešitev za ta primer.

Vsekakor pa obstajajo možnosti, ki lahko pomagajo.

Uravnoteženje dolgotrajnih povezav v Kubernetesu

V Kubernetesu obstajajo štiri vrste storitev:

  1. GrozdIP
  2. Node Port
  3. LoadBalancer
  4. Brez glave

Prve tri storitve delujejo na podlagi navideznega naslova IP, ki ga kube-proxy uporablja za izdelavo pravil iptables. Toda temeljna osnova vseh storitev je brezglava storitev.

Storitev brez glave nima povezanega naslova IP in zagotavlja samo mehanizem za pridobivanje seznama naslovov IP in vrat podov (končnih točk), povezanih z njo.

Vse storitve temeljijo na brezglavi storitvi.

Storitev ClusterIP je brezglava storitev z nekaj dodatki: 

  1. Upravljalni sloj mu dodeli naslov IP.
  2. Kube-proxy ustvari potrebna pravila iptables.

Na ta način lahko prezrete kube-proxy in neposredno uporabite seznam končnih točk, pridobljen iz storitve brez glave, za uravnoteženje obremenitve vaše aplikacije.

Toda kako lahko dodamo podobno logiko vsem aplikacijam, nameščenim v gruči?

Če je vaša aplikacija že nameščena, se ta naloga morda zdi nemogoča. Vendar pa obstaja alternativna možnost.

Service Mesh vam bo pomagal

Verjetno ste že opazili, da je strategija uravnoteženja obremenitve na strani odjemalca precej standardna.

Ko se aplikacija zažene, se:

  1. Od storitve pridobi seznam naslovov IP.
  2. Odpre in vzdržuje polje povezav.
  3. Občasno posodobi bazen z dodajanjem ali odstranjevanjem končnih točk.

Ko aplikacija želi narediti zahtevo,:

  1. Izbere razpoložljivo povezavo z določeno logiko (npr. krožno).
  2. Izvrši zahtevo.

Ti koraki delujejo za povezave WebSockets, gRPC in AMQP.

To logiko lahko ločite v ločeno knjižnico in jo uporabite v svojih aplikacijah.

Vendar pa lahko namesto tega uporabite storitvene mreže, kot sta Istio ali Linkerd.

Service Mesh dopolnjuje vašo aplikacijo s postopkom, ki:

  1. Samodejno išče naslove IP storitev.
  2. Preizkuša povezave, kot sta WebSockets in gRPC.
  3. Uravnava zahteve z uporabo pravilnega protokola.

Storitev Mesh pomaga upravljati promet znotraj gruče, vendar je precej intenzivna. Druge možnosti so uporaba knjižnic tretjih oseb, kot je Netflix Ribbon, ali programabilnih posrednikov, kot je Envoy.

Kaj se zgodi, če ignorirate težave z uravnoteženjem?

Lahko se odločite, da ne boste uporabljali uravnoteženja obremenitve, pa še vedno ne boste opazili nobenih sprememb. Poglejmo si nekaj scenarijev dela.

Če imate več odjemalcev kot strežnikov, to ni tako velik problem.

Recimo, da obstaja pet odjemalcev, ki se povežejo z dvema strežnikoma. Tudi če ni izravnave, bosta uporabljena oba strežnika:

Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Povezave morda niso enakomerno porazdeljene: morda so štirje odjemalci povezani na isti strežnik, vendar obstaja velika verjetnost, da bosta uporabljena oba strežnika.

Bolj problematičen je nasprotni scenarij.

Če imate manj odjemalcev in več strežnikov, bodo vaši viri morda premalo izkoriščeni in pojavilo se bo potencialno ozko grlo.

Recimo, da sta dva odjemalca in pet strežnikov. V najboljšem primeru bosta dve stalni povezavi na dva strežnika od petih.

Preostali strežniki bodo mirovali:

Uravnoteženje obremenitve in skaliranje dolgotrajnih povezav v Kubernetesu

Če ta dva strežnika ne moreta obravnavati zahtev odjemalcev, horizontalno skaliranje ne bo pomagalo.

Zaključek

Storitve Kubernetes so zasnovane tako, da delujejo v večini standardnih scenarijev spletnih aplikacij.

Ko pa začnete delati s protokoli aplikacij, ki uporabljajo trajne povezave TCP, kot so baze podatkov, gRPC ali WebSockets, storitve niso več primerne. Kubernetes ne zagotavlja notranjih mehanizmov za uravnoteženje trajnih povezav TCP.

To pomeni, da morate pisati aplikacije z mislijo na uravnoteženje na strani odjemalca.

Prevod je pripravila ekipa Kubernetes aaS iz Mail.ru.

Kaj še prebrati na to temo:

  1. Tri ravni samodejnega skaliranja v Kubernetesu in kako jih učinkovito uporabljati
  2. Kubernetes v duhu piratstva s predlogo za implementacijo.
  3. Naš Telegram kanal o digitalni transformaciji.

Vir: www.habr.com

Dodaj komentar