Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben
Ez a cikk segít megérteni, hogyan működik a terheléselosztás a Kubernetesben, mi történik a hosszú élettartamú kapcsolatok méretezésekor, és miért érdemes megfontolni az ügyféloldali kiegyenlítést, ha HTTP/2, gRPC, RSockets, AMQP vagy más hosszú élettartamú protokollokat használ. . 

Egy kicsit arról, hogyan osztják újra a forgalmat Kubernetesben 

A Kubernetes két kényelmes absztrakciót biztosít az alkalmazások üzembe helyezéséhez: Szolgáltatások és Telepítések.

A telepítések leírják, hogyan és hány példányban kell futnia az alkalmazásnak egy adott időpontban. Minden alkalmazás Pod-ként kerül telepítésre, és hozzá van rendelve egy IP-cím.

A szolgáltatások funkciójukban hasonlóak a terheléselosztóhoz. Úgy tervezték, hogy a forgalmat több pod között osszák el.

Lássuk, hogyan néz ki.

  1. Az alábbi ábrán ugyanannak az alkalmazásnak és egy terheléselosztónak három példánya látható:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  2. A terheléselosztót szolgáltatásnak hívják, és hozzá van rendelve egy IP-cím. Minden bejövő kérés át lesz irányítva az egyik sorba:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  3. A telepítési forgatókönyv meghatározza az alkalmazás példányainak számát. Szinte soha nem kell közvetlenül a következő alatt bővíteni:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  4. Minden podhoz saját IP-cím van hozzárendelve:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Hasznos a szolgáltatásokat IP-címek gyűjteményének tekinteni. Minden alkalommal, amikor hozzáfér a szolgáltatáshoz, az egyik IP-címet kiválasztja a listából, és célcímként használja.

Ez így néz ki.

  1. Curl 10.96.45.152 kérés érkezett a szolgáltatáshoz:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  2. A szolgáltatás a három podcím egyikét választja célként:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  3. A forgalom egy adott csoportba van átirányítva:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Ha az alkalmazás egy előtérből és egy háttérrendszerből áll, akkor mindegyikhez lesz egy szolgáltatás és egy központi telepítés.

Amikor a frontend kérelmet küld a háttérrendszernek, nem kell pontosan tudnia, hogy a háttérrendszer hány podot szolgál ki: lehet egy, tíz vagy száz.

Ezenkívül a frontend semmit sem tud a háttérrendszert kiszolgáló podok címeiről.

Amikor a frontend kérelmet küld a háttérrendszernek, a háttérszolgáltatás IP-címét használja, amely nem változik.

Így néz ki.

  1. Az 1 alatt a belső háttérkomponenst kéri. Ahelyett, hogy egy konkrétat választana ki a háttérrendszer számára, kérést küld a szolgáltatásnak:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  2. A szolgáltatás az egyik háttérrendszert választja ki célcímként:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  3. A forgalom a szolgáltatás által kiválasztott Pod 1-ről Pod 5-re megy:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  4. Az 1 alatti nem tudja pontosan, hány 5 alatti pod van elrejtve a szolgáltatás mögött:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

De pontosan hogyan osztja el a szolgáltatás a kéréseket? Úgy tűnik, a körmérkőzéses egyensúlyozást használják? Találjuk ki. 

Kiegyensúlyozás a Kubernetes szolgáltatásokban

A Kubernetes szolgáltatások nem léteznek. A szolgáltatáshoz nincs folyamat, amelyhez IP-cím és port van hozzárendelve.

Ezt úgy ellenőrizheti, hogy bejelentkezik a fürt bármely csomópontjába, és futtatja a netstat -ntlp parancsot.

Még a szolgáltatáshoz kiosztott IP-címet sem fogja megtalálni.

