Lasbalansering en skaal langlewende verbindings in Kubernetes

Lasbalansering en skaal langlewende verbindings in Kubernetes
Hierdie artikel sal jou help om te verstaan ​​hoe lasbalansering in Kubernetes werk, wat gebeur wanneer langlewende verbindings skaal en hoekom jy kliënt-kant balansering moet oorweeg as jy HTTP/2, gRPC, RSockets, AMQP of ander langlewende protokolle gebruik . 

'n Bietjie oor hoe verkeer in Kubernetes herverdeel word 

Kubernetes bied twee gerieflike abstraksies vir die implementering van toepassings: Dienste en Ontplooiings.

Ontplooiings beskryf hoe en hoeveel kopieë van jou toepassing op enige gegewe tydstip moet loop. Elke toepassing word as 'n Pod ontplooi en word 'n IP-adres toegeken.

Dienste is soortgelyk in funksie aan 'n lasbalanseerder. Hulle is ontwerp om verkeer oor verskeie peule te versprei.

Kom ons kyk hoe dit lyk.

  1. In die diagram hieronder kan jy drie gevalle van dieselfde toepassing en 'n lasbalanseerder sien:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  2. Die lasbalanseerder word 'n diens genoem en word 'n IP-adres toegeken. Enige inkomende versoek word na een van die peule herlei:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  3. Die ontplooiingscenario bepaal die aantal gevalle van die toepassing. Jy sal amper nooit direk hoef uit te brei onder:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  4. Elke peul kry sy eie IP-adres:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

Dit is nuttig om aan dienste te dink as 'n versameling IP-adresse. Elke keer as jy toegang tot die diens kry, word een van die IP-adresse uit die lys gekies en as die bestemmingsadres gebruik.

Dit lyk so.

  1. 'n Krul 10.96.45.152-versoek word aan die diens ontvang:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  2. Die diens kies een van drie pod-adresse as die bestemming:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  3. Verkeer word na 'n spesifieke peul herlei:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

As u toepassing uit 'n voorkant en 'n agterkant bestaan, sal u beide 'n diens en 'n ontplooiing vir elkeen hê.

Wanneer die frontend 'n versoek aan die backend rig, hoef dit nie presies te weet hoeveel peule die backend bedien nie: daar kan een, tien of honderd wees.

Die voorkant weet ook niks van die adresse van die peule wat die agterkant bedien nie.

Wanneer die frontend 'n versoek aan die backend rig, gebruik dit die IP-adres van die backend-diens, wat nie verander nie.

Dit is hoe dit lyk.

  1. Onder 1 versoek die interne backend-komponent. In plaas daarvan om 'n spesifieke een vir die agterkant te kies, rig dit 'n versoek aan die diens:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  2. Die diens kies een van die backend-peule as die bestemmingsadres:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  3. Verkeer gaan van Pod 1 na Pod 5, gekies deur die diens:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  4. Onder 1 weet nie presies hoeveel peule soos onder 5 agter die diens versteek is nie:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

Maar presies hoe versprei die diens versoeke? Dit wil voorkom asof round-robin-balansering gebruik word? Kom ons vind dit uit. 

Balansering in Kubernetes-dienste

Kubernetes-dienste bestaan ​​nie. Daar is geen proses vir die diens wat 'n IP-adres en poort toegeken is nie.

U kan dit verifieer deur by enige nodus in die groep aan te meld en die netstat -ntlp-opdrag uit te voer.

Jy sal nie eers die IP-adres wat aan die diens toegeken is, kan vind nie.

Die diens se IP-adres is geleë in die beheerlaag, in die kontroleerder, en aangeteken in die databasis - ens. Dieselfde adres word deur 'n ander komponent gebruik - kube-proxy.
Kube-proxy ontvang 'n lys van IP-adresse vir alle dienste en genereer 'n stel iptables-reëls op elke nodus in die groepering.

Hierdie reëls sê: "As ons die IP-adres van die diens sien, moet ons die bestemmingsadres van die versoek verander en dit na een van die peule stuur."

Die diens-IP-adres word slegs as 'n toegangspunt gebruik en word nie bedien deur enige proses wat na daardie IP-adres en poort luister nie.

