Terug naar microservices met Istio. Deel 2

Terug naar microservices met Istio. Deel 2

Opmerking. vert.: Het eerste deel Deze serie was gewijd aan het introduceren van Istio-mogelijkheden en het demonstreren ervan in actie. Nu zullen we het hebben over complexere aspecten van de configuratie en het gebruik van deze service mesh, en in het bijzonder over nauwkeurig afgestemde routering en netwerkverkeersbeheer.

We herinneren u er ook aan dat het artikel configuraties (manifesten voor Kubernetes en Istio) uit de repository gebruikt istio-meesterschap.

Verkeersmanagement

Met Istio verschijnen er nieuwe mogelijkheden in het cluster om het volgende te bieden:

  • Dynamische verzoekroutering: canary-uitrol, A/B-testen;
  • Load-balancering: eenvoudig en consistent, gebaseerd op hashes;
  • Herstel na vallen: time-outs, nieuwe pogingen, stroomonderbrekers;
  • Fouten invoegen: vertragingen, afgewezen aanvragen, enz.

Naarmate het artikel verder gaat, zullen deze mogelijkheden worden geïllustreerd aan de hand van de geselecteerde applicatie als voorbeeld, en gaandeweg zullen nieuwe concepten worden geïntroduceerd. Het eerste dergelijke concept zal zijn DestinationRules (d.w.z. regels over de ontvanger van verkeer/verzoeken - ca. vert.), waarmee we A/B-testen activeren.

A/B-testen: DestinationRules in de praktijk

A/B-testen worden gebruikt in gevallen waarin er twee versies van een applicatie zijn (meestal zijn ze visueel verschillend) en we niet 100% zeker weten welke de gebruikerservaring zal verbeteren. Daarom voeren we beide versies tegelijkertijd uit en verzamelen we statistieken.

Om de tweede versie van de frontend te implementeren, vereist voor het demonstreren van A/B-testen, voert u de volgende opdracht uit:

$ kubectl apply -f resource-manifests/kube/ab-testing/sa-frontend-green-deployment.yaml
deployment.extensions/sa-frontend-green created

Het implementatiemanifest voor de groene versie verschilt op twee punten:

  1. De afbeelding is gebaseerd op een andere tag - istio-green,
  2. Pods hebben een label version: green.

Omdat beide implementaties een label hebben app: sa-frontend,verzoeken gerouteerd door virtuele service sa-external-services voor service sa-frontend, wordt doorgestuurd naar al zijn instanties en de belasting wordt verdeeld via round robin-algoritme, wat tot de volgende situatie zal leiden:

Terug naar microservices met Istio. Deel 2
De gevraagde bestanden zijn niet gevonden

Deze bestanden zijn niet gevonden omdat ze in verschillende versies van de applicatie een andere naam hebben. Laten we hier zeker van zijn:

$ 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

Dit betekent dat index.html, waarbij één versie van statische bestanden wordt aangevraagd, kan door de load balancer worden verzonden naar pods die een andere versie hebben, waar dergelijke bestanden om voor de hand liggende redenen niet bestaan. Om de applicatie te laten werken, moeten we daarom een ​​beperking instellen: “dezelfde versie van de applicatie die index.html bediende, zou volgende verzoeken moeten verwerken.

We komen er met consistente, op hash gebaseerde load-balancing (Consistente hash-loadbalancing). In dit geval verzoeken van dezelfde client worden naar hetzelfde backend-exemplaar verzonden, waarvoor een vooraf gedefinieerde eigenschap wordt gebruikt, bijvoorbeeld een HTTP-header. Geïmplementeerd met behulp van DestinationRules.

Bestemmingsregels

Na VirtueleService een verzoek naar de gewenste service heeft gestuurd, kunnen we met behulp van DestinationRules beleid definiëren dat wordt toegepast op verkeer dat bestemd is voor exemplaren van deze service:

Terug naar microservices met Istio. Deel 2
Verkeersmanagement met Istio-middelen

