Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes
Tento článok vám pomôže pochopiť, ako funguje vyvažovanie záťaže v Kubernetes, čo sa stane pri škálovaní pripojení s dlhou životnosťou a prečo by ste mali zvážiť vyvažovanie na strane klienta, ak používate HTTP/2, gRPC, RSockets, AMQP alebo iné protokoly s dlhou životnosťou. . 

Trochu o tom, ako sa prerozdeľuje návštevnosť v Kubernetes 

Kubernetes poskytuje dve pohodlné abstrakcie na nasadenie aplikácií: Služby a Nasadenia.

Nasadenia popisujú, ako a koľko kópií vašej aplikácie by malo byť spustených v danom čase. Každá aplikácia je nasadená ako modul a má priradenú IP adresu.

Služby majú podobnú funkciu ako load balancer. Sú navrhnuté tak, aby distribuovali návštevnosť medzi viacero modulov.

Pozrime sa, ako to vyzerá.

  1. V nižšie uvedenom diagrame môžete vidieť tri inštancie tej istej aplikácie a nástroj na vyrovnávanie záťaže:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  2. Nástroj na vyrovnávanie záťaže sa nazýva služba a má priradenú IP adresu. Každá prichádzajúca požiadavka je presmerovaná na jeden z modulov:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  3. Scenár nasadenia určuje počet inštancií aplikácie. Takmer nikdy nebudete musieť expandovať priamo pod:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  4. Každý modul má pridelenú vlastnú IP adresu:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Je užitočné chápať služby ako súbor IP adries. Pri každom prístupe k službe sa zo zoznamu vyberie jedna z adries IP a použije sa ako cieľová adresa.

Vyzerá to takto.

  1. Do služby je prijatá požiadavka curl 10.96.45.152:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  2. Služba vyberie jednu z troch adries pod ako cieľ:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  3. Premávka je presmerovaná na konkrétny modul:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Ak vaša aplikácia pozostáva z frontendu a backendu, potom budete mať službu aj nasadenie pre každý z nich.

Keď frontend odošle požiadavku na backend, nemusí presne vedieť, koľko modulov backend obsluhuje: môže ich byť jeden, desať alebo sto.

Frontend tiež nevie nič o adresách modulov obsluhujúcich backend.

Keď frontend odošle požiadavku na backend, použije IP adresu backendovej služby, ktorá sa nemení.

Tu je návod, ako to vyzerá.

  1. Pod 1 požaduje interný backendový komponent. Namiesto výberu konkrétneho pre backend odošle službe požiadavku:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  2. Služba vyberie jeden z backendových modulov ako cieľovú adresu:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  3. Premávka prechádza z bloku 1 do bloku 5, ktorý vyberie služba:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  4. Pod 1 presne nevie, koľko modulov ako pod 5 sa skrýva za službou:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Ale ako presne služba distribuuje požiadavky? Zdá sa, že sa používa okrúhle vyvažovanie? Poďme na to. 

Vyvažovanie v službách Kubernetes

Služby Kubernetes neexistujú. Neexistuje žiadny proces pre službu, ktorá má pridelenú IP adresu a port.

Môžete to overiť prihlásením sa do ľubovoľného uzla v klastri a spustením príkazu netstat -ntlp.

Nebudete môcť nájsť ani IP adresu pridelenú službe.

IP adresa služby sa nachádza v riadiacej vrstve, v kontroléri a je zaznamenaná v databáze – atď. Rovnakú adresu používa ďalší komponent - kube-proxy.
Kube-proxy dostane zoznam IP adries pre všetky služby a vygeneruje sadu pravidiel iptables na každom uzle v klastri.

Tieto pravidlá hovoria: „Ak vidíme IP adresu služby, musíme upraviť cieľovú adresu požiadavky a odoslať ju na jeden z modulov.“

Servisná IP adresa sa používa iba ako vstupný bod a nie je obsluhovaná žiadnym procesom, ktorý počúva túto IP adresu a port.

Pozrime sa na to

  1. Zvážte zhluk troch uzlov. Každý uzol má moduly:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  2. Viazané lusky natreté béžovou farbou sú súčasťou služby. Pretože služba neexistuje ako proces, zobrazuje sa sivou farbou:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  3. Prvý modul požaduje službu a musí prejsť na jeden z priradených modulov:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  4. Ale služba neexistuje, proces neexistuje. Ako to funguje?

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  5. Predtým, ako požiadavka opustí uzol, prejde pravidlami iptables:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  6. Pravidlá iptables vedia, že služba neexistuje a nahradia jej IP adresu jednou z IP adries modulov spojených s touto službou:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  7. Požiadavka dostane platnú IP adresu ako cieľovú adresu a spracuje sa normálne:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  8. V závislosti od topológie siete sa požiadavka nakoniec dostane do modulu:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Dokáže iptables vyvážiť zaťaženie?

