Zurück zu Microservices mit Istio. Teil 2

Zurück zu Microservices mit Istio. Teil 2

Notiz. übersetzen: Der erste Teil In dieser Serie ging es darum, die Funktionen von Istio vorzustellen und sie in Aktion zu demonstrieren. Jetzt werden wir über komplexere Aspekte der Konfiguration und Nutzung dieses Service-Mesh sprechen, insbesondere über fein abgestimmtes Routing und Netzwerkverkehrsmanagement.

Wir erinnern Sie auch daran, dass der Artikel Konfigurationen (Manifeste für Kubernetes und Istio) aus dem Repository verwendet istio-Meisterschaft.

Verkehrsregelung

Mit Istio erscheinen im Cluster neue Funktionen, die Folgendes bieten:

  • Dynamisches Anforderungsrouting: Canary-Rollouts, A/B-Tests;
  • Lastverteilung: einfach und konsistent, basierend auf Hashes;
  • Erholung nach Stürzen: Zeitüberschreitungen, Wiederholungsversuche, Leistungsschalter;
  • Fehler einfügen: Verzögerungen, abgebrochene Anfragen usw.

Im weiteren Verlauf des Artikels werden diese Möglichkeiten am Beispiel der ausgewählten Anwendung veranschaulicht und dabei neue Konzepte vorgestellt. Das erste derartige Konzept wird sein DestinationRules (d. h. Regeln über den Empfänger von Datenverkehr/Anfragen – ca. übersetzt), mit deren Hilfe wir A/B-Tests aktivieren.

A/B-Testing: DestinationRules in der Praxis

A/B-Tests werden in Fällen eingesetzt, in denen es zwei Versionen einer Anwendung gibt (normalerweise unterscheiden sie sich optisch) und wir nicht 100 % sicher sind, welche Version das Benutzererlebnis verbessert. Daher führen wir beide Versionen gleichzeitig aus und sammeln Metriken.

Führen Sie den folgenden Befehl aus, um die zweite Version des Frontends bereitzustellen, die für die Demonstration von A/B-Tests erforderlich ist:

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

Das Bereitstellungsmanifest für die grüne Version unterscheidet sich an zwei Stellen:

  1. Das Bild basiert auf einem anderen Tag - istio-green,
  2. Pods haben ein Etikett version: green.

Da beide Bereitstellungen ein Label haben app: sa-frontend,Anfragen werden vom virtuellen Dienst weitergeleitet sa-external-services für den Dienst sa-frontend, wird an alle seine Instanzen umgeleitet und die Last wird darüber verteilt Round-Robin-Algorithmus, was zu folgender Situation führen wird:

Zurück zu Microservices mit Istio. Teil 2
Die angeforderten Dateien wurden nicht gefunden

Diese Dateien wurden nicht gefunden, da sie in verschiedenen Versionen der Anwendung unterschiedlich benannt sind. Stellen wir Folgendes sicher:

$ 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

Dies bedeutet, dass index.html, die eine Version statischer Dateien anfordert, kann vom Load Balancer an Pods gesendet werden, die eine andere Version haben, wo solche Dateien aus offensichtlichen Gründen nicht vorhanden sind. Damit die Anwendung funktioniert, müssen wir daher eine Einschränkung festlegen: „Dieselbe Version der Anwendung, die index.html bereitgestellt hat, sollte nachfolgende Anforderungen verarbeiten".

Mit einem konsistenten Hash-basierten Lastausgleich erreichen wir dieses Ziel (Konsistenter Hash-Loadbalancing). In diesem Fall Anfragen vom selben Client werden an dieselbe Backend-Instanz gesendet, für die eine vordefinierte Eigenschaft verwendet wird – beispielsweise ein HTTP-Header. Implementiert mit DestinationRules.

Zielregeln