A szolgáltatás IP-címe a vezérlőrétegben, a vezérlőben található, és rögzítve van az adatbázisban - stb. Ugyanezt a címet egy másik összetevő is használja - a kube-proxy.
A Kube-proxy megkapja az összes szolgáltatáshoz tartozó IP-címek listáját, és iptables-szabályokat állít elő a fürt minden csomópontján.

Ezek a szabályok a következőket mondják: "Ha látjuk a szolgáltatás IP-címét, módosítanunk kell a kérés célcímét, és el kell küldenünk az egyik podba."

A szolgáltatás IP-címe csak belépési pontként használatos, és nem szolgálja ki az adott IP-címet és portot figyelő folyamat.

Nézzük ezt

  1. Tekintsünk egy három csomópontból álló klasztert. Minden csomópontnak vannak hüvelyei:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  2. A bézsre festett kötött hüvelyek a szolgáltatás részét képezik. Mivel a szolgáltatás nem folyamatként létezik, szürkén jelenik meg:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  3. Az első pod szolgáltatást kér, és az egyik társított podhoz kell mennie:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  4. De a szolgáltatás nem létezik, a folyamat nem létezik. Hogyan működik?

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  5. Mielőtt a kérés elhagyná a csomópontot, végigmegy az iptables szabályokon:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  6. Az iptables szabályok tudják, hogy a szolgáltatás nem létezik, és lecserélik az IP-címét a szolgáltatáshoz társított podok egyik IP-címére:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  7. A kérelem egy érvényes IP-címet kap célcímként, és a szokásos módon kerül feldolgozásra:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  8. A hálózati topológiától függően a kérés végül eléri a pod-ot:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Tud iptables terhelési egyensúlyt?

Nem, az iptable-okat szűrésre használják, és nem egyensúlyozásra tervezték.

Lehetőség van azonban olyan szabályok felírására, amelyek hasonlóan működnek ál-egyensúlyozó.

És pontosan ezt valósítják meg a Kubernetesben.

Ha három podja van, a kube-proxy a következő szabályokat írja le:

  1. Válassza ki az első alcímet 33%-os valószínűséggel, ellenkező esetben lépjen a következő szabályra.
  2. Válassza ki a másodikat 50%-os valószínűséggel, ellenkező esetben lépjen a következő szabályra.
  3. Alul válassza ki a harmadikat.

Ez a rendszer azt eredményezi, hogy minden pod 33%-os valószínűséggel kerül kiválasztásra.

Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

És nincs garancia arra, hogy a Pod 2-t választják a Pod 1 után.

Megjegyzés: Az iptables véletlen eloszlású statisztikai modult használ. Így a kiegyenlítő algoritmus véletlenszerű kiválasztáson alapul.

Most, hogy megértette a szolgáltatások működését, nézzünk meg érdekesebb szolgáltatási forgatókönyveket.

A Kubernetes hosszú élettartamú kapcsolatai alapértelmezés szerint nem skálázódnak

Az előtértől a háttér felé tartó minden HTTP-kérést külön TCP-kapcsolat szolgál ki, amelyet megnyit és zár.

Ha az előtér másodpercenként 100 kérést küld a háttérrendszernek, akkor 100 különböző TCP-kapcsolat nyílik meg és zár be.

Csökkentheti a kérésfeldolgozási időt és a terhelést, ha megnyit egy TCP-kapcsolatot, és ezt használja az összes további HTTP-kéréshez.

A HTTP protokoll rendelkezik a HTTP életben tartás, vagyis a kapcsolat újrafelhasználása nevű funkcióval. Ebben az esetben egyetlen TCP-kapcsolatot használnak több HTTP kérés és válasz küldésére és fogadására:

Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Ez a funkció alapértelmezés szerint nincs engedélyezve: a szervert és a klienst is ennek megfelelően kell konfigurálni.

Maga a beállítás egyszerű és a legtöbb programozási nyelv és környezet számára elérhető.

Íme néhány hivatkozás a különböző nyelvű példákhoz:

Mi történik, ha a Keep-alive-t használjuk egy Kubernetes szolgáltatásban?
Tegyük fel, hogy a frontend és a háttérrendszer egyaránt támogatja az életben tartást.