Kom ons kyk hierna

  1. Oorweeg 'n groep van drie nodusse. Elke nodus het peule:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  2. Gebinde peule wat beige geverf is, is deel van die diens. Omdat die diens nie as 'n proses bestaan ​​nie, word dit in grys getoon:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  3. Die eerste peul versoek 'n diens en moet na een van die geassosieerde peule gaan:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  4. Maar die diens bestaan ​​nie, die proses bestaan ​​nie. Hoe werk dit?

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  5. Voordat die versoek die nodus verlaat, gaan dit deur die iptables-reëls:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  6. Die iptables-reëls weet dat die diens nie bestaan ​​nie en vervang sy IP-adres met een van die IP-adresse van die peule wat met daardie diens geassosieer word:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  7. Die versoek ontvang 'n geldige IP-adres as die bestemmingsadres en word normaalweg verwerk:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  8. Afhangende van die netwerktopologie, bereik die versoek uiteindelik die peul:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

Kan iptables laaibalans laai?

Nee, iptables word vir filtering gebruik en is nie ontwerp vir balansering nie.

Dit is egter moontlik om 'n stel reëls te skryf wat werk soos pseudo-balanseerder.

En dit is presies wat in Kubernetes geïmplementeer word.

As jy drie peule het, sal kube-proxy die volgende reëls skryf:

  1. Kies die eerste sub met 'n waarskynlikheid van 33%, anders gaan na die volgende reël.
  2. Kies die tweede een met 'n waarskynlikheid van 50%, anders gaan na die volgende reël.
  3. Kies die derde onder.

Hierdie stelsel lei daartoe dat elke peul gekies word met 'n waarskynlikheid van 33%.

Lasbalansering en skaal langlewende verbindings in Kubernetes

En daar is geen waarborg dat Pod 2 volgende na Pod 1 gekies sal word nie.

Let daarop: iptables gebruik 'n statistiese module met ewekansige verspreiding. Die balanseringsalgoritme is dus gebaseer op ewekansige seleksie.

Noudat jy verstaan ​​hoe dienste werk, kom ons kyk na meer interessante diensscenario's.

Langlewende verbindings in Kubernetes skaal nie by verstek nie

Elke HTTP-versoek van die frontend na die backend word bedien deur 'n aparte TCP-verbinding, wat oop- en toegemaak word.

As die frontend 100 versoeke per sekonde na die backend stuur, word 100 verskillende TCP-verbindings oop- en toegemaak.

U kan versoekverwerkingstyd en -lading verminder deur een TCP-verbinding oop te maak en dit vir alle daaropvolgende HTTP-versoeke te gebruik.

Die HTTP-protokol het 'n kenmerk genaamd HTTP keep-alive, of verbinding hergebruik. In hierdie geval word 'n enkele TCP-verbinding gebruik om verskeie HTTP-versoeke en -antwoorde te stuur en te ontvang:

Lasbalansering en skaal langlewende verbindings in Kubernetes

Hierdie kenmerk is nie by verstek geaktiveer nie: beide die bediener en kliënt moet dienooreenkomstig gekonfigureer word.

Die opstelling self is eenvoudig en toeganklik vir die meeste programmeertale en omgewings.

Hier is 'n paar skakels na voorbeelde in verskillende tale:

Wat gebeur as ons Keep-alive in 'n Kubernetes-diens gebruik?
Kom ons neem aan dat beide die voorkant en agterkant aan die lewe hou.

Ons het een kopie van die voorkant en drie kopieë van die agterkant. Die frontend maak die eerste versoek en maak 'n TCP-verbinding na die backend oop. Die versoek bereik die diens, een van die backend-peule word as die bestemmingsadres gekies. Die backend stuur 'n antwoord, en die frontend ontvang dit.

Anders as die gewone situasie waar die TCP-verbinding gesluit word nadat 'n antwoord ontvang is, word dit nou oopgehou vir verdere HTTP-versoeke.

Wat gebeur as die voorkant meer versoeke na die agterkant stuur?

Om hierdie versoeke aan te stuur, sal 'n oop TCP-verbinding gebruik word, alle versoeke sal na dieselfde agterkant gaan waar die eerste versoek gegaan het.

Moet iptables nie die verkeer herverdeel nie?

Nie in hierdie geval nie.

Wanneer 'n TCP-verbinding geskep word, gaan dit deur iptables-reëls, wat 'n spesifieke agterkant kies waarheen die verkeer sal gaan.

Aangesien alle daaropvolgende versoeke op 'n reeds oop TCP-verbinding is, word die iptables-reëls nie meer opgeroep nie.

Kom ons kyk hoe dit lyk.

  1. Die eerste peul stuur 'n versoek aan die diens:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  2. Jy weet reeds wat volgende gaan gebeur. Die diens bestaan ​​nie, maar daar is iptables-reëls wat die versoek sal verwerk:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  3. Een van die backend-peule sal gekies word as die bestemmingsadres:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  4. Die versoek bereik die peul. Op hierdie stadium sal 'n aanhoudende TCP-verbinding tussen die twee peule tot stand gebring word:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  5. Enige daaropvolgende versoek van die eerste pod sal deur die reeds gevestigde verbinding gaan:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