Nie, iptables sa používajú na filtrovanie a neboli navrhnuté na vyvažovanie.

Je však možné napísať súbor pravidiel, ktoré fungujú podobne pseudobalancér.

A presne toto je implementované v Kubernetes.

Ak máte tri moduly, kube-proxy napíše nasledujúce pravidlá:

  1. Vyberte prvého podriadeného s pravdepodobnosťou 33 %, inak prejdite na ďalšie pravidlo.
  2. Vyberte druhé s pravdepodobnosťou 50%, inak prejdite na ďalšie pravidlo.
  3. Vyberte tretiu pod.

Tento systém vedie k tomu, že každý modul je vybraný s pravdepodobnosťou 33 %.

Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

A neexistuje žiadna záruka, že modul 2 bude vybraný ako ďalší po bloku 1.

Poznámka: iptables používa štatistický modul s náhodným rozložením. Algoritmus vyvažovania je teda založený na náhodnom výbere.

Teraz, keď ste pochopili, ako služby fungujú, pozrime sa na zaujímavejšie scenáre služieb.

Dlhodobé pripojenia v Kubernetes sa štandardne neškálujú

Každá HTTP požiadavka z frontendu na backend je obsluhovaná samostatným TCP spojením, ktoré sa otvára a zatvára.

Ak frontend odošle 100 požiadaviek za sekundu na backend, potom sa otvorí a zatvorí 100 rôznych TCP spojení.

Čas spracovania požiadavky a zaťaženie môžete skrátiť otvorením jedného pripojenia TCP a jeho použitím pre všetky nasledujúce požiadavky HTTP.

Protokol HTTP má funkciu nazývanú HTTP keep-alive alebo opätovné použitie pripojenia. V tomto prípade sa jediné pripojenie TCP používa na odosielanie a prijímanie viacerých požiadaviek a odpovedí HTTP:

Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Táto funkcia nie je predvolene povolená: server aj klient musia byť podľa toho nakonfigurované.

Samotné nastavenie je jednoduché a dostupné pre väčšinu programovacích jazykov a prostredí.

Tu je niekoľko odkazov na príklady v rôznych jazykoch:

Čo sa stane, ak použijeme udržiavanie nažive v službe Kubernetes?
Predpokladajme, že frontend aj backend podporujú udržiavanie pri živote.

Máme jednu kópiu frontendu a tri kópie backendu. Frontend odošle prvú požiadavku a otvorí TCP spojenie s backendom. Požiadavka sa dostane k službe, ako cieľová adresa sa vyberie jeden z backendových modulov. Backend odošle odpoveď a frontend ju prijme.

Na rozdiel od bežnej situácie, kedy sa TCP spojenie po prijatí odpovede uzavrie, je teraz ponechané otvorené pre ďalšie HTTP požiadavky.

Čo sa stane, ak frontend odošle viac požiadaviek na backend?

Na preposielanie týchto požiadaviek sa použije otvorené TCP spojenie, všetky požiadavky pôjdu na rovnaký backend, kam smerovala prvá požiadavka.

Nemali by iptables prerozdeľovať návštevnosť?

V tomto prípade nie.

Keď sa vytvorí pripojenie TCP, prechádza pravidlami iptables, ktoré vyberú konkrétny backend, kam bude smerovať prevádzka.

Keďže všetky nasledujúce požiadavky sú na už otvorenom TCP spojení, pravidlá iptables sa už nevolajú.

Pozrime sa, ako to vyzerá.

  1. Prvý modul odošle požiadavku do služby:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  2. Už viete, čo bude nasledovať. Služba neexistuje, ale existujú pravidlá iptables, ktoré spracujú požiadavku:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  3. Ako cieľová adresa sa vyberie jeden z backendových modulov:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  4. Žiadosť sa dostane na modul. V tomto bode sa vytvorí trvalé TCP spojenie medzi dvoma modulmi:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  5. Akákoľvek následná požiadavka z prvého modulu prejde cez už vytvorené pripojenie:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Výsledkom je rýchlejšia doba odozvy a vyššia priepustnosť, ale strácate možnosť škálovať backend.

