Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu
Ovaj članak će vam pomoći da shvatite kako balansiranje opterećenja funkcionira u Kubernetes-u, šta se događa kada skalirate dugovječne veze i zašto biste trebali razmotriti balansiranje na strani klijenta ako koristite HTTP/2, gRPC, RSockets, AMQP ili druge dugovječne protokole . 

Malo o tome kako se promet redistribuira u Kubernetesu 

Kubernetes pruža dvije zgodne apstrakcije za implementaciju aplikacija: usluge i implementacije.

Implementacije opisuju kako i koliko kopija vaše aplikacije treba biti pokrenuto u bilo kojem trenutku. Svaka aplikacija se postavlja kao Pod i dodjeljuje joj se IP adresa.

Usluge su po funkciji slične balanseru opterećenja. Dizajnirani su za distribuciju prometa na više podova.

Hajde da vidimo kako to izgleda.

  1. Na dijagramu ispod možete vidjeti tri primjera iste aplikacije i balansera opterećenja:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  2. Balansator opterećenja se zove usluga i dodjeljuje mu se IP adresa. Svaki dolazni zahtjev se preusmjerava na jedan od podova:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  3. Scenarij implementacije određuje broj instanci aplikacije. Gotovo nikada nećete morati da se širite direktno ispod:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  4. Svakoj podlozi je dodijeljena vlastita IP adresa:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Korisno je razmišljati o uslugama kao o skupu IP adresa. Svaki put kada pristupite servisu, jedna od IP adresa se bira sa liste i koristi kao odredišna adresa.

To izgleda ovako.

  1. Servisu je primljen zahtjev curl 10.96.45.152:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  2. Usluga odabire jednu od tri pod adrese kao odredište:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  3. Saobraćaj se preusmjerava na određeni pod:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Ako se vaša aplikacija sastoji od frontenda i backenda, tada ćete imati i uslugu i implementaciju za svaki.

Kada frontend uputi zahtjev pozadinskom dijelu, ne mora znati koliko podova pozadinska strana opslužuje: može biti jedan, deset ili sto.

Takođe, frontend ne zna ništa o adresama podova koji opslužuju backend.

Kada frontend uputi zahtjev backendu, on koristi IP adresu backend usluge, koja se ne mijenja.

Ovako to izgleda.

  1. Pod 1 zahtijeva internu pozadinsku komponentu. Umjesto odabira određenog za backend, on upućuje zahtjev servisu:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  2. Usluga odabire jedan od pozadinskih podova kao odredišnu adresu:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  3. Saobraćaj ide od Pod 1 do Pod 5, koju odabere servis:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  4. Pod 1 ne zna tačno koliko podova kao ispod 5 je skriveno iza usluge:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Ali kako tačno usluga distribuira zahtjeve? Čini se da se koristi round-robin balansiranje? Hajde da to shvatimo. 

Balansiranje u Kubernetes servisima

Kubernetes servisi ne postoje. Ne postoji proces za uslugu kojoj je dodijeljena IP adresa i port.

Ovo možete provjeriti tako što ćete se prijaviti na bilo koji čvor u klasteru i pokrenuti naredbu netstat -ntlp.

Nećete moći čak ni pronaći IP adresu dodijeljenu servisu.

IP adresa usluge nalazi se u kontrolnom sloju, u kontroleru, i evidentira se u bazi podataka - itd. Istu adresu koristi druga komponenta - kube-proxy.
Kube-proxy prima listu IP adresa za sve usluge i generiše skup iptables pravila za svaki čvor u klasteru.

Ova pravila kažu: “Ako vidimo IP adresu usluge, moramo izmijeniti odredišnu adresu zahtjeva i poslati je jednom od podova.”

IP adresa usluge se koristi samo kao ulazna tačka i ne opslužuje je nijedan proces koji sluša tu IP adresu i port.