Van egy példányunk az előtérből és három másolatunk a háttérből. A frontend végrehajtja az első kérést, és megnyit egy TCP-kapcsolatot a háttérrel. A kérés eléri a szolgáltatást, célcímként az egyik backend pod kerül kiválasztásra. A háttérrendszer választ küld, a frontend pedig megkapja azt.

A szokásos helyzettől eltérően, amikor a TCP-kapcsolat a válasz beérkezése után bezárul, most nyitva marad a további HTTP-kérések számára.

Mi történik, ha a frontend több kérést küld a háttérrendszernek?

Ezeknek a kéréseknek a továbbításához egy nyitott TCP-kapcsolat kerül felhasználásra, és minden kérés ugyanahhoz a háttérrendszerhez fog eljutni, ahol az első kérés.

Az iptables-nak nem kellene újraosztania a forgalmat?

Ebben az esetben nem.

A TCP-kapcsolat létrehozásakor az iptables szabályokon megy keresztül, amelyek kiválasztanak egy adott háttérrendszert, ahová a forgalom irányul.

Mivel minden további kérés már nyitott TCP-kapcsolaton van, az iptables szabályok többé nem kerülnek meghívásra.

Lássuk, hogyan néz ki.

  1. Az első pod kérést küld a szolgáltatásnak:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  2. Már tudod, mi fog történni ezután. A szolgáltatás nem létezik, de vannak iptables szabályok, amelyek feldolgozzák a kérést:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  3. Az egyik háttér-pod lesz kiválasztva célcímként:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  4. A kérés eléri a tokot. Ezen a ponton állandó TCP-kapcsolat jön létre a két pod között:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  5. Az első podból érkező minden további kérés a már létrehozott kapcsolaton keresztül megy keresztül:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Az eredmény gyorsabb válaszidő és nagyobb átviteli sebesség, de elveszíti a háttér méretezésének lehetőségét.

Még ha két pod van is a háttérben, állandó kapcsolat mellett, a forgalom mindig az egyikre fog menni.

Ezt meg lehet oldani?

Mivel a Kubernetes nem tudja, hogyan kell egyensúlyba hozni a tartós kapcsolatokat, ez a feladat rád hárul.

A szolgáltatások végpontoknak nevezett IP-címek és portok gyűjteménye.

Az alkalmazás lekérheti a végpontok listáját a szolgáltatástól, és eldöntheti, hogyan osztja el a kéréseket közöttük. Állandó kapcsolatot nyithat meg minden egyes podhoz, és kör-robin segítségével egyensúlyba hozhatja a kéréseket ezek között a kapcsolatok között.

Vagy alkalmazz többet komplex egyensúlyozó algoritmusok.

A kiegyenlítésért felelős ügyféloldali kódnak a következő logikát kell követnie:

  1. Szerezze be a végpontok listáját a szolgáltatásból.
  2. Nyisson meg egy állandó kapcsolatot minden végponthoz.
  3. Ha kérést kell benyújtani, használja a nyitott kapcsolatok egyikét.
  4. Rendszeresen frissítse a végpontok listáját, hozzon létre újakat, vagy zárja be a régi állandó kapcsolatokat, ha a lista megváltozik.

Így fog kinézni.

  1. Ahelyett, hogy az első pod küldi el a kérést a szolgáltatásnak, az ügyféloldalon egyensúlyozhatja a kéréseket:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  2. Olyan kódot kell írnia, amely megkérdezi, hogy mely podok tartoznak a szolgáltatáshoz:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  3. Ha megvan a lista, mentse el az ügyféloldalra, és használja a podokhoz való csatlakozáshoz:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

  4. Ön felelős a terheléselosztási algoritmusért:

    Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Most felmerül a kérdés: ez a probléma csak a HTTP életben tartásra vonatkozik?

Ügyféloldali terheléselosztás