Noot: De impact van Istio-bronnen op het netwerkverkeer wordt hier gepresenteerd op een manier die gemakkelijk te begrijpen is. Om precies te zijn: de beslissing naar welk exemplaar het verzoek moet worden verzonden, wordt genomen door de Envoy in de Ingress Gateway die in de CRD is geconfigureerd.

Met bestemmingsregels kunnen we de taakverdeling configureren om consistente hashes te gebruiken en ervoor te zorgen dat hetzelfde service-exemplaar op dezelfde gebruiker reageert. Met de volgende configuratie kunt u dit bereiken (bestemmingsregel-sa-frontend.yaml):

apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
  name: sa-frontend
spec:
  host: sa-frontend
  trafficPolicy:
    loadBalancer:
      consistentHash:
        httpHeaderName: version   # 1

1 - hash wordt gegenereerd op basis van de inhoud van de HTTP-header version.

Pas de configuratie toe met het volgende commando:

$ kubectl apply -f resource-manifests/istio/ab-testing/destinationrule-sa-frontend.yaml
destinationrule.networking.istio.io/sa-frontend created

Voer nu de onderstaande opdracht uit en zorg ervoor dat u de juiste bestanden krijgt wanneer u de header opgeeft version:

$ curl --silent -H "version: yogo" http://$EXTERNAL_IP/ | tr '"' 'n' | grep main

Noot: Om verschillende waarden in de header toe te voegen en de resultaten rechtstreeks in de browser te testen, kunt u gebruiken deze uitbreiding naar Chroom (Of hiermee voor Firefox - ca. vert.).

Over het algemeen heeft DestinationRules meer mogelijkheden op het gebied van load-balancing - kijk voor details in officiële documentatie.

Laten we, voordat we VirtualService verder bestuderen, de “groene versie” van de applicatie en de bijbehorende verkeersrichtingsregel verwijderen door de volgende opdrachten uit te voeren:

$ 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” deleted

Mirroring: virtuele services in de praktijk

schaduwing (“afscherming”) of spiegelen (“spiegelen”) gebruikt in gevallen waarin we een productiewijziging willen testen zonder gevolgen voor eindgebruikers: om dit te doen, dupliceren we (‘mirror’) verzoeken naar een tweede instantie waar de gewenste wijzigingen zijn aangebracht, en kijken we naar de gevolgen. Simpel gezegd: dit is het moment waarop uw collega het meest kritieke probleem kiest en een pull-verzoek indient in de vorm van zo'n enorme klomp vuil dat niemand het daadwerkelijk kan beoordelen.

Om dit scenario in actie te testen, maken we een tweede exemplaar van SA-Logic met bugs (buggy) door de volgende opdracht uit te voeren:

$ kubectl apply -f resource-manifests/kube/shadowing/sa-logic-service-buggy.yaml
deployment.extensions/sa-logic-buggy created

En laten we nu de opdracht uitvoeren om ervoor te zorgen dat alle exemplaren met app=sa-logic Ze hebben ook labels met de bijbehorende versies:

$ 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

Dienst sa-logic richt zich op peulen met een label app=sa-logic, zodat alle verzoeken over alle instanties worden verdeeld:

Terug naar microservices met Istio. Deel 2

... maar we willen dat verzoeken naar v1-instanties worden verzonden en worden gespiegeld naar v2-instanties:

Terug naar microservices met Istio. Deel 2

We zullen dit bereiken via VirtualService in combinatie met DestinationRule, waarbij de regels de subsets en routes van de VirtualService naar een specifieke subset bepalen.

Subsets definiëren in bestemmingsregels

Subsets (subsets) worden bepaald door de volgende configuratie (sa-logic-subsets-destinationrule.yaml):

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

  1. Gastheer (host) definieert dat deze regel alleen van toepassing is op gevallen waarin de route richting de dienst gaat sa-logic;
  2. Titels (name) subsets worden gebruikt bij het routeren naar subsetinstanties;
  3. Etiket (label) definieert de sleutel-waardeparen waarmee exemplaren moeten overeenkomen om deel uit te maken van de subset.