Pogledajmo ovo

  1. Razmotrite klaster od tri čvora. Svaki čvor ima mahune:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  2. Vezane mahune obojene u bež su dio usluge. Pošto usluga ne postoji kao proces, prikazana je sivom bojom:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  3. Prvi pod zahtijeva uslugu i mora otići do jednog od povezanih podova:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  4. Ali usluga ne postoji, proces ne postoji. Kako to radi?

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  5. Prije nego što zahtjev napusti čvor, prolazi kroz iptables pravila:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  6. Pravila iptablesa znaju da usluga ne postoji i zamjenjuju njenu IP adresu jednom od IP adresa podova povezanih s tom uslugom:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  7. Zahtjev prima ispravnu IP adresu kao odredišnu adresu i normalno se obrađuje:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  8. Ovisno o topologiji mreže, zahtjev na kraju stiže do pod:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Može li iptables balansirati opterećenje?

Ne, iptables se koriste za filtriranje i nisu dizajnirani za balansiranje.

Međutim, moguće je napisati skup pravila koja funkcioniraju kao pseudo-balanser.

A to je upravo ono što je implementirano u Kubernetes.

Ako imate tri pod-a, kube-proxy će napisati sljedeća pravila:

  1. Odaberite prvu podlogu sa vjerovatnoćom od 33%, inače prijeđite na sljedeće pravilo.
  2. Odaberite drugo sa vjerovatnoćom od 50%, inače idite na sljedeće pravilo.
  3. Odaberite treći ispod.

Ovaj sistem rezultira odabirom svake mahune sa vjerovatnoćom od 33%.

Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

I nema garancije da će Pod 2 biti izabran sljedeći nakon Pod 1.

primjedba: iptables koristi statistički modul sa nasumičnom distribucijom. Stoga se algoritam balansiranja zasniva na slučajnom odabiru.

Sada kada razumijete kako usluge funkcioniraju, pogledajmo zanimljivije scenarije usluga.

Dugotrajne veze u Kubernetesu se prema zadanim postavkama ne povećavaju

Svaki HTTP zahtjev od frontenda do backenda opslužuje se odvojenom TCP vezom, koja se otvara i zatvara.

Ako frontend pošalje 100 zahtjeva u sekundi backendu, tada se otvara i zatvara 100 različitih TCP veza.

Možete smanjiti vrijeme obrade i učitavanja zahtjeva otvaranjem jedne TCP veze i korištenjem za sve naredne HTTP zahtjeve.

HTTP protokol ima funkciju koja se zove HTTP održavanje ili ponovna upotreba veze. U ovom slučaju, jedna TCP veza se koristi za slanje i primanje više HTTP zahtjeva i odgovora:

Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Ova funkcija nije omogućena prema zadanim postavkama: i server i klijent moraju biti konfigurirani u skladu s tim.

Sama postavka je jednostavna i dostupna za većinu programskih jezika i okruženja.

Evo nekoliko linkova do primjera na različitim jezicima:

Šta se dešava ako koristimo keep-alive u Kubernetes servisu?
Pretpostavimo da i frontend i backend podržavaju održavanje.

Imamo jednu kopiju frontenda i tri kopije backenda. Frontend daje prvi zahtjev i otvara TCP vezu sa pozadinom. Zahtjev stiže do servisa, jedan od pozadinskih podova se bira kao odredišna adresa. Backend šalje odgovor, a frontend ga prima.

Za razliku od uobičajene situacije kada je TCP veza zatvorena nakon prijema odgovora, sada je otvorena za dalje HTTP zahtjeve.

Šta se događa ako frontend pošalje više zahtjeva backendu?

Za prosljeđivanje ovih zahtjeva koristit će se otvorena TCP veza, svi zahtjevi će ići na isti backend gdje je otišao prvi zahtjev.

Zar iptables ne bi trebao redistribuirati promet?

Ne u ovom slučaju.

Kada se TCP konekcija kreira, ona prolazi kroz iptables pravila, koja biraju određeni pozadinski dio na koji će promet ići.

Pošto su svi naredni zahtjevi na već otvorenoj TCP vezi, iptables pravila se više ne pozivaju.

Hajde da vidimo kako to izgleda.

  1. Prvi pod šalje zahtjev servisu:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  2. Već znate šta će se dalje dogoditi. Usluga ne postoji, ali postoje iptables pravila koja će obraditi zahtjev:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  3. Jedan od pozadinskih podova će biti odabran kao odredišna adresa:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  4. Zahtjev stiže do pod. U ovom trenutku će se uspostaviti trajna TCP veza između dva pod-a:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  5. Svaki naredni zahtjev iz prvog pod će proći kroz već uspostavljenu vezu:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Rezultat je brže vrijeme odgovora i veća propusnost, ali gubite mogućnost skaliranja pozadine.

