Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes
Tento článek vám pomůže pochopit, jak funguje vyvažování zátěže v Kubernetes, co se stane při škálování dlouhodobých připojení a proč byste měli zvážit vyvažování na straně klienta, pokud používáte HTTP/2, gRPC, RSockets, AMQP nebo jiné protokoly s dlouhou životností. . 

Něco málo o tom, jak je provoz v Kubernetes přerozdělován 

Kubernetes poskytuje dvě pohodlné abstrakce pro nasazení aplikací: Služby a Nasazení.

Nasazení popisují, jak a kolik kopií vaší aplikace by mělo být v daném okamžiku spuštěno. Každá aplikace je nasazena jako Pod a je jí přidělena IP adresa.

Služby mají podobnou funkci jako load balancer. Jsou navrženy tak, aby distribuovaly provoz mezi více modulů.

Pojďme se podívat, jak to vypadá.

  1. Na níže uvedeném diagramu můžete vidět tři instance stejné aplikace a load balancer:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  2. Nástroj pro vyrovnávání zatížení se nazývá služba a je mu přidělena adresa IP. Jakýkoli příchozí požadavek je přesměrován na jeden z modulů:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  3. Scénář nasazení určuje počet instancí aplikace. Téměř nikdy nebudete muset expandovat přímo pod:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  4. Každému modulu je přiřazena vlastní IP adresa:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Je užitečné uvažovat o službách jako o sbírce IP adres. Při každém přístupu ke službě se ze seznamu vybere jedna z IP adres a použije se jako cílová adresa.

Vypadá to takto.

  1. Do služby je přijat požadavek curl 10.96.45.152:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  2. Služba vybere jako cíl jednu ze tří adres pod:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  3. Provoz je přesměrován na konkrétní pod:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Pokud se vaše aplikace skládá z frontendu a backendu, budete mít pro každý z nich službu i nasazení.

Když frontend zadá požadavek na backend, nemusí přesně vědět, kolik podů backend obsluhuje: může jich být jeden, deset nebo sto.

Frontend také neví nic o adresách podů obsluhujících backend.

Když frontend zadá požadavek na backend, použije IP adresu backendové služby, která se nemění.

Zde je návod, jak to vypadá.

  1. Pod 1 požaduje interní backend komponentu. Namísto výběru konkrétního pro backend zadá požadavek na službu:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  2. Služba vybere jeden z backendových modulů jako cílovou adresu:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  3. Provoz přechází z Pod 1 do Pod 5, vybrané službou:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  4. Pod 1 přesně neví, kolik podů jako pod 5 se skrývá za službou:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Ale jak přesně služba distribuuje požadavky? Zdá se, že se používá vyvažování mezi jednotlivými okruhy? Pojďme na to přijít. 

Balancování ve službách Kubernetes

Služby Kubernetes neexistují. Pro službu, které je přiřazena IP adresa a port, neexistuje žádný proces.

Můžete to ověřit přihlášením do libovolného uzlu v klastru a spuštěním příkazu netstat -ntlp.

Nebudete moci ani najít IP adresu přidělenou službě.

IP adresa služby je umístěna v řídicí vrstvě, v řadiči a zaznamenána v databázi - atd. Stejnou adresu používá další komponenta - kube-proxy.
Kube-proxy obdrží seznam IP adres pro všechny služby a vygeneruje sadu pravidel iptables na každém uzlu v clusteru.

Tato pravidla říkají: „Pokud vidíme IP adresu služby, musíme upravit cílovou adresu požadavku a odeslat ji na jeden z modulů.“

Servisní IP adresa se používá pouze jako vstupní bod a neobsluhuje ji žádný proces naslouchající této IP adrese a portu.

