Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu
Ovaj će vam članak pomoći razumjeti kako funkcionira balansiranje opterećenja u Kubernetesu, što se događa pri skaliranju dugotrajnih veza i zašto biste trebali razmotriti balansiranje na strani klijenta ako koristite HTTP/2, gRPC, RSockets, AMQP ili druge dugotrajne protokole . 

Malo o tome kako se redistribuira promet u Kubernetesu 

Kubernetes pruža dvije prikladne 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 je raspoređena kao Pod i dodijeljena joj je IP adresa.

Usluge su po funkciji slične balanseru opterećenja. Osmišljeni su za raspodjelu prometa na više grupa.

Da vidimo kako to izgleda.

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  2. Uravnoteživač opterećenja naziva se usluga i dodjeljuje mu se IP adresa. Svaki dolazni zahtjev preusmjerava se na jednu od grupa:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  3. Scenarij implementacije određuje broj instanci aplikacije. Gotovo nikad se nećete morati proširiti izravno ispod:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  4. Svakom modulu je dodijeljena vlastita IP adresa:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

Korisno je zamisliti usluge kao skup IP adresa. Svaki put kada pristupite usluzi, jedna od IP adresa odabire se s popisa i koristi se kao odredišna adresa.

Ovako izgleda.

  1. Zahtjev curl 10.96.45.152 primljen je na uslugu:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  3. Promet se preusmjerava na određenu pod:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

Kada sučelje podnese zahtjev pozadini, ne mora točno znati koliko podova služi pozadina: može biti jedan, deset ili stotinu.

Također, sučelje ne zna ništa o adresama podova koji opslužuju pozadinu.

Kada sučelje uputi zahtjev pozadini, koristi se IP adresa pozadinske usluge, koja se ne mijenja.

Evo kako to izgleda.

  1. Pod 1 zahtijeva internu pozadinsku komponentu. Umjesto odabira određenog za pozadinu, šalje zahtjev usluzi:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  2. Usluga odabire jedan od backend modula kao odredišnu adresu:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  3. Promet se odvija od Pod 1 do Pod 5 prema izboru servisa:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  4. Pod 1 ne zna točno koliko je mahuna kao pod 5 skriveno iza usluge:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

Ali kako točno usluga distribuira zahtjeve? Čini se da se koristi kružno balansiranje? Hajdemo shvatiti. 

Balansiranje u Kubernetes uslugama

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

To možete provjeriti prijavom na bilo koji čvor u klasteru i pokretanjem naredbe netstat -ntlp.

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

IP adresa servisa nalazi se u kontrolnom sloju, u kontroleru, i zabilježena u bazi podataka - itd. Istu adresu koristi druga komponenta - kube-proxy.
Kube-proxy prima popis IP adresa za sve usluge i generira skup pravila iptables na svakom čvoru u klasteru.

Ova pravila kažu: "Ako vidimo IP adresu usluge, moramo izmijeniti odredišnu adresu zahtjeva i poslati je jednoj od grupa."

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

Pogledajmo ovo

  1. Razmotrimo klaster od tri čvora. Svaki čvor ima podove:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  2. Vezane mahune obojene u bež boju dio su servisa. Budući da usluga ne postoji kao proces, prikazana je sivom bojom:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  3. Prva grupa zahtijeva uslugu i mora ići na jednu od pridruženih grupa:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  8. Ovisno o topologiji mreže, zahtjev na kraju stigne do modula:

    Balansiranje opterećenja i skaliranje dugotrajnih 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 upravo je to implementirano u Kubernetesu.

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

  1. Odaberite prvi pod s vjerojatnošću od 33%, inače prijeđite na sljedeće pravilo.
  2. Odaberite drugo s vjerojatnošću od 50%, inače prijeđite na sljedeće pravilo.
  3. Odaberite treće ispod.

Ovaj sustav rezultira odabirom svake mahune s vjerojatnošću od 33%.

Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

I nema jamstva da će Pod 2 biti odabran sljedeći nakon Pod 1.