Pas de configuratie toe met het volgende commando:

$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-destinationrule.yaml
destinationrule.networking.istio.io/sa-logic created

Nu de subsets zijn gedefinieerd, kunnen we verder gaan en de VirtualService configureren om regels toe te passen op verzoeken aan sa-logic, zodat ze:

  1. Doorgestuurd naar een subset v1,
  2. Gespiegeld naar een subset v2.

Met het volgende manifest kunt u uw plannen verwezenlijken (sa-logic-subsets-shadowing-vs.yaml):

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: v2

Hier is geen uitleg nodig, dus laten we het gewoon in actie zien:

$ kubectl apply -f resource-manifests/istio/shadowing/sa-logic-subsets-shadowing-vs.yaml
virtualservice.networking.istio.io/sa-logic created

Laten we de belasting toevoegen door de volgende opdracht aan te roepen:

$ while true; do curl -v http://$EXTERNAL_IP/sentiment 
    -H "Content-type: application/json" 
    -d '{"sentence": "I love yogobella"}'; 
    sleep .8; done

Laten we eens kijken naar de resultaten in Grafana, waar je kunt zien dat de versie met bugs (buggy) resulteert in een mislukking voor ~60% van de verzoeken, maar geen van deze fouten heeft gevolgen voor eindgebruikers, aangezien hierop wordt gereageerd door een actieve service.

Terug naar microservices met Istio. Deel 2
Succesvolle reacties van verschillende versies van de sa-logic-service

Hier zagen we voor het eerst hoe VirtualService wordt toegepast op de Envoys van onze diensten: wanneer sa-web-app doet een verzoek aan sa-logic, het gaat via de zijspan Envoy, die - via VirtualService - is geconfigureerd om het verzoek naar de v1-subset te routeren en het verzoek te spiegelen naar de v2-subset van de service sa-logic.

Ik weet het, je denkt misschien al dat Virtual Services eenvoudig is. In het volgende gedeelte gaan we daar dieper op in door te zeggen dat ze ook echt geweldig zijn.

Kanarie-uitrol

Canary Deployment is het proces waarbij een nieuwe versie van een applicatie wordt uitgerold naar een klein aantal gebruikers. Het wordt gebruikt om ervoor te zorgen dat er geen problemen zijn met de release en pas daarna, terwijl je al vertrouwen hebt in de kwaliteit ervan, deze naar andere gebruikers te distribueren.оgroter publiek.

Om de uitrol van kanaries te demonstreren, blijven we werken met een subset buggy у sa-logic.

Laten we geen tijd verspillen aan kleinigheden en onmiddellijk 20% van de gebruikers naar de versie met bugs sturen (dit vertegenwoordigt onze kanarie-uitrol), en de resterende 80% naar de normale service. Gebruik hiervoor de volgende VirtualService (sa-logic-subsets-canary-vs.yaml):

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 is het gewicht (weight), waarmee het percentage verzoeken wordt opgegeven dat wordt gericht aan een ontvanger of een subset van de ontvanger.

Laten we de vorige VirtualService-configuratie bijwerken voor sa-logic met het volgende commando:

$ kubectl apply -f resource-manifests/istio/canary/sa-logic-subsets-canary-vs.yaml
virtualservice.networking.istio.io/sa-logic configured

... en we zullen meteen zien dat sommige verzoeken tot mislukkingen leiden:

$ while true; do 
   curl -i http://$EXTERNAL_IP/sentiment 
   -H "Content-type: application/json" 
   -d '{"sentence": "I love 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: 500

VirtualServices maken canary-implementaties mogelijk: in dit geval hebben we de potentiële impact van de problemen beperkt tot 20% van het gebruikersbestand. Prachtig! In elk geval waarin we niet zeker zijn van onze code (met andere woorden: altijd...), kunnen we mirroring en canary-implementaties gebruiken.

Time-outs en nieuwe pogingen