Die resultaat is vinniger reaksietyd en hoër deurset, maar jy verloor die vermoë om die agterkant te skaal.

Selfs as jy twee peule in die agterkant het, met 'n konstante verbinding, sal verkeer altyd na een van hulle gaan.

Kan dit reggemaak word?

Aangesien Kubernetes nie weet hoe om aanhoudende verbindings te balanseer nie, val hierdie taak op jou.

Dienste is 'n versameling IP-adresse en poorte wat eindpunte genoem word.

Jou aansoek kan 'n lys eindpunte van die diens kry en besluit hoe om versoeke tussen hulle te versprei. Jy kan 'n aanhoudende verbinding met elke peul oopmaak en versoeke tussen hierdie verbindings balanseer met behulp van round-robin.

Of pas meer toe komplekse balanseringsalgoritmes.

Die kliënt-kant kode wat verantwoordelik is vir balansering moet hierdie logika volg:

  1. Kry 'n lys van eindpunte van die diens.
  2. Maak 'n aanhoudende verbinding vir elke eindpunt oop.
  3. Wanneer 'n versoek gedoen moet word, gebruik een van die oop verbindings.
  4. Werk gereeld die lys eindpunte op, skep nuwes of maak ou aanhoudende verbindings toe as die lys verander.

Dit is hoe dit sal lyk.

  1. In plaas daarvan dat die eerste peul die versoek na die diens stuur, kan u versoeke aan die kliëntkant balanseer:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  2. Jy moet kode skryf wat vra watter peule deel van die diens is:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  3. Sodra jy die lys het, stoor dit aan die kliëntkant en gebruik dit om aan die peule te koppel:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

  4. Jy is verantwoordelik vir die lasbalanseringsalgoritme:

    Lasbalansering en skaal langlewende verbindings in Kubernetes

Nou ontstaan ​​die vraag: is hierdie probleem net van toepassing op HTTP keep-alive?

Kliënt-kant lasbalansering

HTTP is nie die enigste protokol wat volgehoue ​​TCP-verbindings kan gebruik nie.

As jou toepassing 'n databasis gebruik, word 'n TCP-verbinding nie elke keer oopgemaak as jy 'n versoek moet rig of 'n dokument van die databasis moet haal nie. 

In plaas daarvan word 'n aanhoudende TCP-verbinding met die databasis oopgemaak en gebruik.

As jou databasis op Kubernetes ontplooi word en toegang as 'n diens verskaf word, sal jy dieselfde probleme ondervind wat in die vorige afdeling beskryf is.

Een databasis replika sal meer gelaai wees as die ander. Kube-proxy en Kubernetes sal nie help om verbindings te balanseer nie. U moet sorg dat u die navrae na u databasis balanseer.

Afhangende van watter biblioteek jy gebruik om aan die databasis te koppel, kan jy verskillende opsies hê om hierdie probleem op te los.

Hieronder is 'n voorbeeld van toegang tot 'n MySQL-databasiskluster vanaf 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

Daar is baie ander protokolle wat aanhoudende TCP-verbindings gebruik:

  • WebSockets en veilige WebSockets
  • HTTP / 2
  • gRPC
  • Rsokke
  • AMQP

Jy behoort reeds vertroud te wees met die meeste van hierdie protokolle.

Maar as hierdie protokolle so gewild is, hoekom is daar nie 'n gestandaardiseerde balanseringsoplossing nie? Waarom moet die kliëntlogika verander? Is daar 'n inheemse Kubernetes-oplossing?

Kube-proxy en iptables is ontwerp om die mees algemene gebruiksgevalle te dek wanneer dit na Kubernetes ontplooi word. Dit is vir gerief.

As jy 'n webdiens gebruik wat 'n REST API blootstel, is jy gelukkig - in hierdie geval word volgehoue ​​TCP-verbindings nie gebruik nie, jy kan enige Kubernetes-diens gebruik.

Maar sodra jy begin om aanhoudende TCP-verbindings te gebruik, sal jy moet uitvind hoe om die las eweredig oor die backends te versprei. Kubernetes bevat nie klaargemaakte oplossings vir hierdie saak nie.

Daar is egter beslis opsies wat kan help.

Balansering van langlewende verbindings in Kubernetes

Daar is vier tipes dienste in Kubernetes:

  1. ClusterIP
  2. NodePort
  3. LoadBalancer
  4. onthoofde

Die eerste drie dienste werk gebaseer op 'n virtuele IP-adres, wat deur kube-proxy gebruik word om iptables-reëls te bou. Maar die fundamentele basis van alle dienste is 'n koplose diens.