Čak i ako imate dva pod-a u pozadini, sa stalnom vezom, promet će uvijek ići na jedan od njih.

Može li se ovo popraviti?

Pošto Kubernetes ne zna kako da izbalansira trajne veze, ovaj zadatak pada na vas.

Usluge su skup IP adresa i portova koji se nazivaju krajnje tačke.

Vaša aplikacija može dobiti listu krajnjih tačaka od usluge i odlučiti kako distribuirati zahtjeve između njih. Možete otvoriti trajnu vezu sa svakim modulom i balansirati zahtjeve između ovih veza koristeći kružni rad.

Ili se prijavite više složeni algoritmi za balansiranje.

Kod na strani klijenta koji je odgovoran za balansiranje trebao bi slijediti ovu logiku:

  1. Dobijte listu krajnjih tačaka od usluge.
  2. Otvorite trajnu vezu za svaku krajnju tačku.
  3. Kada je potrebno uputiti zahtjev, koristite jednu od otvorenih veza.
  4. Redovno ažurirajte listu krajnjih tačaka, kreirajte nove ili zatvorite stare trajne veze ako se lista promeni.

Ovako će to izgledati.

  1. Umjesto da prvi pod šalje zahtjev servisu, možete uravnotežiti zahtjeve na strani klijenta:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  2. Morate napisati kod koji pita koji su podovi dio usluge:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  3. Kada dobijete listu, sačuvajte je na strani klijenta i koristite je za povezivanje sa podovima:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

  4. Vi ste odgovorni za algoritam balansiranja opterećenja:

    Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Sada se postavlja pitanje: da li se ovaj problem odnosi samo na HTTP Keep-alive?

Balansiranje opterećenja na strani klijenta

HTTP nije jedini protokol koji može koristiti trajne TCP veze.

Ako vaša aplikacija koristi bazu podataka, tada se TCP veza ne otvara svaki put kada trebate podnijeti zahtjev ili preuzeti dokument iz baze podataka. 

Umjesto toga, otvara se i koristi trajna TCP veza s bazom podataka.

Ako je vaša baza podataka raspoređena na Kubernetes i pristup je omogućen kao usluga, onda ćete naići na iste probleme opisane u prethodnom odeljku.

Jedna replika baze podataka će biti više učitana od ostalih. Kube-proxy i Kubernetes neće pomoći u balansiranju veza. Morate voditi računa o balansiranju upita prema vašoj bazi podataka.

Ovisno o tome koju biblioteku koristite za povezivanje s bazom podataka, možda ćete imati različite opcije za rješavanje ovog problema.

Ispod je primjer pristupanja MySQL klasteru baze podataka 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

Postoje mnogi drugi protokoli koji koriste trajne TCP veze:

  • WebSockets i zaštićeni WebSockets
  • HTTP / 2
  • gRPC
  • RSockets
  • AMQP

Većinu ovih protokola trebate već upoznati.

Ali ako su ovi protokoli toliko popularni, zašto ne postoji standardizirano rješenje za balansiranje? Zašto je potrebno promijeniti logiku klijenta? Postoji li izvorno Kubernetes rješenje?

Kube-proxy i iptables su dizajnirani da pokriju najčešće slučajeve upotrebe prilikom postavljanja na Kubernetes. Ovo je zbog pogodnosti.

Ako koristite web servis koji otkriva REST API, imate sreće - u ovom slučaju se ne koriste trajne TCP veze, možete koristiti bilo koju uslugu Kubernetes.

Ali kada počnete koristiti trajne TCP veze, morat ćete shvatiti kako ravnomjerno rasporediti opterećenje na pozadine. Kubernetes ne sadrži gotova rješenja za ovaj slučaj.

Međutim, svakako postoje opcije koje mogu pomoći.

Balansiranje dugotrajnih veza u Kubernetesu

Postoje četiri vrste usluga u Kubernetesu:

  1. ClusterIP
  2. NodePort
  3. LoadBalancer
  4. Bez glave

Prve tri usluge rade na osnovu virtuelne IP adrese, koju kube-proxy koristi za pravljenje iptables pravila. Ali temeljna osnova svih usluga je usluga bez glave.