Maar bugs komen niet altijd in de code terecht. In de lijst van "8 Misvattingen over gedistribueerde computers“In de eerste plaats is er de onjuiste overtuiging dat ‘het netwerk betrouwbaar is’. In werkelijkheid het netwerk geen betrouwbaar, en om deze reden hebben we time-outs nodig (time-outs) en nieuwe pogingen (pogingen).

Voor demonstratie blijven we dezelfde probleemversie gebruiken sa-logic (buggy), en we zullen de onbetrouwbaarheid van het netwerk simuleren met willekeurige storingen.

Laat onze service met bugs een kans van 1/3 hebben dat het te lang duurt om te reageren, een kans van 1/3 dat deze eindigt met een interne serverfout en een kans van 1/3 dat de pagina succesvol wordt geretourneerd.

Om de impact van dergelijke problemen te verzachten en het leven van gebruikers te verbeteren, kunnen we:

  1. een time-out toevoegen als de service langer dan 8 seconden nodig heeft om te reageren,
  2. Probeer het opnieuw als het verzoek mislukt.

Voor implementatie zullen we de volgende resourcedefinitie gebruiken (sa-logic-retries-timeouts-vs.yaml):

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

  1. De time-out voor het verzoek is ingesteld op 8 seconden;
  2. Verzoeken worden 3 keer opnieuw geprobeerd;
  3. En elke poging wordt als mislukt beschouwd als de responstijd langer is dan 3 seconden.

Dit is een optimalisatie omdat de gebruiker niet langer dan 8 seconden hoeft te wachten en we bij storingen drie nieuwe pogingen zullen doen om een ​​reactie te krijgen, waardoor de kans op een succesvolle reactie groter wordt.

Pas de bijgewerkte configuratie toe met de volgende opdracht:

$ kubectl apply -f resource-manifests/istio/retries/sa-logic-retries-timeouts-vs.yaml
virtualservice.networking.istio.io/sa-logic configured

En kijk in de Grafana-grafieken hierboven dat het aantal succesvolle reacties is toegenomen:

Terug naar microservices met Istio. Deel 2
Verbeteringen in succesvolle responsstatistieken na het toevoegen van time-outs en nieuwe pogingen

Voordat u doorgaat naar het volgende gedeelte (of beter gezegd, naar het volgende deel van het artikel, want hierin zullen geen praktische experimenten meer plaatsvinden - ca. vert.), verwijderen sa-logic-buggy en VirtualService door de volgende opdrachten uit te voeren:

$ kubectl delete deployment sa-logic-buggy
deployment.extensions “sa-logic-buggy” deleted
$ kubectl delete virtualservice sa-logic
virtualservice.networking.istio.io “sa-logic” deleted

Stroomonderbreker- en schotpatronen

We hebben het over twee belangrijke patronen in de microservice-architectuur waarmee u zelfherstel kunt bereiken (zelfgenezing) Diensten.

schakelaar ("zekering") gebruikt om verzoeken te beëindigen die binnenkomen bij een exemplaar van een service die als ongezond wordt beschouwd en deze te herstellen terwijl clientverzoeken worden omgeleid naar gezonde exemplaren van die service (wat het percentage succesvolle reacties verhoogt). (Let op: Een meer gedetailleerde beschrijving van het patroon vindt u bijvoorbeeld op hier.)

waterdicht schot ("partitie") voorkomt dat servicestoringen het hele systeem beïnvloeden. Service B is bijvoorbeeld kapot en een andere service (de client van Service B) doet een verzoek aan Service B, waardoor deze zijn threadpool leegmaakt en geen andere verzoeken kan verwerken (zelfs als deze niet van Service B komen). (Let op: Een meer gedetailleerde beschrijving van het patroon vindt u bijvoorbeeld op hier.)

Ik zal de implementatiedetails van deze patronen weglaten omdat ze gemakkelijk te vinden zijn officiële documentatie, en ik wil ook heel graag authenticatie en autorisatie laten zien, wat in het volgende deel van het artikel zal worden besproken.

PS van vertaler

Lees ook op onze blog:

Bron: www.habr.com

Voeg een reactie