Die koplose diens het geen IP-adres wat daarmee geassosieer word nie en verskaf slegs 'n meganisme om 'n lys van IP-adresse en poorte van die peule (eindpunte) wat daarmee geassosieer word, op te haal.

Alle dienste is gebaseer op die koplose diens.

Die ClusterIP-diens is 'n koplose diens met 'n paar toevoegings: 

  1. Die bestuurslaag ken 'n IP-adres daaraan toe.
  2. Kube-proxy genereer die nodige iptables-reëls.

Op hierdie manier kan jy kube-proxy ignoreer en die lys eindpunte wat van die koplose diens verkry is, direk gebruik om jou aansoek te laai.

Maar hoe kan ons soortgelyke logika by alle toepassings wat in die groepering ontplooi word, byvoeg?

As jou toepassing reeds ontplooi is, kan hierdie taak onmoontlik lyk. Daar is egter 'n alternatiewe opsie.

Service Mesh sal jou help

U het waarskynlik al opgemerk dat die kliënt-kant-lasbalanseringstrategie redelik standaard is.

Wanneer die toepassing begin, dit:

  1. Kry 'n lys van IP-adresse van die diens.
  2. Maak 'n verbindingspoel oop en hou dit in stand.
  3. Dateer die swembad periodiek op deur eindpunte by te voeg of te verwyder.

Sodra die aansoek 'n versoek wil rig, dit:

  1. Kies 'n beskikbare verbinding met behulp van een of ander logika (bv. round-robin).
  2. Voer die versoek uit.

Hierdie stappe werk vir beide WebSockets-, gRPC- en AMQP-verbindings.

Jy kan hierdie logika in 'n aparte biblioteek skei en dit in jou toepassings gebruik.

U kan egter eerder diensnetwerke soos Istio of Linkerd gebruik.

Service Mesh vul jou aansoek aan met 'n proses wat:

  1. Soek outomaties vir diens IP-adresse.
  2. Toets verbindings soos WebSockets en gRPC.
  3. Balanseer versoeke deur die korrekte protokol te gebruik.

Service Mesh help om verkeer binne die groepering te bestuur, maar dit is redelik hulpbron-intensief. Ander opsies is om derdeparty-biblioteke soos Netflix Ribbon of programmeerbare gevolmagtigdes soos Envoy te gebruik.

Wat gebeur as jy balanseringskwessies ignoreer?

Jy kan kies om nie lasbalansering te gebruik nie en steeds geen veranderinge opmerk nie. Kom ons kyk na 'n paar werkscenario's.

As jy meer kliënte as bedieners het, is dit nie so 'n groot probleem nie.

Kom ons sê daar is vyf kliënte wat aan twee bedieners koppel. Selfs al is daar geen balansering nie, sal beide bedieners gebruik word:

Lasbalansering en skaal langlewende verbindings in Kubernetes

Verbindings is dalk nie eweredig versprei nie: miskien vier kliënte wat aan dieselfde bediener gekoppel is, maar daar is 'n goeie kans dat albei bedieners gebruik sal word.

Wat meer problematies is, is die teenoorgestelde scenario.

As jy minder kliënte en meer bedieners het, kan jou hulpbronne onderbenut word en 'n potensiële bottelnek sal verskyn.

Kom ons sê daar is twee kliënte en vyf bedieners. In die beste geval sal daar twee permanente verbindings met twee uit vyf bedieners wees.

Die oorblywende bedieners sal ledig wees:

Lasbalansering en skaal langlewende verbindings in Kubernetes

As hierdie twee bedieners nie kliëntversoeke kan hanteer nie, sal horisontale skaal nie help nie.

Gevolgtrekking

Kubernetes-dienste is ontwerp om in die meeste standaard webtoepassingscenario's te werk.

Sodra jy egter begin werk met toepassingsprotokolle wat aanhoudende TCP-verbindings gebruik, soos databasisse, gRPC of WebSockets, is dienste nie meer geskik nie. Kubernetes verskaf nie interne meganismes om volgehoue ​​TCP-verbindings te balanseer nie.

Dit beteken dat jy aansoeke moet skryf met kliënt-kant-balansering in gedagte.

Vertaling voorberei deur die span Kubernetes aaS van Mail.ru.

Wat anders om te lees oor die onderwerp:

  1. Drie vlakke van outoskaal in Kubernetes en hoe om dit effektief te gebruik
  2. Kubernetes in die gees van seerowery met 'n sjabloon vir implementering.
  3. Ons Telegram-kanaal oor digitale transformasie.

Bron: will.com

Voeg 'n opmerking