Nach VirtualService Wir haben eine Anfrage an den gewünschten Dienst gesendet. Mithilfe von DestinationRules können wir Richtlinien definieren, die auf den Datenverkehr angewendet werden, der für Instanzen dieses Dienstes bestimmt ist:

Zurück zu Microservices mit Istio. Teil 2
Verkehrsmanagement mit Istio-Ressourcen

Beachten: Der Einfluss von Istio-Ressourcen auf den Netzwerkverkehr wird hier auf leicht verständliche Weise dargestellt. Genauer gesagt trifft die Entscheidung darüber, an welche Instanz die Anfrage gesendet wird, der Envoy im im CRD konfigurierten Ingress Gateway.

Mit Zielregeln können wir den Lastausgleich so konfigurieren, dass konsistente Hashes verwendet werden und sichergestellt wird, dass dieselbe Dienstinstanz auf denselben Benutzer antwortet. Mit der folgenden Konfiguration können Sie dies erreichen (Destinationrule-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 wird basierend auf dem Inhalt des HTTP-Headers generiert version.

Wenden Sie die Konfiguration mit dem folgenden Befehl an:

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

Führen Sie nun den folgenden Befehl aus und stellen Sie sicher, dass Sie bei der Angabe des Headers die richtigen Dateien erhalten version:

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

Beachten: Um verschiedene Werte in den Header einzufügen und die Ergebnisse direkt im Browser zu testen, können Sie verwenden diese Erweiterung zu Chrome (oder mit diesem für Firefox - ca. übersetzt).

Im Allgemeinen verfügt DestinationRules über mehr Funktionen im Bereich Lastausgleich – Einzelheiten finden Sie unter amtliche Dokumentation.

Bevor wir VirtualService weiter untersuchen, löschen wir die „grüne Version“ der Anwendung und die entsprechende Verkehrsrichtungsregel, indem wir die folgenden Befehle ausführen:

$ 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

Spiegelung: Virtuelle Dienste in der Praxis

Beschatten ("Abschirmung") oder Spiegelung („Spiegelung“) Wird in Fällen verwendet, in denen wir eine Änderung in der Produktion testen möchten, ohne dass sich dies auf Endbenutzer auswirkt: Dazu duplizieren („spiegeln“) wir Anfragen an eine zweite Instanz, in der die gewünschten Änderungen vorgenommen wurden, und prüfen die Konsequenzen. Vereinfacht ausgedrückt ist dies der Zeitpunkt, an dem Ihr Kollege das kritischste Problem auswählt und einen Pull-Request in Form eines so großen Schmutzklumpens stellt, dass niemand ihn tatsächlich überprüfen kann.

Um dieses Szenario in Aktion zu testen, erstellen wir eine zweite Instanz von SA-Logic mit Fehlern (buggy), indem Sie den folgenden Befehl ausführen:

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

Und jetzt führen wir den Befehl aus, um sicherzustellen, dass alle Instanzen mit app=sa-logic Sie haben auch Etiketten mit den entsprechenden Versionen:

$ 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

Service sa-logic zielt auf Pods mit einem Label ab app=sa-logic, sodass alle Anfragen auf alle Instanzen verteilt werden:

Zurück zu Microservices mit Istio. Teil 2

... aber wir möchten, dass Anfragen an v1-Instanzen gesendet und auf v2-Instanzen gespiegelt werden:

Zurück zu Microservices mit Istio. Teil 2

Dies erreichen wir durch VirtualService in Kombination mit DestinationRule, wobei die Regeln die Teilmengen und Routen des VirtualService zu einer bestimmten Teilmenge bestimmen.

Teilmengen in Zielregeln definieren

Teilmengen (Teilmengen) werden durch die folgende Konfiguration bestimmt (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. Gastgeber (host) legt fest, dass diese Regel nur für Fälle gilt, in denen die Route zum Dienst führt sa-logic;
  2. Titel (name) Teilmengen werden beim Routing zu Teilmengeninstanzen verwendet;
  3. Etikett (label) definiert die Schlüssel-Wert-Paare, mit denen Instanzen übereinstimmen müssen, um Teil der Teilmenge zu werden.

Wenden Sie die Konfiguration mit dem folgenden Befehl an:

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

Nachdem die Teilmengen nun definiert sind, können wir fortfahren und den VirtualService so konfigurieren, dass er Regeln auf Anfragen an sa-logic anwendet, sodass sie:

  1. An eine Teilmenge weitergeleitet v1,
  2. Auf eine Teilmenge gespiegelt v2.

Mit dem folgenden Manifest können Sie Ihre Pläne verwirklichen (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 bedarf es keiner Erklärung, also sehen wir es uns einfach in Aktion an:

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

Fügen wir die Last hinzu, indem wir den folgenden Befehl aufrufen:

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

Schauen wir uns die Ergebnisse in Grafana an, wo Sie sehen können, dass die Version mit Fehlern (buggy) führt bei ca. 60 % der Anfragen zu Fehlern, aber keiner dieser Fehler wirkt sich auf Endbenutzer aus, da sie von einem laufenden Dienst beantwortet werden.

Zurück zu Microservices mit Istio. Teil 2
Erfolgreiche Antworten verschiedener Versionen des sa-logic-Dienstes

Hier haben wir zum ersten Mal gesehen, wie VirtualService auf die Envoys unserer Dienste angewendet wird: wann sa-web-app stellt eine Anfrage an sa-logic, durchläuft es den Sidecar Envoy, der – über VirtualService – so konfiguriert ist, dass er die Anfrage an die v1-Teilmenge weiterleitet und die Anfrage an die v2-Teilmenge des Dienstes spiegelt sa-logic.

Ich weiß, Sie denken vielleicht schon, dass virtuelle Dienste einfach sind. Im nächsten Abschnitt gehen wir näher darauf ein und sagen, dass sie auch wirklich großartig sind.

Canary-Rollouts

Canary Deployment ist der Prozess der Bereitstellung einer neuen Version einer Anwendung für eine kleine Anzahl von Benutzern. Es wird verwendet, um sicherzustellen, dass es keine Probleme mit der Veröffentlichung gibt, und erst danach, wenn man bereits von der Qualität der Veröffentlichung überzeugt ist, kann man sie an andere Benutzer verteilen.оgrößeres Publikum.

Um Canary-Rollouts zu demonstrieren, werden wir weiterhin mit einer Teilmenge arbeiten buggy у sa-logic.

Verschwenden wir keine Zeit mit Kleinigkeiten und schicken wir 20 % der Benutzer sofort zur Version mit Fehlern (dies stellt unseren Canary-Rollout dar) und die restlichen 80 % zum normalen Dienst. Verwenden Sie dazu den folgenden 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 ist das Gewicht (weight), der den Prozentsatz der Anfragen angibt, die an einen Empfänger oder eine Teilmenge des Empfängers weitergeleitet werden.

Aktualisieren wir die vorherige VirtualService-Konfiguration für sa-logic mit folgendem Befehl:

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

... und wir werden sofort sehen, dass einige Anfragen zu Fehlern führen:

$ 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 ermöglichen Canary-Rollouts: In diesem Fall haben wir die potenziellen Auswirkungen der Probleme auf 20 % der Benutzerbasis eingegrenzt. Wunderbar! Jetzt können wir in jedem Fall, wenn wir uns unseres Codes nicht sicher sind (mit anderen Worten: immer...), Spiegelung und Canary-Rollouts verwenden.

Zeitüberschreitungen und Wiederholungsversuche

Doch nicht immer landen Fehler im Code. In der Liste von „8 Missverständnisse über verteiltes Rechnen„An erster Stelle steht der Irrglaube, dass „das Netzwerk zuverlässig ist“. In Wirklichkeit das Netzwerk nicht zuverlässig, und aus diesem Grund brauchen wir Auszeiten (Zeitüberschreitungen) und versucht es erneut (Wiederholungen).

Zur Demonstration werden wir weiterhin die gleiche Problemversion verwenden sa-logic (buggy) und wir werden die Unzuverlässigkeit des Netzwerks mit zufälligen Ausfällen simulieren.

Bei Fehlern besteht bei unserem Dienst eine Wahrscheinlichkeit von 1/3, dass die Antwort zu lange dauert, eine Wahrscheinlichkeit von 1/3, dass er mit einem internen Serverfehler endet, und eine Wahrscheinlichkeit von 1/3, dass die Seite erfolgreich zurückgegeben wird.

Um die Auswirkungen solcher Probleme abzumildern und das Leben der Benutzer zu verbessern, können wir:

  1. Fügen Sie eine Zeitüberschreitung hinzu, wenn der Dienst länger als 8 Sekunden zum Antworten benötigt.
  2. Versuchen Sie es erneut, wenn die Anfrage fehlschlägt.

Für die Implementierung verwenden wir die folgende Ressourcendefinition (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. Der Timeout für die Anfrage ist auf 8 Sekunden eingestellt;
  2. Anfragen werden dreimal wiederholt;
  3. Und jeder Versuch gilt als erfolglos, wenn die Reaktionszeit 3 ​​Sekunden überschreitet.

Dies ist eine Optimierung, da der Benutzer nicht länger als 8 Sekunden warten muss und wir im Falle eines Fehlers drei neue Versuche unternehmen, um eine Antwort zu erhalten, wodurch die Chance auf eine erfolgreiche Antwort erhöht wird.

Wenden Sie die aktualisierte Konfiguration mit dem folgenden Befehl an:

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

Und überprüfen Sie in den Grafana-Grafiken, ob die Anzahl der erfolgreichen Antworten oben gestiegen ist:

Zurück zu Microservices mit Istio. Teil 2
Verbesserungen bei den Statistiken zu erfolgreichen Antworten nach dem Hinzufügen von Zeitüberschreitungen und Wiederholungsversuchen

Bevor wir zum nächsten Abschnitt übergehen (oder besser gesagt zum nächsten Teil des Artikels, denn in diesem wird es keine praktischen Experimente mehr geben - ca. übersetzt.), löschen sa-logic-buggy und VirtualService, indem Sie die folgenden Befehle ausführen:

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

Leistungsschalter- und Schottmuster

Wir sprechen über zwei wichtige Muster in der Microservice-Architektur, die es Ihnen ermöglichen, eine Selbstwiederherstellung zu erreichen (Selbstheilung) Dienstleistungen.

Circuit Breaker („Leistungsschalter“) Wird verwendet, um Anfragen an eine Instanz eines Dienstes zu beenden, die als fehlerhaft gilt, und sie wiederherzustellen, während Clientanfragen an fehlerfreie Instanzen dieses Dienstes umgeleitet werden (was den Prozentsatz erfolgreicher Antworten erhöht). (Hinweis: Eine detailliertere Beschreibung des Musters finden Sie z. B. hier.)

Schott („Partition“) verhindert, dass Dienstausfälle das gesamte System beeinträchtigen. Beispielsweise ist Dienst B defekt und ein anderer Dienst (der Client von Dienst B) stellt eine Anfrage an Dienst B, was dazu führt, dass dieser seinen Thread-Pool erschöpft und keine anderen Anfragen mehr bedienen kann (auch wenn diese nicht von Dienst B stammen). (Hinweis: Eine detailliertere Beschreibung des Musters finden Sie z. B. hier.)

Ich werde die Implementierungsdetails dieser Muster weglassen, da sie leicht zu finden sind amtliche Dokumentation, und ich möchte auch unbedingt Authentifizierung und Autorisierung anzeigen, was im nächsten Teil des Artikels besprochen wird.

PS vom Übersetzer

Lesen Sie auch auf unserem Blog:

Source: habr.com

Kommentar hinzufügen