A HTTP nem az egyetlen protokoll, amely állandó TCP-kapcsolatokat tud használni.

Ha az alkalmazás adatbázist használ, akkor a TCP-kapcsolat nem nyílik meg minden alkalommal, amikor kérést kell benyújtania vagy dokumentumot kell lekérnie az adatbázisból. 

Ehelyett egy állandó TCP-kapcsolatot nyit meg és használ az adatbázishoz.

Ha az adatbázis a Kubernetesen van telepítve, és a hozzáférés szolgáltatásként van biztosítva, akkor az előző részben leírt problémákkal fog szembesülni.

Az egyik adatbázis-replika jobban betöltődik, mint a többi. A Kube-proxy és a Kubernetes nem segít kiegyensúlyozni a kapcsolatokat. Gondoskodnia kell a lekérdezések és az adatbázis közötti egyensúlyról.

Attól függően, hogy melyik könyvtárat használja az adatbázishoz való csatlakozáshoz, különböző lehetőségek közül választhat a probléma megoldására.

Az alábbiakban egy MySQL adatbázis-fürt Node.js-ből való elérésére látható példa:

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

Sok más protokoll is állandó TCP-kapcsolatot használ:

  • WebSockets és biztonságos WebSockets
  • HTTP / 2
  • gRPC
  • RSockets
  • AMQP

A legtöbb ilyen protokollt már ismernie kell.

De ha ezek a protokollok olyan népszerűek, miért nem létezik szabványosított kiegyenlítő megoldás? Miért kell az ügyfél logikáját megváltoztatni? Van natív Kubernetes megoldás?

A Kube-proxy és az iptables úgy lett kialakítva, hogy a Kubernetes rendszerbe történő telepítéskor a leggyakoribb használati eseteket lefedjék. Ez a kényelem kedvéért.

Ha olyan webszolgáltatást használ, amely egy REST API-t tesz közzé, akkor szerencséje van – ebben az esetben a rendszer nem használ állandó TCP-kapcsolatokat, bármelyik Kubernetes szolgáltatást használhatja.

De miután elkezdi használni a tartós TCP-kapcsolatokat, ki kell találnia, hogyan lehet egyenletesen elosztani a terhelést a háttérrendszerek között. A Kubernetes erre az esetre nem tartalmaz kész megoldásokat.

Azonban biztosan vannak olyan lehetőségek, amelyek segíthetnek.

A hosszú életű kapcsolatok kiegyensúlyozása Kubernetesben

A Kubernetesben négyféle szolgáltatás létezik:

  1. ClusterIP
  2. Csomópont port
  3. Terhelés elosztó
  4. Fejetlen

Az első három szolgáltatás virtuális IP-címen működik, amelyet a kube-proxy használ az iptables szabályok felépítéséhez. De minden szolgáltatás alapvető alapja a fejetlen szolgáltatás.

A fej nélküli szolgáltatáshoz nem tartozik semmilyen IP-cím, és csak egy mechanizmust biztosít az IP-címek és a hozzá társított podok (végpontok) portjainak lekéréséhez.

Minden szolgáltatás a fej nélküli szolgáltatáson alapul.

A ClusterIP szolgáltatás egy fej nélküli szolgáltatás néhány kiegészítéssel: 

  1. A felügyeleti réteg hozzárendel egy IP-címet.
  2. A Kube-proxy előállítja a szükséges iptables szabályokat.

Így figyelmen kívül hagyhatja a kube-proxyt, és közvetlenül használhatja a fej nélküli szolgáltatásból kapott végpontok listáját az alkalmazás terheléselosztásához.

De hogyan adhatunk hozzá hasonló logikát a fürtben telepített összes alkalmazáshoz?

Ha az alkalmazás már telepítve van, ez a feladat lehetetlennek tűnhet. Van azonban egy alternatív lehetőség.

A Service Mesh segít Önnek