Podívejme se na to

  1. Uvažujme shluk tří uzlů. Každý uzel má pody:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  2. Vázané lusky lakované béžovou barvou jsou součástí služby. Protože služba neexistuje jako proces, je zobrazena šedě:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  3. První modul požaduje službu a musí přejít na jeden z přidružených modulů:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

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

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  5. Než požadavek opustí uzel, projde pravidly iptables:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  6. Pravidla iptables vědí, že služba neexistuje, a nahrazují její IP adresu jednou z IP adres podů spojených s touto službou:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  7. Požadavek obdrží platnou IP adresu jako cílovou adresu a je zpracován normálně:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  8. V závislosti na topologii sítě požadavek nakonec dosáhne pod:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Dokáže iptables vyvážit zatížení?

Ne, iptables se používají k filtrování a nebyly navrženy pro vyvažování.

Je však možné napsat sadu pravidel, která fungují jako pseudobalancér.

A přesně to je implementováno v Kubernetes.

Pokud máte tři moduly, kube-proxy napíše následující pravidla:

  1. Vyberte prvního podřízeného s pravděpodobností 33 %, jinak přejděte k dalšímu pravidlu.
  2. Vyberte druhé s pravděpodobností 50 %, jinak přejděte k dalšímu pravidlu.
  3. Vyberte třetí pod.

Tento systém má za následek, že každý modul je vybrán s pravděpodobností 33 %.

Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

A neexistuje žádná záruka, že modul 2 bude vybrán jako další po modulu 1.

Poznámka: iptables používá statistický modul s náhodným rozdělením. Algoritmus vyvažování je tedy založen na náhodném výběru.

Nyní, když rozumíte tomu, jak služby fungují, pojďme se podívat na zajímavější scénáře služeb.

Dlouhodobá připojení v Kubernetes se ve výchozím nastavení neškálují

Každý HTTP požadavek z frontendu na backend je obsluhován samostatným TCP spojením, které se otevírá a zavírá.

Pokud frontend odešle do backendu 100 požadavků za sekundu, otevře a zavře se 100 různých TCP spojení.

Můžete zkrátit dobu zpracování požadavků a zatížení tím, že otevřete jedno TCP spojení a použijete ho pro všechny následující HTTP požadavky.

Protokol HTTP má funkci zvanou HTTP keep-alive neboli opětovné použití připojení. V tomto případě se k odesílání a přijímání více požadavků a odpovědí HTTP používá jediné připojení TCP:

Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Tato funkce není ve výchozím nastavení povolena: podle toho musí být nakonfigurován server i klient.

Samotné nastavení je jednoduché a dostupné pro většinu programovacích jazyků a prostředí.

Zde je několik odkazů na příklady v různých jazycích:

Co se stane, když ve službě Kubernetes použijeme funkci keep-alive?
Předpokládejme, že jak frontend, tak backend podporují zachování.

Máme jednu kopii frontendu a tři kopie backendu. Frontend provede první požadavek a otevře TCP spojení s backendem. Požadavek dorazí ke službě, jeden z backendových modulů je vybrán jako cílová adresa. Backend odešle odpověď a frontend ji přijme.

Na rozdíl od obvyklé situace, kdy je TCP spojení po obdržení odpovědi uzavřeno, je nyní udržováno otevřené pro další HTTP požadavky.

Co se stane, když frontend odešle více požadavků na backend?

K předání těchto požadavků bude použito otevřené TCP spojení, všechny požadavky půjdou na stejný backend, kam šel první požadavek.

Neměly by iptables přerozdělovat provoz?

V tomto případě ne.

Když je vytvořeno TCP spojení, prochází pravidly iptables, která vybírají konkrétní backend, kam bude provoz směřovat.

Protože všechny následující požadavky jsou na již otevřeném TCP spojení, pravidla iptables se již nevolají.

Pojďme se podívat, jak to vypadá.

  1. První modul odešle požadavek službě:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  2. Už víte, co bude dál. Služba neexistuje, ale existují pravidla iptables, která požadavek zpracují:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  3. Jako cílová adresa bude vybrán jeden z backendových modulů:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  4. Žádost dorazí do modulu. V tomto okamžiku bude navázáno trvalé TCP spojení mezi dvěma moduly:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  5. Jakýkoli další požadavek z prvního modulu projde již vytvořeným připojením:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Výsledkem jsou rychlejší doby odezvy a vyšší propustnost, ale ztrácíte možnost škálovat backend.