Aj keď máte v backende dva moduly, pri neustálom pripojení bude prevádzka vždy smerovať na jeden z nich.

Dá sa to opraviť?

Keďže Kubernetes nevie, ako vyvážiť trvalé pripojenia, táto úloha pripadá na vás.

Služby sú kolekciou IP adries a portov nazývaných koncové body.

Vaša aplikácia môže získať zoznam koncových bodov zo služby a rozhodnúť sa, ako medzi ne distribuovať požiadavky. Môžete otvoriť trvalé pripojenie ku každému modulu a vyvážiť požiadavky medzi týmito pripojeniami pomocou funkcie round-robin.

Alebo aplikujte viac komplexné vyvažovacie algoritmy.

Kód na strane klienta, ktorý je zodpovedný za vyvažovanie, by sa mal riadiť touto logikou:

  1. Získajte zoznam koncových bodov zo služby.
  2. Otvorte trvalé pripojenie pre každý koncový bod.
  3. Keď je potrebné zadať požiadavku, použite jedno z otvorených pripojení.
  4. Pravidelne aktualizujte zoznam koncových bodov, vytvorte nové alebo zatvorte staré trvalé pripojenia, ak sa zoznam zmení.

Takto to bude vyzerať.

  1. Namiesto toho, aby prvý modul odosielal požiadavku do služby, môžete vyrovnávať požiadavky na strane klienta:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  2. Musíte napísať kód, ktorý sa pýta, ktoré moduly sú súčasťou služby:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  3. Keď máte zoznam, uložte ho na strane klienta a použite ho na pripojenie k modulom:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

  4. Ste zodpovedný za algoritmus vyvažovania záťaže:

    Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Teraz vyvstáva otázka: týka sa tento problém iba udržiavania HTTP?

Vyvažovanie záťaže na strane klienta

HTTP nie je jediný protokol, ktorý môže používať trvalé pripojenia TCP.

Ak vaša aplikácia používa databázu, pripojenie TCP sa neotvorí zakaždým, keď potrebujete zadať požiadavku alebo získať dokument z databázy. 

Namiesto toho sa otvorí a použije trvalé pripojenie TCP k databáze.

Ak je vaša databáza nasadená na Kubernetes a prístup je poskytovaný ako služba, stretnete sa s rovnakými problémami, aké sú opísané v predchádzajúcej časti.

Jedna replika databázy bude načítaná viac ako ostatné. Kube-proxy a Kubernetes nepomôžu vyvážiť pripojenia. Musíte sa postarať o vyváženie dopytov do databázy.

V závislosti od knižnice, ktorú používate na pripojenie k databáze, môžete mať rôzne možnosti riešenia tohto problému.

Nižšie je uvedený príklad prístupu k databázovému klastru MySQL z 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

Existuje mnoho ďalších protokolov, ktoré používajú trvalé pripojenia TCP:

  • WebSockets a zabezpečené WebSockets
  • HTTP / 2
  • gRPC
  • RSockets
  • AMQP

Väčšinu týchto protokolov by ste už mali poznať.

Ale ak sú tieto protokoly také populárne, prečo neexistuje štandardizované riešenie vyváženia? Prečo je potrebné zmeniť logiku klienta? Existuje natívne riešenie Kubernetes?

Kube-proxy a iptables sú navrhnuté tak, aby pokryli najbežnejšie prípady použitia pri nasadení na Kubernetes. Toto je pre pohodlie.

Ak používate webovú službu, ktorá odhaľuje REST API, máte šťastie – v tomto prípade sa nepoužívajú trvalé pripojenia TCP, môžete použiť akúkoľvek službu Kubernetes.

Akonáhle však začnete používať trvalé pripojenia TCP, budete musieť prísť na to, ako rovnomerne rozložiť záťaž medzi backendy. Kubernetes neobsahuje hotové riešenia pre tento prípad.

Určite však existujú možnosti, ktoré môžu pomôcť.

Vyvažovanie dlhodobých pripojení v Kubernetes

V Kubernetes existujú štyri typy služieb:

  1. ClusterIP
  2. Port uzla
  3. Load Balancer
  4. Bezhlavý

Prvé tri služby fungujú na základe virtuálnej IP adresy, ktorú používa kube-proxy na vytváranie pravidiel iptables. Ale základom všetkých služieb je bezhlavá služba.

