
Nota traducătorului.: acest ciclu a fost dedicat familiarizării cu posibilitățile Istio și demonstrarea acestora în acțiune. Acum, vom discuta despre aspecte mai complexe ale configurației și utilizării acestui service mesh, în special despre rutarea fină și gestionarea traficului de rețea.
Amintim de asemenea că articolul folosește configurații (manifesturi pentru Kubernetes și Istio) din depozitul .
Gestionarea traficului
Cu Istio, în cluster apar noi posibilități care permit:
- Rutarea dinamică a cererilor: lansări canar, testare A/B;
- Încărcarea echilibrului: simplă și consistentă, bazată pe hash-uri;
- Recuperarea după colapsuri: timeout-uri, încercări repetate, circuit breakers;
- Introducerea erorilor: întârzieri, întreruperi ale cererilor etc.
În continuarea articolului, aceste posibilități vor fi demonstrate pe exemplul unei aplicații selectate și, în același timp, vor fi prezentate noi concepte. Prima astfel de concept va fi DestinationRules (adică reguli despre destinatarul traficului/cererilor — n.r.), prin care activăm testarea A/B.
Testarea A/B: DestinationRules în practică
Testarea A/B se aplică în cazurile în care există două versiuni ale aplicației (de obicei, acestea diferă vizual) și nu suntem 100% siguri care dintre ele va îmbunătăți interacțiunea cu utilizatorul. Așadar, lansăm simultan ambele versiuni și colectăm metrici.
Pentru a desfășura a doua versiune a frontend-ului, necesară pentru demonstrarea testării A/B, executați următoarea comandă:
$ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml
deployment.extensions/sa-frontend-green creatManifestul deployment-ului pentru "versiunea verde" se diferențiază în două locuri:
- Imaginea este bazată pe un alt tag —
istio-green, - Pod-urile au eticheta
version: green.
Deoarece ambele deployment-uri au eticheta app: sa-frontend, cererile rutează prin serviciul virtual sa-external-services , vor fi redirecționate către toate instanțele sale, iar încărcarea se va distribui prin sa-frontendalgoritmul round-robin Fișierele solicitante nu au fost găsite

Aceste fișiere nu au fost găsite deoarece acestea poartă denumiri diferite în diferitele versiuni ale aplicației. Să ne asigurăm de acest lucru:
Aceasta înseamnă că
$ curl --silent http://$EXTERNAL_IP/ | tr '"' 'n' | grep main
/static/css/main.c7071b22.css
/static/js/main.059f8e9c.js
$ curl --silent http://$EXTERNAL_IP/ | tr '"' 'n' | grep main
/static/css/main.f87cd8c9.css
/static/js/main.f7659dbb.js Asta înseamnă că index.html, cererea pentru o versiune a fișierelor statice poate fi trimisă de un balansor de încărcare către poduri care au o altă versiune, unde, din motive evidente, astfel de fișiere nu există. Prin urmare, pentru ca aplicația să funcționeze, trebuie să stabilim o limitare: „aceeași versiune a aplicației care a returnat index.html trebuie să gestioneze și cererile ulterioare».
Ne vom atinge obiectivul printr-o balansare a încărcăturii coerentă bazată pe hash-uri (Balansare Consistentă a Încărcăturii). În acest caz cererile de la un client sunt trimise către aceeași instanță de backend, pentru care se utilizează o proprietate prestabilită - de exemplu, un antet HTTP. Acesta este implementat folosind DestinationRules.
DestinationRules
După ce VirtualService a direcționat cererea către serviciul corect, prin intermediul DestinationRules putem defini politicile care vor fi aplicate traficului destinat instanțelor acestui serviciu:

Gestionarea traficului cu resursele Istio
Notă: Influența resurselor Istio asupra traficului de rețea este prezentată aici într-o formă simplificată pentru a fi înțeleasă. Dacă vrem să fim preciși, decizia cu privire la ce instanță să trimită cererea este luată de Envoy în Ingress Gateway, configurat în CRD.
Folosind Destination Rules, putem configura balansarea încărcăturii astfel încât să se utilizeze hash-uri coerente și se garantează răspunsuri de la aceeași instanță a serviciului pentru același utilizator. Configurația următoare permite realizarea acestui lucru ():
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: sa-frontend
spec:
host: sa-frontend
trafficPolicy:
loadBalancer:
consistentHash:
httpHeaderName: version # 1 1 — hash-ul va fi generat pe baza conținutului antetului HTTP version.
Aplicați configurația cu următoarea comandă:
$ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml
destinationrule.networking.istio.io/sa-frontend created Acum executați comanda de mai jos și asigurați-vă că obțineți fișierele dorite atunci când specificați antetul version:
$ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' 'n' | grep mainNotă: Pentru a adăuga valori diferite în antet și a testa rezultatele direct în browser, puteți folosi pentru Chrome (sau pentru Firefox - notă de traductor).
În general, DestinationRules au mai multe opțiuni în domeniul balansării încărcăturii - detalii verificați în .
Înainte de a studia mai departe VirtualService, să ștergem „versiunea verde” a aplicației și regula de direcționare a traficului corespunzătoare, executând următoarele comenzi:
$ kubectl delete -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml
deployment.extensions "sa-frontend-green" deleted
$ kubectl delete -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml
destinationrule.networking.istio.io "sa-frontend" deletedMirror: Virtual Services în practică
Shadowing („mascare”) sau Mirroring („mirror”) este utilizat în cazurile în care dorim să testăm o modificare în producție, fără a afecta utilizatorii finali: pentru aceasta duplicăm („mirror”) cererile către a doua instanță, unde au fost efectuate modificările necesare, și observăm consecințele. Pe scurt, când colegul tău alege cea mai critică problemă și face un pull request sub forma unui ghem masiv de cod, încât nimeni nu poate efectiv să-i facă revizuirea.
Pentru a testa acest scenariu în acțiune, să creăm a doua instanță SA-Logic cu bug-uri (buggy), executând următoarea comandă:
$ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service-buggy.yaml
deployment.extensions/sa-logic-buggy created Și acum să executăm comanda pentru a ne asigura că toate instanțele cu app=sa-logic au și etichete cu versiunile corespunzătoare:
$ kubectl get pods -l app=sa-logic --show-labels
NAME READY LABELS
sa-logic-568498cb4d-2sjwj 2/2 app=sa-logic,version=v1
sa-logic-568498cb4d-p4f8c 2/2 app=sa-logic,version=v1
sa-logic-buggy-76dff55847-2fl66 2/2 app=sa-logic,version=v2
sa-logic-buggy-76dff55847-kx8zz 2/2 app=sa-logic,version=v2 Serviciu sa-logic țintind pod-urile cu eticheta app=sa-logic, așa că toate cererile vor fi distribuite între toate instanțele:

… dar vrem ca cererile să fie direcționate către instanțele cu versiunea v1 și să fie mirroring pe instanțele cu versiunea v2:

Vom realiza acest lucru prin VirtualService în combinație cu DestinationRule, unde regulile vor defini submulțimile și rutele VirtualService către o anumită submulțime.
Definirea submulțimilor în Destination Rules
Submulțimi (subsets) sunt definite prin următoarea configurație ():
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: sa-logic
spec:
host: sa-logic # 1
subsets:
- name: v1 # 2
labels:
version: v1 # 3
- name: v2
labels:
version: v2- Host-ul (
host) definește că această regulă se aplică doar în cazurile în care ruta merge spre serviciusa-logic; - Numele (
name) submulțimilor sunt utilizate la rutarea către instanțele submulțimii; - Eticheta (
label) determină perechile cheie-valoare la care trebuie să corespundă instanțele pentru a deveni parte din submulțime.
Aplicați configurația cu următoarea comandă:
$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-destinationrule.yaml
destinationrule.networking.istio.io/sa-logic creat.Acum că submulțimile sunt definite, putem merge mai departe și configura VirtualService pentru a aplica regulile la cererile către sa-logic, astfel încât acestea să:
- Fie direcționate către submulțime
v1, - Fie oglindite către submulțime
v2.
Următorul manifest permite atingerea scopului ():
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: sa-logic
spec:
hosts:
- sa-logic
http:
- route:
- destination:
host: sa-logic
subset: v1
mirror:
host: sa-logic
subset: v2Explicațiile nu sunt necesare aici, așa că să vedem pur și simplu în acțiune:
$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing-vs.yaml
virtualservice.networking.istio.io/sa-logic creat.Să adăugăm sarcina apelând această comandă:
$ while true; do curl -v http://$EXTERNAL_IP/sentiment
-H "Content-type: application/json"
-d '{"sentence": "I love yogobella"}';
sleep .8; done Să ne uităm la rezultate în Grafana, unde putem vedea că versiunea cu erori (buggy) provoacă eșecuri pentru ~60% din cereri, dar niciunul dintre aceste eșecuri nu afectează utilizatorii finali, deoarece aceștia primesc răspuns de la serviciul funcțional.

Rata de succes a răspunsurilor diferitelor versiuni ale serviciului sa-logic
Aici am văzut pentru prima dată cum VirtualService este aplicat în raport cu Envoy-ii serviciilor noastre: când sa-web-app face o cerere către sa-logic, trece prin sidecar-ul Envoy, care — prin VirtualService — este configurat să rotească cererea către submulțimea v1 și să oglindească cererea către submulțimea v2 a serviciului. sa-logic.
Știu: deja ați început să vă gândiți că serviciile virtuale sunt simple. În secțiunea următoare, ne vom extinde această părere prin faptul că sunt cu adevărat excelente.
Versiile canar
Canary Deployment — procesul de lansare a unei noi versiuni a aplicației pentru un număr mic de utilizatori. Este utilizat pentru a vă asigura că nu există probleme în lansare și abia apoi, fiind deja sigur de calitatea suficient de bună a acesteia, a o distribui uneimareaudiențe mai mari.
Pentru a demonstra desfășurările canary, vom continua să lucrăm cu submulțimea buggy u sa-logic.
Nu ne vom limita și vom trimite imediat 20% din utilizatori către versiunea cu erori (aceasta va reprezenta desfășurarea noastră canary), iar restul de 80% către serviciul normal. Pentru aceasta, vom aplica următorul VirtualService ():
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: sa-logic
spec:
hosts:
- sa-logic
http:
- route:
- destination:
host: sa-logic
subset: v1
weight: 80 # 1
- destination:
host: sa-logic
subset: v2
weight: 20 # 1 1 — este greutatea (greutate), care determină procentajul cererilor care vor fi direcționate către destinație sau submulțimea destinației.
Vom actualiza configurația anterioară a VirtualService pentru sa-logic comanda următoare:
$ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yaml
virtualservice.networking.istio.io/sa-logic configurat… și imediat vom observa că o parte din cereri generează erori:
$ while true; do
curl -i http://$EXTERNAL_IP/sentiment
-H "Content-type: application/json"
-d '{"sentence": "Îmi place yogobella"}'
--silent -w "Time: %{time_total}s t Status: %{http_code}n"
-o /dev/null; sleep .1; done
Time: 0.153075s Status: 200
Time: 0.137581s Status: 200
Time: 0.139345s Status: 200
Time: 30.291806s Status: 500VirtualServices activează desfășurările canar: în acest caz am restrâns potențialele consecințe ale problemelor la 20% din baza utilizatorilor. Minunat! Acum, de fiecare dată când nu suntem siguri de codul nostru (în alte cuvinte — mereu…), putem utiliza oglindirea și desfășurările canar.
Timpul limită și încercările repetate
Dar nu întotdeauna bug-urile sunt în cod. În lista „» cel mai important este mitul că „rețeaua este de încredere”. În realitate, rețeaua nu este de încredere, și din acest motiv avem nevoie de timpi limită (timeouts) și încercări repetate (retries).
Pentru demonstrație, vom continua să folosim aceeași problemă versiunea sa-logic (buggy), iar instabilitatea rețelei o vom simula prin erori aleatorii.
Să presupunem că serviciul nostru cu bug-uri are 1/3 șanse să răspundă prea lent, 1/3 - să returneze eroarea Internal Server Error și 1/3 - să returneze cu succes pagina.
Pentru a atenua consecințele unor astfel de probleme și pentru a îmbunătăți experiența utilizatorilor, putem:
- să adăugăm un timp limită, dacă serviciul răspunde mai mult de 8 secunde,
- să facem o încercare repetată, dacă cererea întâmpină o eroare.
Pentru implementare, vom folosi această definiție a resursei ():
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: sa-logic
spec:
hosts:
- sa-logic
http:
- route:
- destination:
host: sa-logic
subset: v1
weight: 50
- destination:
host: sa-logic
subset: v2
weight: 50
timeout: 8s # 1
retries:
attempts: 3 # 2
perTryTimeout: 3s # 3- Timpul limită pentru cerere este setat la 8 secunde;
- Încercările repetate ale cererilor sunt realizate de 3 ori;
- Și fiecare încercare este considerată eșuată dacă timpul de răspuns depășește 3 secunde.
Astfel, am realizat optimizarea, deoarece utilizatorului nu îi va trebui să aștepte mai mult de 8 secunde și vom face trei noi încercări de a obține un răspuns în caz de defecțiuni, crescând șansele pentru un răspuns reușit.
Aplicați configurația actualizată cu următoarea comandă:
$ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts-vs.yaml
virtualservice.networking.istio.io/sa-logic configuratȘi verificați în graficele Grafana că numărul de răspunsuri reușite a crescut peste:

Îmbunătățiri în statistica răspunsurilor reușite după adăugarea timeout-urilor și a încercărilor repetate
Înainte de a trece la următoarea secțiune (sau mai exact — deja la următoarea parte a articolului, deoarece în această parte nu vor mai fi experimente practice — n.t.), eliminați sa-logic-buggy și VirtualService, executând următoarele comenzi:
$ kubectl delete deployment sa-logic-buggy
deployment.extensions “sa-logic-buggy” șters
$ kubectl delete virtualservice sa-logic
virtualservice.networking.istio.io “sa-logic” ștersModelele Circuit Breaker și Bulkhead
Este vorba despre două modele importante în arhitectura microserviciilor, care permit autocontracararea (self-healing) serviciilor.
Circuit Breaker („disjunctor”) este utilizat pentru a opri solicitările care ajung la o instanță de serviciu considerată nesănătoasă, iar recuperarea are loc în timp ce solicitările clienților sunt redirecționate către instanțele sănătoase ale acestui serviciu (ceea ce crește procentul de răspunsuri reușite). (n.t.: O descriere mai detaliată a modelului poate fi găsită, de exemplu, .)
Bulkhead („perete despărțitor”) izolează eșecurile în servicii de întreaga sistem. De exemplu, serviciul B este defect, iar un alt serviciu (clientul serviciului B) face o solicitare către serviciul B, ducând la consumarea pool-ului său de fire și incapacitarea lui de a gestiona alte solicitări (chiar dacă acestea nu sunt legate de serviciul B). (n.t.: O descriere mai detaliată a modelului poate fi găsită, de exemplu, .)
Voi omite detaliile privind implementarea acestor modele pentru că sunt ușor de găsit în , și de asemenea vreau foarte mult să arăt autentificarea și autorizarea, despre care va fi vorba în următoarea parte a articolului.
P.S. de la traducător
Citiți și în blogul nostru:
- „Înapoi la microservicii împreună cu Istio”: , ;
- «»;
- «».
Sursa: habr.com