I když máte v backendu dva moduly, s konstantním připojením bude provoz vždy směřovat do jednoho z nich.

Lze to opravit?

Vzhledem k tomu, že Kubernetes neví, jak vyvážit trvalá připojení, je tento úkol na vás.

Služby jsou kolekce IP adres a portů nazývaných koncové body.

Vaše aplikace může získat seznam koncových bodů ze služby a rozhodnout, jak mezi ně rozdělit požadavky. Můžete otevřít trvalé připojení ke každému podu a vyrovnat požadavky mezi těmito připojeními pomocí kruhové obsluhy.

Nebo aplikujte více složité vyvažovací algoritmy.

Kód na straně klienta, který je zodpovědný za vyvažování, by se měl řídit touto logikou:

  1. Získejte seznam koncových bodů ze služby.
  2. Otevřete trvalé připojení pro každý koncový bod.
  3. Když je třeba provést požadavek, použijte jedno z otevřených připojení.
  4. Pravidelně aktualizujte seznam koncových bodů, vytvořte nové nebo ukončete stará trvalá připojení, pokud se seznam změní.

Takhle to bude vypadat.

  1. Namísto toho, aby první modul odeslal požadavek službě, můžete vyrovnat požadavky na straně klienta:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  2. Musíte napsat kód, který se zeptá, které moduly jsou součástí služby:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  3. Jakmile budete mít seznam, uložte jej na straně klienta a použijte jej k připojení k modulům:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

  4. Jste odpovědní za algoritmus vyrovnávání zátěže:

    Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Nyní vyvstává otázka: týká se tento problém pouze HTTP keep-alive?

Vyvažování zátěže na straně klienta

HTTP není jediný protokol, který může používat trvalá připojení TCP.

Pokud vaše aplikace používá databázi, pak se TCP spojení neotevře pokaždé, když potřebujete vytvořit požadavek nebo načíst dokument z databáze. 

Místo toho se otevře a použije trvalé připojení TCP k databázi.

Pokud je vaše databáze nasazena na Kubernetes a přístup je poskytován jako služba, setkáte se se stejnými problémy, které jsou popsány v předchozí části.

Jedna replika databáze bude načtena více než ostatní. Kube-proxy a Kubernetes nepomohou vyvážit připojení. Musíte se postarat o vyvážení dotazů do vaší databáze.

V závislosti na knihovně, kterou používáte pro připojení k databázi, můžete mít různé možnosti řešení tohoto problému.

Níže je uveden příklad přístupu k databázovému clusteru 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 dalších protokolů, které používají trvalá připojení TCP:

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

S většinou těchto protokolů byste již měli být obeznámeni.

Ale pokud jsou tyto protokoly tak populární, proč neexistuje standardizované řešení vyvážení? Proč se logika klienta musí změnit? Existuje nativní řešení Kubernetes?

Kube-proxy a iptables jsou navrženy tak, aby pokryly většinu běžných případů použití při nasazení na Kubernetes. Toto je pro pohodlí.

Pokud používáte webovou službu, která odhaluje REST API, máte štěstí – v tomto případě se nepoužívají trvalá připojení TCP, můžete použít jakoukoli službu Kubernetes.

Jakmile ale začnete používat trvalá připojení TCP, budete muset vymyslet, jak rovnoměrně rozložit zátěž mezi backendy. Kubernetes neobsahuje hotová řešení pro tento případ.

Určitě však existují možnosti, které mohou pomoci.

Vyvažování dlouhodobých připojení v Kubernetes

V Kubernetes existují čtyři typy služeb:

  1. ClusterIP
  2. Port uzlu
  3. LoadBalancer
  4. Bezhlavý

První tři služby fungují na základě virtuální IP adresy, kterou používá kube-proxy k vytváření pravidel iptables. Ale základním základem všech služeb je bezhlavá služba.

Bezhlavá služba nemá přidruženou žádnou IP adresu a poskytuje pouze mechanismus pro načtení seznamu IP adres a portů podů (koncových bodů) s ní spojených.