Bezglava usluga nema nijednu IP adresu pridruženu s njom i pruža samo mehanizam za dohvaćanje liste IP adresa i portova podova (krajnjih tačaka) povezanih s njom.

Sve usluge su bazirane na bezglavoj usluzi.

Usluga ClusterIP je usluga bez glave s nekim dodacima: 

  1. Upravljački sloj mu dodeljuje IP adresu.
  2. Kube-proxy generiše potrebna iptables pravila.

Na ovaj način možete ignorisati kube-proxy i direktno koristiti listu krajnjih tačaka dobijenih od bezglavog servisa za balansiranje opterećenja vaše aplikacije.

Ali kako možemo dodati sličnu logiku svim aplikacijama raspoređenim u klasteru?

Ako je vaša aplikacija već raspoređena, ovaj zadatak može izgledati nemoguć. Međutim, postoji alternativna opcija.

Service Mesh će vam pomoći

Verovatno ste već primetili da je strategija balansiranja opterećenja na strani klijenta prilično standardna.

Kada se aplikacija pokrene, ona:

  1. Dobiva listu IP adresa od usluge.
  2. Otvara i održava skup veza.
  3. Povremeno ažurira skup dodavanjem ili uklanjanjem krajnjih tačaka.

Kada aplikacija želi da uputi zahtjev, ona:

  1. Odabire dostupnu vezu koristeći neku logiku (npr. round-robin).
  2. Izvršava zahtjev.

Ovi koraci rade za WebSockets, gRPC i AMQP veze.

Ovu logiku možete odvojiti u zasebnu biblioteku i koristiti je u svojim aplikacijama.

Međutim, umjesto toga možete koristiti servisne mreže kao što su Istio ili Linkerd.

Service Mesh proširuje vašu aplikaciju procesom koji:

  1. Automatski traži IP adrese usluge.
  2. Testira veze kao što su WebSockets i gRPC.
  3. Balansira zahtjeve koristeći ispravan protokol.

Service Mesh pomaže u upravljanju prometom unutar klastera, ali je prilično intenzivan resursima. Druge opcije su korištenje biblioteka trećih strana kao što je Netflix Ribbon ili programabilnih proksija kao što je Envoy.

Šta se dešava ako zanemarite probleme balansiranja?

Možete odabrati da ne koristite balansiranje opterećenja i još uvijek nećete primijetiti nikakve promjene. Pogledajmo nekoliko scenarija rada.

Ako imate više klijenata nego servera, to i nije tako veliki problem.

Recimo da postoji pet klijenata koji se povezuju na dva servera. Čak i ako nema balansiranja, oba servera će se koristiti:

Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Veze možda nisu ravnomjerno raspoređene: možda su četiri klijenta povezana na isti server, ali postoji velika šansa da će se koristiti oba servera.

Ono što je problematičnije je suprotan scenario.

Ako imate manje klijenata i više servera, vaši resursi mogu biti nedovoljno iskorišteni i pojavit će se potencijalno usko grlo.

Recimo da postoje dva klijenta i pet servera. U najboljem slučaju, postojaće dvije trajne veze na dva od pet servera.

Preostali serveri će biti neaktivni:

Balansiranje opterećenja i skaliranje dugovječnih veza u Kubernetesu

Ako ova dva servera ne mogu podnijeti zahtjeve klijenata, horizontalno skaliranje neće pomoći.

zaključak

Kubernetes usluge su dizajnirane da rade u većini standardnih scenarija web aplikacija.

Međutim, kada počnete raditi s aplikacijskim protokolima koji koriste trajne TCP veze, kao što su baze podataka, gRPC ili WebSockets, usluge više nisu prikladne. Kubernetes ne pruža interne mehanizme za balansiranje trajnih TCP veza.

To znači da morate pisati aplikacije imajući na umu balansiranje na strani klijenta.

Prevod pripremio tim Kubernetes aaS sa Mail.ru.

Šta još pročitati na temu:

  1. Tri nivoa automatskog skaliranja u Kubernetesu i kako ih efikasno koristiti
  2. Kubernetes u duhu piraterije sa šablonom za implementaciju.
  3. Naš Telegram kanal o digitalnoj transformaciji.

izvor: www.habr.com

Dodajte komentar