Primijetiti: iptables koristi statistički modul sa slučajnom distribucijom. Stoga se algoritam balansiranja temelji na slučajnom odabiru.

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

Dugotrajne veze u Kubernetesu ne skaliraju se prema zadanim postavkama

Svaki HTTP zahtjev od frontenda do backenda poslužuje zasebna TCP veza, 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 zahtjeva i opterećenje otvaranjem jedne TCP veze i njezinim korištenjem za sve naredne HTTP zahtjeve.

HTTP protokol ima značajku koja se zove HTTP keep-alive ili ponovno korištenje veze. U ovom slučaju, jedna TCP veza koristi se za slanje i primanje više HTTP zahtjeva i odgovora:

Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

Ova značajka nije omogućena prema zadanim postavkama: i poslužitelj i klijent moraju biti konfigurirani u skladu s tim.

Samo postavljanje je jednostavno i dostupno za većinu programskih jezika i okruženja.

Evo nekoliko poveznica na primjere na različitim jezicima:

Što se događa ako koristimo keep-alive u Kubernetes usluzi?
Pretpostavimo da i frontend i backend podržavaju održavanje života.

Imamo jednu kopiju frontenda i tri kopije backenda. Sučelje postavlja prvi zahtjev i otvara TCP vezu s pozadinom. Zahtjev stigne do usluge, jedan od pozadinskih modula odabran je kao odredišna adresa. Backend šalje odgovor, a frontend ga prima.

Za razliku od uobičajene situacije u kojoj se TCP veza zatvara nakon primitka odgovora, sada ostaje otvorena za daljnje HTTP zahtjeve.

Što se događa ako sučelje pošalje više zahtjeva pozadini?

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

Ne bi li iptables trebao redistribuirati promet?

Ne u ovom slučaju.

Kada se stvori TCP veza, ona prolazi kroz pravila iptables, koja odabiru određenu pozadinu gdje će promet ići.

Budući da su svi sljedeći zahtjevi na već otvorenoj TCP vezi, pravila iptables se više ne pozivaju.

Da vidimo kako to izgleda.

  1. Prva grupa šalje zahtjev servisu:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  3. Jedna od pozadinskih grupa bit će odabrana kao odredišna adresa:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  4. Zahtjev stiže pod. U ovoj će se točki uspostaviti stalna TCP veza između dva modula:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  5. Svaki sljedeći zahtjev iz prve jedinice ići će kroz već uspostavljenu vezu:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

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

Može li se to popraviti?

Budući da Kubernetes ne zna kako uravnotežiti trajne veze, ovaj zadatak pada na vas.

Usluge su skup IP adresa i priključaka koji se nazivaju krajnje točke.

Vaša aplikacija može dobiti popis krajnjih točaka od usluge i odlučiti kako distribuirati zahtjeve između njih. Možete otvoriti trajnu vezu sa svakim modulom i uravnotežiti zahtjeve između tih veza koristeći kružni postupak.

Ili nanesite više složeni algoritmi za balansiranje.

Kôd na strani klijenta koji je odgovoran za balansiranje trebao bi slijediti ovu logiku:

  1. Dobijte popis krajnjih točaka od usluge.
  2. Otvorite trajnu vezu za svaku krajnju točku.
  3. Kada je potrebno podnijeti zahtjev, koristite jednu od otvorenih veza.
  4. Redovito ažurirajte popis krajnjih točaka, stvorite nove ili zatvorite stare trajne veze ako se popis promijeni.

Ovako će to izgledati.

  1. Umjesto da prvi modul pošalje zahtjev usluzi, možete uravnotežiti zahtjeve na strani klijenta:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

  3. Kada imate popis, spremite ga na strani klijenta i upotrijebite ga za povezivanje s podovima:

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

    Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

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

Balansiranje opterećenja na strani klijenta

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

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

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

Ako je vaša baza podataka postavljena na Kubernetes i pristup je omogućen kao usluga, tada ćete naići na iste probleme opisane u prethodnom odjeljku.