Všechny služby jsou založeny na bezhlavé službě.

Služba ClusterIP je bezhlavá služba s některými doplňky: 

  1. Vrstva správy mu přidělí IP adresu.
  2. Kube-proxy vygeneruje potřebná pravidla iptables.

Tímto způsobem můžete ignorovat kube-proxy a přímo použít seznam koncových bodů získaných ze služby headless k vyrovnávání zatížení vaší aplikace.

Jak ale můžeme přidat podobnou logiku všem aplikacím nasazeným v clusteru?

Pokud je vaše aplikace již nasazena, může se tento úkol zdát nemožný. Existuje však alternativní možnost.

Service Mesh vám pomůže

Pravděpodobně jste si již všimli, že strategie vyvažování zátěže na straně klienta je zcela standardní.

Po spuštění aplikace:

  1. Získá seznam IP adres ze služby.
  2. Otevírá a udržuje fond připojení.
  3. Pravidelně aktualizuje fond přidáním nebo odebráním koncových bodů.

Jakmile aplikace chce podat žádost,:

  1. Vybere dostupné připojení pomocí nějaké logiky (např. round-robin).
  2. Vyřídí požadavek.

Tyto kroky fungují pro připojení WebSockets, gRPC i AMQP.

Tuto logiku můžete oddělit do samostatné knihovny a použít ji ve svých aplikacích.

Místo toho však můžete použít servisní sítě jako Istio nebo Linkerd.

Service Mesh rozšíří vaši aplikaci o proces, který:

  1. Automaticky vyhledává servisní IP adresy.
  2. Testuje připojení, jako jsou WebSockets a gRPC.
  3. Vyrovnává požadavky pomocí správného protokolu.

Service Mesh pomáhá řídit provoz v rámci clusteru, ale je poměrně náročný na zdroje. Dalšími možnostmi jsou použití knihoven třetích stran, jako je Netflix Ribbon, nebo programovatelné proxy, jako je Envoy.

Co se stane, když problémy s vyvážením ignorujete?

Můžete se rozhodnout nepoužívat vyrovnávání zátěže a přesto nezaznamenat žádné změny. Podívejme se na několik pracovních scénářů.

Pokud máte více klientů než serverů, není to tak velký problém.

Řekněme, že existuje pět klientů, kteří se připojují ke dvěma serverům. I když nedojde k vyrovnání, budou použity oba servery:

Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Připojení nemusí být rovnoměrně rozmístěno: možná jsou čtyři klienti připojeni ke stejnému serveru, ale je velká šance, že budou použity oba servery.

Problematičtější je opačný scénář.

Máte-li méně klientů a více serverů, mohou být vaše prostředky nevyužité a objeví se potenciální úzké místo.

Řekněme, že existují dva klienti a pět serverů. V nejlepším případě budou dvě trvalá připojení ke dvěma serverům z pěti.

Zbývající servery budou nečinné:

Vyrovnávání zátěže a škálování dlouhodobých připojení v Kubernetes

Pokud tyto dva servery nezvládají požadavky klientů, horizontální škálování nepomůže.

Závěr

Služby Kubernetes jsou navrženy tak, aby fungovaly ve většině scénářů standardních webových aplikací.

Jakmile však začnete pracovat s aplikačními protokoly, které používají trvalá TCP spojení, jako jsou databáze, gRPC nebo WebSockets, služby již nejsou vhodné. Kubernetes neposkytuje interní mechanismy pro vyvažování trvalých připojení TCP.

To znamená, že musíte psát aplikace s ohledem na vyvažování na straně klienta.

Překlad připravil tým Kubernetes aaS z Mail.ru.

Co si k tématu ještě přečíst:

  1. Tři úrovně automatického škálování v Kubernetes a jak je efektivně používat
  2. Kubernetes v pirátském duchu se šablonou pro implementaci.
  3. Náš kanál Telegram o digitální transformaci.

Zdroj: www.habr.com

Přidat komentář