Valószínűleg már észrevette, hogy az ügyféloldali terheléselosztási stratégia meglehetősen szabványos.

Amikor az alkalmazás elindul, akkor:

  1. Lekéri az IP-címek listáját a szolgáltatástól.
  2. Megnyitja és karbantartja a kapcsolati készletet.
  3. Rendszeresen frissíti a készletet végpontok hozzáadásával vagy eltávolításával.

Ha az alkalmazás kérelmet szeretne benyújtani, akkor:

  1. Kiválaszt egy elérhető kapcsolatot valamilyen logika segítségével (pl. körmérkőzés).
  2. Végrehajtja a kérést.

Ezek a lépések WebSockets, gRPC és AMQP kapcsolatok esetén is működnek.

Ezt a logikát külön könyvtárba választhatja, és felhasználhatja alkalmazásaiban.

Ehelyett azonban használhat szolgáltatáshálókat, például az Istio-t vagy a Linkerd-et.

A Service Mesh egy olyan folyamattal egészíti ki az alkalmazást, amely:

  1. Automatikusan megkeresi a szolgáltatás IP-címeit.
  2. Olyan kapcsolatokat tesztel, mint a WebSockets és a gRPC.
  3. Kiegyensúlyozza a kéréseket a megfelelő protokoll használatával.

A Service Mesh segít a fürtön belüli forgalom kezelésében, de meglehetősen erőforrás-igényes. További lehetőségek a harmadik féltől származó könyvtárak, például a Netflix Ribbon vagy a programozható proxyk, például az Envoy használata.

Mi történik, ha figyelmen kívül hagyja az egyensúlyi problémákat?

Dönthet úgy, hogy nem használja a terheléselosztást, és továbbra sem vesz észre semmilyen változást. Nézzünk néhány munkaforgatókönyvet.

Ha több kliensünk van, mint szerverünk, ez nem olyan nagy probléma.

Tegyük fel, hogy öt kliens csatlakozik két szerverhez. Még akkor is, ha nincs egyensúlyozás, mindkét szervert használni fogja:

Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Lehet, hogy a kapcsolatok nem egyenletesen oszlanak el: lehet, hogy négy kliens csatlakozik ugyanahhoz a szerverhez, de jó eséllyel mindkét szervert használni fogják.

A problémásabb az ellenkező forgatókönyv.

Ha kevesebb kliense és több szervere van, előfordulhat, hogy erőforrásai alul vannak kihasználva, és potenciális szűk keresztmetszetek jelennek meg.

Tegyük fel, hogy két kliens és öt szerver van. A legjobb esetben két állandó kapcsolat lesz ötből kettő szerverrel.

A többi szerver tétlen lesz:

Terheléselosztás és hosszú élettartamú kapcsolatok méretezése a Kubernetesben

Ha ez a két szerver nem tudja kezelni az ügyfélkéréseket, a vízszintes méretezés nem segít.

Következtetés

A Kubernetes-szolgáltatásokat úgy tervezték, hogy a legtöbb szabványos webalkalmazás-forgatókönyvben működjenek.

Ha azonban elkezd dolgozni állandó TCP-kapcsolatokat használó alkalmazásprotokollokkal, például adatbázisokkal, gRPC-vel vagy WebSocketekkel, a szolgáltatások már nem alkalmasak. A Kubernetes nem biztosít belső mechanizmusokat az állandó TCP-kapcsolatok kiegyensúlyozására.

Ez azt jelenti, hogy az alkalmazásokat az ügyféloldali kiegyensúlyozás figyelembevételével kell írnia.

A fordítást a csapat készítette Kubernetes aaS a Mail.ru webhelyről.

Mit kell még olvasni a témában:

  1. Az automatikus skálázás három szintje a Kubernetesben és azok hatékony használata
  2. Kubernetes a kalózkodás jegyében egy sablonnal a megvalósításhoz.
  3. Telegram csatornánk a digitális átalakulásról.

Forrás: will.com

Hozzászólás