Bezhlavá služba nemá priradenú žiadnu IP adresu a poskytuje iba mechanizmus na získanie zoznamu IP adries a portov podov (koncových bodov), ktoré sú s ňou spojené.

Všetky služby sú založené na bezhlavej službe.

Služba ClusterIP je bezhlavá služba s niekoľkými doplnkami: 

  1. Vrstva správy mu pridelí IP adresu.
  2. Kube-proxy vygeneruje potrebné pravidlá iptables.

Týmto spôsobom môžete ignorovať kube-proxy a priamo použiť zoznam koncových bodov získaných z bezhlavej služby na vyváženie zaťaženia vašej aplikácie.

Ako však môžeme pridať podobnú logiku všetkým aplikáciám nasadeným v klastri?

Ak je vaša aplikácia už nasadená, táto úloha sa môže zdať nemožná. Existuje však alternatívna možnosť.

Service Mesh vám pomôže

Pravdepodobne ste si už všimli, že stratégia vyvažovania záťaže na strane klienta je celkom štandardná.

Po spustení aplikácie:

  1. Získa zoznam IP adries zo služby.
  2. Otvára a udržiava fond pripojení.
  3. Pravidelne aktualizuje fond pridávaním alebo odstraňovaním koncových bodov.

Keď chce aplikácia podať žiadosť,:

  1. Vyberie dostupné pripojenie pomocou nejakej logiky (napr. round-robin).
  2. Vykoná požiadavku.

Tieto kroky fungujú pre pripojenia WebSockets, gRPC aj AMQP.

Túto logiku môžete rozdeliť do samostatnej knižnice a použiť ju vo svojich aplikáciách.

Namiesto toho však môžete použiť sieťky služieb ako Istio alebo Linkerd.

Service Mesh rozšíri vašu aplikáciu o proces, ktorý:

  1. Automaticky vyhľadáva adresy IP služby.
  2. Testuje pripojenia, ako sú WebSockets a gRPC.
  3. Vyrovnáva požiadavky pomocou správneho protokolu.

Service Mesh pomáha spravovať prevádzku v rámci klastra, ale je dosť náročná na zdroje. Ďalšími možnosťami sú použitie knižníc tretích strán, ako je Netflix Ribbon, alebo programovateľných proxy serverov, ako je Envoy.

Čo sa stane, ak ignorujete problémy s vyvážením?

Môžete sa rozhodnúť nepoužívať vyrovnávanie záťaže a napriek tomu nezaznamenať žiadne zmeny. Pozrime sa na niekoľko pracovných scenárov.

Ak máte viac klientov ako serverov, nie je to až taký problém.

Povedzme, že existuje päť klientov, ktorí sa pripájajú k dvom serverom. Aj keď nedôjde k vyvažovaniu, použijú sa oba servery:

Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Pripojenia nemusia byť rovnomerne rozdelené: možno štyria klienti sú pripojení k rovnakému serveru, ale je veľká šanca, že sa použijú oba servery.

Problematickejší je opačný scenár.

Ak máte menej klientov a viac serverov, vaše zdroje môžu byť nedostatočne využité a objaví sa potenciálne úzke miesto.

Povedzme, že existujú dvaja klienti a päť serverov. V najlepšom prípade budú dve trvalé pripojenia k dvom serverom z piatich.

Zostávajúce servery budú nečinné:

Vyvažovanie záťaže a škálovanie dlhodobých pripojení v Kubernetes

Ak tieto dva servery nedokážu spracovať požiadavky klientov, horizontálne škálovanie nepomôže.

Záver

Služby Kubernetes sú navrhnuté tak, aby fungovali vo väčšine štandardných scenárov webových aplikácií.

Keď však začnete pracovať s aplikačnými protokolmi, ktoré využívajú trvalé TCP spojenia, ako sú databázy, gRPC alebo WebSockets, služby už nie sú vhodné. Kubernetes neposkytuje interné mechanizmy na vyrovnávanie trvalých pripojení TCP.

To znamená, že musíte písať aplikácie s ohľadom na vyváženie na strane klienta.

Preklad pripravil tím Kubernetes aaS z Mail.ru.

Čo si ešte prečítať k téme:

  1. Tri úrovne automatického škálovania v Kubernetes a ako ich efektívne používať
  2. Kubernetes v duchu pirátstva so šablónou na implementáciu.
  3. Náš kanál Telegram o digitálnej transformácii.

Zdroj: hab.com

Pridať komentár