
See artikkel aitab mõista, kuidas toimib koormuse tasakaalustamine Kuberneteses, mis juhtub pikaajaliste ühenduste skaleerimisel ja miks tasub kaaluda kliendi poolel tasakaalustamist, kui kasutate HTTP/2, gRPC, RSockets, AMQP või muid pikaajalisi protokolle.
Veidi sellest, kuidas liiklus Kuberneteses ümber jaotatakse
Kubernetes pakub kahte mugavat abstraktsiooni rakenduste välja tootmiseks: teenused (Services) ja juurutamised (Deployments).
Juurutamised määratlevad, kuidas ja kui palju teie rakenduse koopiaid peaks olema käimas igal hetkel. Iga rakendus käivitatakse kui pod (Pod) ja sellele määratakse IP-aadress.
Teenused on funktsioonidelt sarnased koormuse tasakaalustajaga. Need on mõeldud liikluse jaotamiseks mitme podi vahel.
Vaatame, kuidas see välja näeb.
- Alloleval joonisel näete kolme sama rakenduse instantsi ja koormuse tasakaalustajat:

- Koormuse tasakaalustajat nimetatakse teenuseks (Service), sellele on määratud IP-aadress. Iga sisenev päring suunatakse ühele podile:

- Juurutusstsenaarium määrab rakenduse instantside arvu. Peaaegu kunagi ei pea te podi otse juurutama:

- Igal podil on oma IP-aadress:

On kasulik mõista teenuseid kui IP-aadresside kogumit. Iga kord, kui pöördute teenuse poole, valitakse nimekirjast üks IP-aadress ja seda kasutatakse sihtadressina.
See näeb välja järgmine.
- Päring curl 10.96.45.152 teenusele tuleb:

- Teenuse valib sihtkohaks ühe kolmest podi aadressist:

- Liiklus suunatakse konkreetsele podile:

Kui teie rakendus koosneb esiosas ja tagaküljest, siis on teil igaühe jaoks teenus ja juurutamine.
Kui esiosa teeb päringu tagaküljele, ei pea tal teadma, kui palju podisid tagumine osa teenindab: neid võib olla üks, kümme või sada.
Samuti ei tea esiosa midagi tagumise poole podide aadressidest.
Kui esiosa teeb päringu tagaküljele, kasutab ta tagumise teenuse IP-aadressi, mis ei muutu.
Nii see välja näeb.
- Pod 1 palub tagumise poole sisekomponenti. Selle asemel, et valida kindel tagumise poole pod, teeb ta päringu teenusele:

- Teenus valib ühe tagapaneeli podi sihtadressiks:

- Läbi on liiklus podi 1 ja teenuse poolt valitud podi 5 vahel:

- Podi 1 ei tea, kui paljusid podisid, nagu pod 5, teenuse taga on:

Aga kuidas teenus päringuid jagab? Kas tundub, et kasutatakse round-robin tasakaalustamist? Uurime lähemalt.
Tasakaalustamine Kubernetes tegevustes
Kubernetes teenused ei eksisteeri. Teenusel ei ole protsessi, millele on määratud IP-aadress ja port.
Selle veendumiseks võite siseneda mistahes klastrinoodi ja käivitada käsu netstat -ntlp.
Te isegi ei suuda leida teenusele määratud IP-aadressi.
Teenuse IP-aadress on haldustasandil, kontrolleris, ja salvestatud andmebaasi — etcd. Seda aadressi kasutab veel üks komponent — kube-proxy.
Kube-proxy saab nimekirja IP-aadressidest kõigile teenustele ja koostab igas klastrinoode iptables reeglite kogumi.
Need reeglid ütlevad: "Kui näeme teenuse IP-aadressi, peame muutma päringu sihtaadressi ja suunama selle ühe seotud podi juurde."
Teenuse IP-aadressi kasutatakse ainult sissepääsupunktina ja seda ei halda ükski protsess, mis kuulab selle IP-aadressi ja porti.
Vaadakem seda.
- Vaatame kolmest noodist koosnevat klastrit. Igas noodis on podid:

- Seotud podid, millel on beež värv, on teenuse osa. Kuna teenust ei eksisteeri protsessina, on see kujutatud hallina:

- Esimene pod küsib teenust ja peab jõudma ühe seotud podi juurde:

- Kuid teenus ei eksisteeri, protsessi pole. Kuidas see toimib?

- Enne kui päring lahkub noodist, läbib see iptables reeglid:

- Iptables reeglid teavad, et teenust ei ole, ja asendavad selle IP-aadressi ühega podide IP-aadressidest, mis on seotud selle teenusega:

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

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

Kas iptables suudavad tasakaalu hoida?
Ei, iptables kasutatakse filtrimiseks ja ei ole loodud tasakaalustamiseks.
Kuid on võimalus kirjutada reeglite kogum, 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, muidu liikuda järgmise reegli juurde.
- Vali teine pod 50% tõenäosusega, vastasel juhul mine järgmise reegli juurde.
- Vali kolmas pod.
Selline süsteem toob kaasa selle, et iga pod valitakse 33% tõenäosusega.

Ja ei ole garantiid, et pod 2 valitakse järgmiseks pärast podi 1.
Märkus: iptables kasutab statistilist moodulit juhusliku jaotuse jaoks. Seega põhineb tasakaalustamise algoritm juhuslikul valikul.
Nüüd, kui sa mõistad, kuidas teenused töötavad, vaatame huvitavamaid tööstsenaariume.
Pikad ühendused Kuberneteses ei skaala vaikimisi.
Iga HTTP-päring esiosast tagasiside poole teenindatud eraldi TCP-ühenduse kaudu, mis avatakse ja suletakse.
Kui esiosa saadab tagasiside poolele 100 päringut sekundis, avatakse ja suletakse 100 erinevat TCP-ühendust.
Päringu töötlemise aega on võimalik vähendada ja koormust alandada, kui avada üks TCP-ühendus ja kasutada seda kõigi järgneva HTTP-päringu jaoks.
HTTP-protokollis on võimalus, mida nimetatakse HTTP keep-alive'iks või ühenduse taaskasutamiseks. Sel juhul kasutatakse ühte TCP-ühendust paljude HTTP-päringute ja vastuste saatmiseks ja vastuvõtmiseks:

See võimalus ei ole vaikimisi sisse lülitatud: nii server kui ka klient peavad olema vastavalt seadistatud.
Seadistamine iseenesest on lihtne ja kergesti kergesti kättesaadav enamikule programmeerimiskeeltele ja keskkondadele.
Siin on mõned lingid erinevate keelte näidetele:
Mis juhtub, kui kasutame keep-alive'i Kuberneteses?
Oletame, et nii esi- kui tagasiside toetavad keep-alive'i.
Meil on üks eesmine koopia ja kolm tagapoolset eksemplari. Eesmine teeb esimese päringu ja avab TCP-ühenduse tagasiside poolega. Päring jõuab teenuseni, üks tagapool valitakse sihtmärgiks. Tagapool saadab vastuse ja eesmine saab selle kätte.
Erinevalt tavalisest olukorrast, kus pärast vastuse saamist TCP-ühendus suletakse, hoitakse nüüd see avatud järgmiste HTTP-päringute jaoks.
Mis juhtub, kui eesmine saadab veel päringud tagasiside poolele?
Nende päringute edastamiseks kasutatakse avatud TCP-ühendust, kõik päringud jõuavad samasse tagapooli, kuhu esimene päring jõudis.
Kas iptables ei peaks juurduks ära jaotama liiklust?
Mitteametlikul juhul.
Kui TCP-ühendus luuakse, läbib see iptables reegleid, mis valivad, millisesse tagabäkkidesse liiklus suunatakse.
Kuna kõik järgmised päringud lähevad juba avatud TCP-ühenduse kaudu, ei kutsuta iptables reegleid enam välja.
Vaatame, kuidas see välja näeb.
- Esimene pod saadab päringu teenusele:

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

- Üks tagabäkkide podidest valitakse sihtkohaks:

- Päring jõuab podi. Sel hetkel luuakse kahe poda vahel püsiv TCP-ühendus:

- Iga järgmine päring esimesest podist läheb juba loodud ühenduse kaudu:

Seega saate kiirema vastuse ja kõrgema läbilaskevõime, kuid peate loobuma tagabäkkide skaleeritavusest.
Ieven kui tagabäkkides on kaks poda, liigub pidev ühendus alati ühe neist.
Kas seda on võimalik parandada?
Kuna Kubernetes ei tea, kuidas tasakaalustada püsivaid ühendusi, on see ülesanne antud teile.
Teenused on komplekt IP-aadresse ja porte, mida nimetatakse lõpp-punktideks.
Teie rakendus saab teenusest lõpp-punktide nimekirja ja otsustab, kuidas päringud nende vahel jagada. Võimalik on avada püsiv ühendus iga podiga ja tasakaalustada päringud nende ühenduste vahel round-robin meetodiga.
Või rakendada keerukamaid .
Kliendi poolel olev kood, mis vastutab tasakaalustamise eest, peaks järgima järgmist loogikat:
- Saada lõpp-punktide nimekiri teenusest.
- Iga lõpp-punkti jaoks luua püsiv ühendus.
- Kui on vaja teha päring, kasutada ühte avatud ühendust.
- Regulaarselt värskendada lõpp-punktide nimekirja, luua uusi või sulgeda vanu püsivaid ühendusi nimekirja muutumisel.
Nii see välja näeb:.
- Kohaliku podi päringu saatmise asemel võite tasakaalustada päringud kliendi poolel:

- Tuleb kirjutada kood, mis küsib, millised podid kuuluvad teenusesse:

- Kui olete nimekirja saanud, salvestage see kliendi poolel ja kasutage podidega ühenduse loomiseks:

- Te olete ise vastutav koormuse tasakaalustamise algoritmi eest:

Nüüd kerkib küsimus: kas see probleem puudutab ainult HTTP keep-alive'i?
Klient-poolne koormuse tasakaalustamine
HTTP ei ole ainus protokoll, mis võib kasutada püsinud TCP-ühendusi.
Kui teie rakendus kasutab andmebaasi, ei avata TCP-ühendust iga kord, kui peate päringu esitama või dokumendi andmebaasist saama.
Selle asemel avatakse ja kasutatakse püsiv TCP-ühendus andmebaasiga.
Kui teie andmebaas on eraldatud Kuberneteses ja juurdepääs antakse teenuse kaudu, siis puutute kokku samu probleemidega, nagu eelnevas osas kirjeldatud.
Üks andmebaasi koopia on rohkem koormatud kui teised. Kube-proxy ja Kubernetes ei aita ühendusi tasakaalustada. Te peate hoolitsema oma andmebaasile esitatud päringute tasakaalustamise eest.
Tuginedes sellele, millist raamatukogu te andmebaasi ühendamiseks kasutate, võivad teil olla erinevad lahenduse variandid.
Allpool on näide MySQL andmebaasi klastrisse pääsemiseks Node.js'ist:
var mysql = require('mysql');
var poolCluster = mysql.createPoolCluster();
var endpoints = /* get endpoints from the Service */
for (var [index, endpoint] of endpoints) {
poolCluster.add(`mysql-replica-${index}`, endpoint);
}
// Esitage päringud klastrisse kuuluvale MySQL andmebaasileOn palju teisi protokolle, mis kasutavad püsinud TCP-ühendusi:
- WebSocket ja turvatud WebSocketid
- HTTP/2
- gRPC
- RSocketid
- AMQP
Te peaksite olema tutvunud enamikuga neist protokollidest.
Aga kui need protokollid on nii populaarsed, siis miks ei ole standardiseeritud lahendust tasakaalustamiseks? Miks peab klienti loogikat muutma? Kas Kubernetesel on natiivne lahendus?
Kube-proxy ja iptables on loodud sulgema enamik standardseid kasutusstsenaariume Kuberneteses rakendamisel. See on tehtud mugavuse lahendamiseks.
Kui kasutate veebiteenust, mis pakub REST API-d, siis olete õnnelik — sel juhul püsinud TCP-ühendusi ei kasutata, saate kasutada mis tahes Kubernetes teenust.
Kuid kui hakkate kasutama püsinud TCP-ühendusi, peate välja selgitama, kuidas koormust tasakaalustada backendide vahel. Kubernetes ei sisalda selle jaoks valmis lahendusi.
Küll aga on olemas variandid, mis võivad aidata.
Pikaajaliste ühenduste tasakaalustamine Kuberneteses
Kuberneteses on neli tüüpi teenuseid:
- ClusterIP
- NodePort
- LoadBalancer
- Pea-ühendus
Kolme esimest teenust töötavad virtuaalse IP-aadressi baasil, mida kube-proxy kasutab iptables'i reeglite koostamiseks. Kuid kõigi teenuste põhiidee on headless teenus.
Headless teenusega ei ole seotud ühtegi IP-aadressi ja see pakub ainult mehhanismi, et saada loend seotud podide IP-aadressidest ja sadamatest (lõpp-punktidest).
Kõik teenused põhinevad headless teenusel.
ClusterIP teenus on headless teenus teatud lisanditega:
- Halduse kiht määrab sellele IP-aadressi.
- Kube-proxy koostab vajalikud iptables'i reeglid.
Seega võite ignoreerida kube-proxy't ja kasutada otse headless teenusest saadud lõpp-punktide loendit koormuse jagamiseks oma rakenduses.
Kuidas lisada sellist loogikat kõigisse klastrisse paigaldatud rakendustesse?
Kui teie rakendus on juba paigaldatud, võib see ülesanne tunduda ületamatuna. Kuid on olemas alternatiivne lahendus.
Service Mesh aitab teid.
Olete võib-olla juba märganud, et kliendipoolne koormuse jagamise strateegia on üsna standardne.
Kui rakendus käivitub, siis:
- Saab teenusest IP-aadresside loendi.
- Avab ja hoiab ühenduste tanti.
- Aeg-ajalt värskendab tanti, lisades või eemaldades lõpp-punkte.
Kui rakendus soovib teha päringu, siis:
- Valib saadaval oleva ühenduse, kasutades mingit loogikat (näiteks round-robin).
- Teeb päringu.
Need sammud töötavad nii WebSocketi kui ka gRPC ja AMQP ühenduste jaoks.
Saate selle loogika eraldi teeki välja tõsta ja kasutada oma rakendustes.
Siiski on võimalik kasutada teenuse võrke, näiteks Istio või Linkerd.
Service Mesh täiendab teie rakendust protsessiga, mis:
- Otsib automaatselt teenuste IP-aadresse.
- Kontrollib ühendusi, nagu WebSocketid ja gRPC.
- Jagab päringud, kasutades õiget protokolli.
Service Mesh aitab hallata liiklust klastris, kuid see on üsna ressursimahukas. Teised variandid on kolmandate osapoolte raamatukogude kasutamine, nagu Netflix Ribbon, või programmeeritavad pöördproksid, nagu Envoy.
Mida juhtub, kui ignoreerida koormuse jagamise küsimusi?
Te võite mitte kasutada koormuse jagamist ja siiski mingeid muutusi mitte märgata. Vaadakem mõningaid tööstsenaariume.
Kui teil on rohkem kliente kui servereid, ei ole see nii suur probleem.
Oletame, et on viis klienti, kes ühenduvad kahe serveriga. Isegi kui tasakaalustust ei ole, kasutatakse mõlemat serverit:

Ühendused võivad olla ebaühtlaselt jaotatud: võib juhtuda, et neli klienti on ühinenud samasse serverisse, kuid on hea võimalus, et mõlemat serverit kasutatakse.
Küll aga on probleemsem vastupidine stsenaarium.
Kui teil on vähem kliente ja rohkem servereid, võivad teie ressursid jääda piisavalt kasutamata ning see toob endaga kaasa võimaliku kitsaskoha.
Oletame, et on kaks klienti ja viis serverit. Parimal juhul on kaks pidevat ühendust kahe serveriga viiest.
Ülejäänud serverid jäävad seisma:

Kui need kaks serverit ei suuda klientide päringute töötlemisega hakkama saada, ei aita horisontaalne skaleerimine.
Kokkuvõte
Kubernetes teenused on loodud töötama enamikus veebirakenduste standardsetes stsenaariumides.
Siiski, niipea kui hakkate töötama rakendusprotokollidega, mis kasutavad pidevaid TCP ühendusi, nagu andmebaasid, gRPC või WebSocketid, ei sobi teenused enam. Kubernetes ei paku seadmevahelist mehhanismi pidevate TCP-ühenduste tasakaalustamiseks.
See tähendab, et peate kirjutama rakendusi, arvestades kliendipoolse tasakaalustamise võimalust.
Tõlge on koostatud meeskonna poolt .
Mida veel selle kohta lugeda:
- .
- .
- .
Allikas: habr.com




