Jedna replika baze podataka bit će opterećenija od ostalih. Kube-proxy i Kubernetes neće pomoći u ravnoteži veza. Morate paziti na uravnoteženje upita u svojoj bazi podataka.

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

Ispod je primjer pristupa 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 stalne TCP veze:

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

Već ste trebali biti upoznati s većinom ovih protokola.

Ali ako su ti protokoli toliko popularni, zašto ne postoji standardizirano rješenje za balansiranje? Zašto se logika klijenta mora promijeniti? Postoji li izvorno Kubernetes rješenje?

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

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

Ali kad jednom počnete koristiti trajne TCP veze, morat ćete smisliti kako ravnomjerno rasporediti opterećenje po pozadinskim dijelovima. 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

U Kubernetesu postoje četiri vrste usluga:

  1. KlasterIP
  2. Čvorni priključak
  3. LoadBalancer
  4. Bezglav

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

Bezglava usluga nema nikakvu IP adresu povezanu sa sobom i pruža samo mehanizam za dohvaćanje popisa IP adresa i priključaka mahuna (krajnjih točaka) povezanih s njom.

Sve usluge temelje se na bezglavom servisu.

Usluga ClusterIP je usluga bez glave s nekim dodacima: 

  1. Upravljački sloj mu dodjeljuje IP adresu.
  2. Kube-proxy generira potrebna pravila za iptables.

Na ovaj način možete ignorirati kube-proxy i izravno upotrijebiti popis krajnjih točaka dobiven od headless usluge za uravnoteženje 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ć implementirana, ovaj se zadatak može činiti nemogućim. Međutim, postoji alternativna opcija.

Service Mesh će vam pomoći

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

Kada se aplikacija pokrene, ona:

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

Nakon što aplikacija želi podnijeti zahtjev, ona:

  1. Odabire dostupnu vezu pomoću neke logike (npr. kružno).
  2. Izvršava zahtjev.

Ovi koraci rade i 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 servisa.
  2. Testira veze kao što su WebSockets i gRPC.
  3. Uravnotežuje zahtjeve pomoću ispravnog protokola.

Service Mesh pomaže u upravljanju prometom unutar klastera, ali je dosta intenzivan. Ostale opcije su korištenje biblioteka trećih strana kao što je Netflix Ribbon ili programabilnih proxyja kao što je Envoy.

Što se događa ako zanemarite probleme s ravnotežom?

Možete odabrati da ne koristite balansiranje opterećenja, a da ipak ne primijetite nikakve promjene. Pogledajmo nekoliko scenarija rada.

Ako imate više klijenata nego poslužitelja, to i nije tako velik problem.

Recimo da postoji pet klijenata koji se spajaju na dva poslužitelja. Čak i ako nema balansiranja, koristit će se oba poslužitelja:

Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

Veze možda nisu ravnomjerno raspoređene: možda su četiri klijenta spojena na isti poslužitelj, ali postoji velika vjerojatnost da će se koristiti oba poslužitelja.

Problematičniji je suprotan scenarij.

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

Recimo da postoje dva klijenta i pet poslužitelja. U najboljem slučaju postojat će dvije stalne veze na dva poslužitelja od pet.

Preostali poslužitelji bit će u stanju mirovanja:

Balansiranje opterećenja i skaliranje dugotrajnih veza u Kubernetesu

Ako ova dva poslužitelja ne mogu obraditi zahtjeve klijenata, horizontalno skaliranje neće pomoći.

Zaključak

Kubernetes usluge dizajnirane su za rad u većini standardnih scenarija web aplikacija.

Međutim, nakon što 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.

Prijevod pripremio tim Kubernetes aaS s Mail.ru.

Što još pročitati na temu:

  1. Tri razine automatskog skaliranja u Kubernetesu i kako ih učinkovito koristiti
  2. Kubernetes u duhu piratstva s predloškom za implementaciju.
  3. Naš Telegram kanal o digitalnoj transformaciji.

Izvor: www.habr.com

Dodajte komentar