
See artikkel aitab mõista, kuidas toimub koormuse tasakaalustamine Kuberneteses, mis juhtub pikaajaliste ühenduste skaleerimise ajal ja miks tasub kaaluda kliendi poole tasakaalustamist, kui kasutate HTTP/2, gRPC, RSockets, AMQP või muid pikaajalisi protokolle.
Veidi sellest, kuidas liiklus Kuberneteses jaotatakse
Kubernetes pakub kahte mugavat abstraktsiooni rakenduste juurutamiseks: teenuseid (Services) ja juurutamisi (Deployments).
Juurutamised määratlevad, kui palju koopiad teie rakendusest peaks igal hetkel töötama. Iga rakendus juurutatakse kui pod (Pod) ja sellele määratakse IP-aadress.
Teenuste funktsioonid on sarnased koormuse tasakaalustajaga. Need on mõeldud liikluse jaotamiseks mitme podi vahel.
Vaadakem, kuidas see välja näeb.
- Alloleval diagrammil näete kolme instantsi ühest rakendusest ja koormuse tasakaalustajat:

- Koormuse tasakaalustajat nimetatakse teenuseks (Service) ja sellele on määratud IP-aadress. Iga sissetulev päring suunatakse ühele podidest:

- Juurutamise stsenaarium määrab rakenduse instantside arvu. Te ei pea kunagi otse podi juurutama:

- Igal podil on oma IP-aadress:

On kasulik käsitleda teenuseid kui IP-aadresside kogumit. Iga kord, kui pöördute teenuse poole, valitakse nimekirjast üks IP-aadress ja kasutatakse sihtaadressina.
See näeb välja järgmiselt.
- Saabub päring curl 10.96.45.152 teenusele:

- Teenuse valib ühe kolmest podi aadressist sihtkohaks:

- Liiklus suunatakse konkreetsele podile:

Kui teie rakendus koosneb esiosast ja taustast, siis on kummalgi teenus ja juurutamine.
Kuna esiosa teeb päringu tausta poole, ei pea see teadma, kui palju podi taust teenindab: neid võib olla üks, kümme või sada.
Samuti ei tea esiosa midagi podide aadressidest, mis teenindavad tausta.
Kuna esiosa teeb päringu tausta poole, kasutab see tausta teenuse IP-aadressi, mis ei muutu.
Nii see välja näeb.
- Pod 1 pärib tausta sisekomponendilt. Selle asemel, et valida konkreetne tausta pod, teeb ta päringu teenusele:

- Teenuse valib ühe tausta podi sihtkohaks:

- Liiklus läheb podist 1 podi 5 juurde, mille teenus valis:

- Pod 1 ei tea, kui palju selliseid podi nagu pod 5 teenuse taga on:

Aga kuidas teenus päringuid jaotab? Kas kasutatakse round-robin tasakaalustamist? Uurime.
Tasakaalustamine Kubernetes teenustes
Kubernetes teenused ei eksisteeri. Teenusel ei ole protsessi, millele on määratud IP-aadress ja port.
Saate veenduda, et minge igasse klastrisse ja käivitage käsk netstat -ntlp.
Te isegi ei suuda leida IP-aadressi, mis on teenusele määratud.
Teenuse IP-aadress asub juhtimistasemes, kontrolleris, ja see on salvestatud andmebaasi - etcd. Sama aadressi kasutab ka teine komponent - kube-proxy.
Kube-proxy saab kõikide teenuste IP-aadresside nimekirja ja koostab igal klastris oleval sõlmel iptables reeglite komplekti.
Need reeglid ütlevad: "Kui näeme teenuse IP-aadressi, tuleb muuta päringu sihtaadressi ja suunata see ühe podi juurde."
Teenuse IP-aadressi kasutatakse ainult sisenemispunktina ja seda ei teeninda mingi protsess, mis kuulab seda IP-aadressi ja porti.
Vaadakem seda.
- Tõlgendame klastrit kolmest sõlmest. Igal sõlmel on podid:

- Seotud podid, mis on beežiks värvitud, on teenuse osa. Kuna teenus ei eksisteeri kui protsess, on see kujutatud hallina:

- Esimene pod teeb päringu teenusele ja peab jõudma ühe seotud podi juurde:

- Aga teenust ei eksisteeri, protsessi pole. Kuidas see siis toimib?

- Enne kui päring lahkub sõlmest, läbib see iptables reeglid:

- iptables reeglid teavad, et teenust ei ole, ja asendavad selle IP-aadressi ühe podi IP-aadressiga, mis on seotud sellega teenusega:

- Päring saab kehtiva IP-aadressi sihtaadressina ja töödeldakse normaalselt:

- Sõltuvalt võrgu topoloogiast jõuab päring lõpuks podini:

Kas iptables suudavad koormust tasakaalustada?
Ei, iptables kasutatakse filtreerimise jaoks ja ei ole projekteeritud tasakaalustamiseks.
Siiski on olemas võimalus kirjutada reeglite komplekt, mis toimib nagu .
Ja just seda on Kubernetesis rakendatud.
Kui teil on kolm podi, kirjutab kube-proxy järgmised reeglid:
- Valige esimene pod 33% tõenäosusega, vastasel juhul minge järgmisse reeglisse.
- Valige teine pod 50% tõenäosusega, vastasel juhul minge järgmisse reeglisse.
- Valige kolmas pod.
Selline süsteem toob kaasa, et iga pod valitakse 33% tõenäosusega.

Ja ei ole mingit garantiid, et pod 2 valitakse järgmisena pärast pod 1.
Märkus: iptables kasutab statistilist moodulit juhusliku jaotuse jaoks. Seega põhineb tasakaalustamisalgoritm juhuslikul valikul.
Nüüd, kui mõistate, kuidas teenused töötavad, vaatame huvitavamaid tööstsenaariume.
Pikaajalised ühendused Kuberneteses ei ole vaikimisi skaleeritavad.
Iga HTTP-päring front-endilt back-endile teenindatakse eraldi TCP-ühenduse kaudu, mis avatakse ja suletakse.
Kui front-end saadab back-endile 100 päringut sekundis, avatakse ja suletakse 100 erinevat TCP-ühendust.
Päringu töötlemise aega ja koormust on võimalik vähendada, kui avada üks TCP-ühendus ja kasutada seda kõigi edasiste HTTP-päringute jaoks.
HTTP-protokollis on olemas võimalus, mida nimetatakse HTTP keep-alive'iks, ehk ühenduse taaskasutamiseks. Sel juhul kasutatakse ühte TCP-ühendust paljude HTTP-päringute ja vastuste saatmiseks ja saamiseks:

See võimalus ei ole vaikimisi sisse lülitatud: nii server kui ka klient peavad olema vastavalt konfigureeritud.
Seadistamine on iseenesest lihtne ja kergesti kätte saadav enamikus programmeerimiskeeltes ja keskkondades.
Siin on mõned lingid erinevates keeltes esitluste näidiste juurde:
Mis juhtub, kui kasutame Kuberneteses keep-alive'i?
Oletame, et nii front-end kui ka back-end toetavad keep-alive'i.
Meil on üks front-end'i koopia ja kolm back-end'i instantsi. Front-end teeb esimese päringu ja avab TCP-ühenduse back-end'iga. Päring jõuab teenuseni, üks back-end'i pod valitakse sihtmärgiks. Back-end'i pod saadab vastuse ja front-end saab selle kätte.
Eraldi olukorrast, kus pärast vastuse saamist TCP-ühendus suletakse, hoitakse seda nüüd avatud järgmistele HTTP-päringutele.
Mis juhtub, kui front-end saadab back-end'ile veel päringuid?
Nende päringute edastamiseks kasutatakse avatud TCP-ühendust; kõik päringud jõuavad samasse back-end'i pod'i, kuhu esimene päring sattus.
Kas iptables ei peaks liiklust ümber jagama?
Kuid mitte sel juhul.
TCP-ühenduse loomisel läbib see iptables reegleid, mis valivad konkreetse back-end'i pod'i, kuhu liiklus suunatakse.
Kuna kõik järgmised päringud lähevad juba avatud TCP-ühenduse kaudu, ei kutsuta iptables reegleid enam.
Vaadakem, kuidas see välja näeb.
- Esimene pod saadab päringu teenusele:

- Te juba teate, mis edasi saab. Teenust ei eksisteeri, kuid iptables reeglid töötlevad päringu:

- Üks back-end'i pod'i valitakse sihtmärgiks:

- Päring jõuab pod'i. Sel hetkel luuakse kahe pod'i vahel püsiv TCP-ühendus:

- Kõik järgmised päringud esimesest pod'ist lähevad juba loodud ühenduse kaudu:

Kuna tulemus on kiiremad vastused ja suurem läbilaskevõime, on teil aga kadunud back-end'i skaleerimise võimalus.
Isegi kui teie back-end'is on kaks pod'i, jõuab pideva ühenduse korral liiklus kogu aeg alati ühte neist.
Kas seda saab parandada?
Kuna Kubernetes ei tea, kuidas tasakaalustada pidevaid ühendusi, lasub see ülesanne teie õlul.
Teenused on IP-aadresside ja portide kogum, mida nimetatakse lõpp-punktideks.
Teie rakendus võib teenusest lõpp-punktide nimekirja saada ja otsustada, kuidas neid päringute vahel jagada. Võite avada pideva ühenduse iga pod'iga ja tasakaalustada päringuid nende ühenduste vahel round-robin meetodil.
Või rakendada keerukamaid .
Kliendi küljes olev kood, mis vastutab tasakaalustamise eest, peab järgima sellist loogikat:
- Saada teenusest lõpp-punktide nimekiri.
- Iga lõpp-punkti jaoks avada pidev ühendus.
- Kui on vaja päringut teha, kasutada mõnd avatud ühendust.
- Regulaarselt värskendada lõpp-punktide nimekirja, luua uusi või sulgeda vanu püsivaid ühendusi nimekirja muutumise korral.
Nii see välja näeb..
- Kuna esimene pod ei saada päringut teenusele, võite päringute tasakaalustamise klientide poole teha:

- Tuleb kirjutada kood, mis küsib, millised pod'id teenusesse kuuluvad:

- Kuna olete nimekirja saanud, salvestage see kliendi poole ja kasutage ühendamiseks pod'idega:

- Te vastutate koormuse tasakaalustamise algoritmi eest:

Nüüd on küsimus: kas see probleem puudutab ainult HTTP keep-alive'i?
Koormuse tasakaalustamine kliendi poole.
HTTP — ei ole ainus protokoll, mis suudab kasutada püsivaid TCP-ühendusi.
Kui teie rakendus kasutab andmebaasi, siis TCP-ühendust ei avata iga kord, kui peate päringu täitma või dokumendi andmebaasist saama.
Selle asemel avatakse ja kasutatakse püsivat TCP-ühendust andmebaasiga.
Kui teie andmebaas on väljaspool Kuberneteset ja juurdepääs tehakse teenuse kaudu, siis kohtate samu probleeme, nagu eelnevas osas kirjeldatud.
Üks andmebaasi replika on rohkem koormatud kui teised. Kube-proxy ja Kubernetes ei aita ühenduste tasakaalu. Te peate ise hoolitsema oma andmebaasi päringute tasakaalustamise eest.
Sõltuvalt teie kasutatavast teegist andmebaasi ühendamiseks võivad teil olla erinevad lahendusvõimalused.
Allpool on näide MySQL andmebaasi klastrisse sisenemiseks Node.js-is:
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);
}
// Tee päringud klastrisse MySQL andmebaasiOn palju teisi protokolle, mis kasutavad püsivaid TCP-ühendusi:
- WebSockets ja turvalised WebSockets
- HTTP/2
- gRPC
- RSockets
- AMQP
Te peaksite olema enamiku nende protokollide osas juba tuttav.
Kuid kui need protokollid on nii populaarsed, miks ei ole standardiseeritud lahendust tasakaalustamiseks? Miks on vajalik kliendi loogika muutmine? Kas Kubernetesel on natiivne lahendus?
Kube-proxy ja iptables on loodud selleks, et katta enamik standardseid kasutusstsenaariume Kuberneteses juurutamisel. See on tehtud mugavuse nimel.
Kui kasutate veebiteenust, mis pakub REST API-t, siis olete õnnelik — sel juhul ei kasutata püsivaid TCP-ühendusi, võite kasutada mistahes Kubernetes teenust.
Kuid niipea, kui hakkate kasutama püsivaid TCP-ühendusi, peate välja mõtlema, kuidas koormust võrdselt jaotada back-endide vahel. Kubernetesel ei ole selle jaoks valmis lahendusi.
Kuid loomulikult on olemas võimalusi, mis võivad aidata.
Pikaajaliste ühenduste tasakaalustamine Kuberneteses
Kuberneteses on neli tüüpi teenuseid:
- ClusterIP
- NodePort
- LoadBalancer
- Pealkirjata
Esimese kolme teenuse aluseks on virtuaalne IP-aadress, mida kube-proxy kasutab iptables reeglite kehtestamiseks. Kuid kõikide teenuste põhialus on pealkirjata teenus.
Pealkirjata teenus ei ole seotud ühegi IP-aadressiga ja see pakub ainult mehhanismi, et saada nimekiri IP-aadressidest ja portidest, mis on seotud selle podidega (lõpp-punktid).
Kõik teenused põhinevad pealkirjata teenusel.
ClusterIP teenus on pealkirjata teenus teatud täiendustega:
- Juhtimiskihis määratakse sellele IP-aadress.
- Kube-proxy loob vajalikke iptables reegleid.
Seega saate ignoreerida kube-proxy't ja otse kasutada nimekirja lõpp-punktidest, mis on saadud pealkirjata teenusest, oma rakenduses koormuse tasakaalustamiseks.
Kuid kuidas sellist loogikat lisada kõigile klastris juurutatud rakendustele?
Kui teie rakendus on juba juurutatud, siis võib selline ülesanne tunduda ületamatuna. Kuid on alternatiivne võimalus.
Teenuse mesh aitab teid
Olete ilmselt juba märganud, et koormuse tasakaalustamise strateegia kliendi poolel on üsna standardne.
Kui rakendus käivitub, siis:
- Saab nimekirja IP-aadressidest teenusest.
- Avab ja hoiab ühenduste basseini.
- Aeg-ajalt värskendab basseini, lisades või eemaldades lõpp-punkte.
Niikaua kui rakendus tahab teha päringu, siis:
- Valib saadaval oleva ühenduse, kasutades mingit loogikat (näiteks round-robin).
- Teeb päringu.
Need sammud toimivad nii WebSocketi, gRPC kui ka AMQP ühenduste puhul.
Saate selle loogika eraldi teeki välja tuua ja kasutada seda oma rakendustes.
Kuid selle asemel saate kasutada teenuse mesh'e, näiteks Istio või Linkerd.
Teenuse mesh täiendab teie rakendust protsessiga, mis:
- Otsib automaatselt teenuste IP-aadresse.
- Kontrollib ühendusi, näiteks WebSockets ja gRPC.
- Tasakaalustab päringud, kasutades õiget protokolli.
Teenuse mesh aitab hallata liiklust klastris, kuid see on üsna ressursimahukas. Teised võimalused on kasutada kolmandate osapoolte teeke, näiteks Netflix Ribbon, või programmeeritavaid vahendeid, nagu Envoy.
Mis juhtub, kui ignoreerite tasakaalustamise küsimusi?
Võite mitte kasutada koormuse tasakaalustamist ja siiski mittetähelda mingeid muutusi. Vaadakem mõningaid tööstsenaariume.
Kui teil on rohkem kliente kui servereid, pole see nii suur probleem.
Kujutage ette, et on viis klienti, kes on ühendatud kahe serveriga. Isegi kui tasakaalustamist pole, kasutatakse mõlemaid servereid:

Ühendused võivad olla ebaühtlaselt jagatud: võib juhtuda, et neli klienti on seotud sama serveriga, kuid on suur tõenäosus, et mõlemat serverit kasutatakse.
Rohkem probleeme tekitab aga vastupidine stsenaarium.
Kui teil on vähem kliente ja rohkem servereid, võivad teie ressursid jääda alakasutatud ja tekkida potentsiaalne kitsaskoht.
Oletame, et on kaks klienti ja viis serverit. Parimal juhul on pidevad ühendused kahe serveriga viiest.
Ülejäänud serverid jäävad seisma:

Kui need kaks serverit ei suuda kliente teenindada, ei aita horisontaalne skaleerimine.
Kokkuvõte
Kubernetes teenused on loodud töötama enamikus standardsetes veebirakenduste stsenaariumides.
Kuid kui hakkate tegelema rakenduse protokollidega, mis kasutavad püsivaid TCP-ühendusi, nagu andmebaasid, gRPC või WebSockets, ei ole teenused enam sobivad. Kubernetes ei paku sisemehhanisme püsivate TCP-ühenduste laadimise tasakaalustamiseks.
See tähendab, et peate kirjutama rakendusi, arvestades kliendi poole tasakaalustamise võimalust.
Tõlge on koostatud meeskonna poolt .
Mida veel teemast lugeda:
- .
- .
- .
Allikas: habr.com




























