Powrót do mikroserwisów z Istio. Część 2

Powrót do mikroserwisów z Istio. Część 2

Notatka. przeł.: Pierwsza część Ta seria była poświęcona wprowadzeniu możliwości Istio i zademonstrowaniu ich w działaniu. Teraz porozmawiamy o bardziej złożonych aspektach konfiguracji i wykorzystania tej siatki usług, a w szczególności o precyzyjnie dostrojonym routingu i zarządzaniu ruchem sieciowym.

Przypominamy również, że w artykule wykorzystano konfiguracje (manifesty dla Kubernetes i Istio) z repozytorium istio-mistrzostwo.

Zarządzanie ruchem

Dzięki Istio w klastrze pojawiają się nowe możliwości, które zapewniają:

  • Dynamiczne kierowanie żądań: rollouty Canary, testy A/B;
  • Równoważenie obciążenia: prosty i spójny, oparty na skrótach;
  • Regeneracja po upadkach: przekroczenia limitu czasu, ponowne próby, wyłączniki automatyczne;
  • Wstawianie usterek: opóźnienia, odrzucone żądania itp.

W dalszej części artykułu możliwości te będą ilustrowane na przykładzie wybranej aplikacji, przy okazji wprowadzane będą nowe koncepcje. Pierwszą taką koncepcją będzie DestinationRules (tj. zasady dotyczące odbiorcy ruchu/żądań – ok. tł.), za pomocą którego uruchamiamy testy A/B.

Testy A/B: DestinationRules w praktyce

Testy A/B stosujemy w przypadku, gdy istnieją dwie wersje aplikacji (zwykle różnią się one wizualnie) i nie jesteśmy w 100% pewni, która z nich poprawi komfort użytkowania. Dlatego uruchamiamy obie wersje jednocześnie i zbieramy metryki.

Aby wdrożyć drugą wersję frontendu, wymaganą do zademonstrowania testów A/B, uruchom następującą komendę:

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

Manifest wdrożenia wersji zielonej różni się w dwóch miejscach:

  1. Obraz jest oparty na innym tagu - istio-green,
  2. Strąki mają etykietę version: green.

Ponieważ oba wdrożenia mają etykietę app: sa-frontend,żądania kierowane przez usługę wirtualną sa-external-services Do obsługi sa-frontend, zostanie przekierowany do wszystkich swoich instancji, a obciążenie zostanie rozłożone algorytm okrężny, co doprowadzi do następującej sytuacji:

Powrót do mikroserwisów z Istio. Część 2
Nie znaleziono żądanych plików

Pliki te nie zostały znalezione, ponieważ mają różne nazwy w różnych wersjach aplikacji. Upewnijmy się co do tego:

$ 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

Oznacza to, że index.html, żądając jednej wersji plików statycznych, może zostać przesłane przez moduł równoważenia obciążenia do podów mających inną wersję, gdzie z oczywistych powodów takie pliki nie istnieją. Dlatego aby aplikacja działała musimy ustawić ograniczenie: „ta sama wersja aplikacji, która obsługiwała plik Index.html, powinna obsługiwać kolejne żądania".

Osiągniemy to dzięki spójnemu równoważeniu obciążenia w oparciu o skróty (Spójne równoważenie obciążenia skrótu). W tym przypadku żądania od tego samego klienta są wysyłane do tej samej instancji zaplecza, dla którego używana jest predefiniowana właściwość - na przykład nagłówek HTTP. Zaimplementowano przy użyciu DestinationRules.

Regulamin miejsca docelowego

Później Usługa wirtualna wysłał żądanie do żądanej usługi, za pomocą DestinationRules możemy zdefiniować polityki, które będą stosowane do ruchu kierowanego do instancji tej usługi:

Powrót do mikroserwisów z Istio. Część 2
Zarządzanie ruchem za pomocą zasobów Istio

Operacja: Wpływ zasobów Istio na ruch sieciowy przedstawiono tutaj w łatwy do zrozumienia sposób. A konkretnie decyzję do której instancji wysłać żądanie podejmuje Envoy w skonfigurowanym w CRD Ingress Gateway.

Dzięki regułom docelowym możemy skonfigurować równoważenie obciążenia, aby używać spójnych skrótów i mieć pewność, że ta sama instancja usługi odpowiada temu samemu użytkownikowi. Poniższa konfiguracja pozwala to osiągnąć (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 zostanie wygenerowany na podstawie zawartości nagłówka HTTP version.

Zastosuj konfigurację za pomocą następującego polecenia:

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

Teraz uruchom poniższe polecenie i upewnij się, że po określeniu nagłówka otrzymujesz właściwe pliki version:

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

Operacja: Aby dodać różne wartości w nagłówku i przetestować wyniki bezpośrednio w przeglądarce, możesz użyć to rozszerzenie do Chrome (or z tym dla Firefoksa – ok. tłumacz.).

Generalnie DestinationRules ma więcej możliwości w obszarze równoważenia obciążenia - szczegóły znajdziesz w oficjalna dokumentacja.

Zanim dokładniej przestudiujemy VirtualService, usuńmy „zieloną wersję” aplikacji i odpowiadającą jej regułę kierunku ruchu, uruchamiając następujące polecenia:

$ 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: usługi wirtualne w praktyce

Cieniowanie ("zastawianie") lub Odbicie lustrzane („odbicie lustrzane”) stosowane w przypadkach, gdy chcemy przetestować zmianę w produkcji bez wpływu na użytkowników końcowych: w tym celu duplikujemy („kopiujemy”) żądania do drugiej instancji, w której wprowadzono pożądane zmiany i sprawdzamy konsekwencje. Mówiąc najprościej, ma to miejsce wtedy, gdy Twój współpracownik wybiera najbardziej krytyczny problem i wysyła prośbę o ściągnięcie w postaci tak ogromnej bryły brudu, że nikt nie jest w stanie jej sprawdzić.

Aby przetestować ten scenariusz w działaniu, utwórzmy drugą instancję SA-Logic z błędami (buggy), uruchamiając następujące polecenie:

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

A teraz uruchommy polecenie, aby upewnić się, że wszystkie instancje z app=sa-logic Mają także etykiety z odpowiednimi wersjami:

$ 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

Platforma sa-logic celuje w kapsuły z etykietą app=sa-logic, więc wszystkie żądania zostaną rozdzielone pomiędzy wszystkie instancje:

Powrót do mikroserwisów z Istio. Część 2

... ale chcemy, aby żądania były wysyłane do instancji v1 i odzwierciedlane w instancjach v2:

Powrót do mikroserwisów z Istio. Część 2

Osiągniemy to poprzez VirtualService w połączeniu z DestinationRule, gdzie reguły określą podzbiory i trasy VirtualService do określonego podzbioru.

Definiowanie podzbiorów w regułach docelowych

Podzbiory (podzbiory) są określane przez następującą konfigurację (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. Gospodarz (host) określa, że ​​zasada ta ma zastosowanie jedynie w przypadkach, gdy trasa biegnie w stronę serwisu sa-logic;
  2. Tytuły (name) podzbiory są używane podczas routingu do instancji podzbiorów;
  3. Etykieta (label) definiuje pary klucz-wartość, które muszą pasować do instancji, aby stać się częścią podzbioru.

Zastosuj konfigurację za pomocą następującego polecenia:

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

Teraz, gdy podzbiory są już zdefiniowane, możemy przejść dalej i skonfigurować usługę VirtualService tak, aby stosowała reguły do ​​żądań kierowanych do sa-logic, tak aby:

  1. Skierowany do podzbioru v1,
  2. Odbicie lustrzane do podzbioru v2.

Poniższy manifest pozwala zrealizować Twoje plany (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

Nie ma tu potrzeby wyjaśniania, więc zobaczmy to w akcji:

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

Dodajmy obciążenie wywołując następującą komendę:

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

Przyjrzyjmy się wynikom w Grafanie, gdzie widać, że wersja z błędami (buggy) skutkuje niepowodzeniem w przypadku ~60% żądań, ale żadna z tych awarii nie ma wpływu na użytkowników końcowych, ponieważ odpowiada na nie działająca usługa.

Powrót do mikroserwisów z Istio. Część 2
Pomyślne odpowiedzi różnych wersji usługi sa-logic

Tutaj po raz pierwszy zobaczyliśmy, jak VirtualService jest stosowany wobec Posłów naszych usług: kiedy sa-web-app zwraca się z prośbą sa-logic, przechodzi przez usługę Sidecar Envoy, która — za pośrednictwem usługi VirtualService — jest skonfigurowana tak, aby kierować żądanie do podzbioru v1 i odzwierciedlać żądanie do podzbioru v2 usługi sa-logic.

Wiem, możesz już myśleć, że usługi wirtualne są proste. W następnej sekcji rozwiniemy tę kwestię, stwierdzając, że są one również naprawdę świetne.

Wdrożenia Kanaryjskie

Canary Deployment to proces wdrażania nowej wersji aplikacji dla małej liczby użytkowników. Służy do upewnienia się, że w wydaniu nie ma żadnych problemów i dopiero wtedy, mając już pewność co do jego jakości (wydania), rozpowszechnia się go wśród innych użytkowników.оwiększa publiczność.

Aby zademonstrować wdrożenia Canary, będziemy kontynuować pracę z podzbiorem buggy у sa-logic.

Nie traćmy czasu na drobnostki i od razu odsyłajmy 20% użytkowników do wersji z błędami (będzie to reprezentować nasz kanarekowy rollout), a pozostałe 80% do normalnej usługi. Aby to zrobić, użyj następującej usługi wirtualnej (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 to waga (weight), który określa procent żądań, które zostaną skierowane do odbiorcy lub jego podzbioru.

Zaktualizujmy poprzednią konfigurację VirtualService dla sa-logic za pomocą następującego polecenia:

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

... i od razu zobaczymy, że niektóre żądania prowadzą do niepowodzeń:

$ 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

Usługi wirtualne umożliwiają wdrażanie rozwiązań typu canary: w tym przypadku zawęziliśmy potencjalny wpływ problemów do 20% bazy użytkowników. Wspaniały! Teraz w każdym przypadku, gdy nie jesteśmy pewni naszego kodu (czyli zawsze...), możemy zastosować Mirroring i Canary Rollouts.

Przekroczenia limitu czasu i ponowne próby

Ale błędy nie zawsze kończą się w kodzie. Na liście z „8 błędnych przekonań na temat przetwarzania rozproszonego„Na pierwszym miejscu znajduje się błędne przekonanie, że „sieć jest niezawodna”. W rzeczywistości sieć nie niezawodne i z tego powodu potrzebujemy limitów czasu (przekroczenia limitu czasu) i ponawia próby (próby).

W celach demonstracyjnych będziemy nadal używać tej samej wersji problemu sa-logic (buggy), a my będziemy symulować zawodność sieci z przypadkowymi awariami.

Niech nasza usługa z błędami ma 1/3 szansy, że odpowiedź zajmie zbyt dużo czasu, 1/3 szansy, że zakończy się wewnętrznym błędem serwera i 1/3 szansy na pomyślne zwrócenie strony.

Aby złagodzić skutki takich problemów i poprawić życie użytkowników, możemy:

  1. dodaj timeout, jeśli reakcja usługi trwa dłużej niż 8 sekund,
  2. spróbuj ponownie, jeśli żądanie nie powiedzie się.

Do implementacji użyjemy następującej definicji zasobu (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. Limit czasu dla żądania jest ustawiony na 8 sekund;
  2. Żądania są ponawiane 3 razy;
  3. Każdą próbę uważa się za nieudaną, jeżeli czas odpowiedzi przekracza 3 sekundy.

Jest to optymalizacja, ponieważ użytkownik nie będzie musiał czekać dłużej niż 8 sekund, a w przypadku awarii podejmiemy trzy nowe próby uzyskania odpowiedzi, zwiększając szansę na pomyślną reakcję.

Zastosuj zaktualizowaną konfigurację za pomocą następującego polecenia:

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

I sprawdź na wykresach Grafana, czy liczba pomyślnych odpowiedzi wzrosła powyżej:

Powrót do mikroserwisów z Istio. Część 2
Ulepszenia statystyk pomyślnych odpowiedzi po dodaniu przekroczeń limitu czasu i ponownych prób

Zanim przejdziesz do następnej sekcji (a raczej do dalszej części artykułu, bo w tym nie będzie już praktycznych eksperymentów - ok. tł.), usuwać sa-logic-buggy i VirtualService, uruchamiając następujące polecenia:

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

Wzory wyłączników i przegród

Mówimy o dwóch ważnych wzorcach w architekturze mikrousług, które pozwalają na samoodzyskiwanie (samo leczenie) usługi.

Wyłącznik obwodu ("wyłącznik obwodu") służy do kończenia żądań przychodzących do wystąpienia usługi uważanej za niezdrową i przywracania jej, podczas gdy żądania klientów są przekierowywane do prawidłowych wystąpień tej usługi (co zwiększa procent pomyślnych odpowiedzi). (Uwaga: Bardziej szczegółowy opis wzoru można znaleźć np. tutaj.)

Przegroda ("przegroda") izoluje awarie usług od wpływu na cały system. Na przykład usługa B jest uszkodzona i inna usługa (klient usługi B) wysyła żądanie do usługi B, powodując wyczerpanie jej puli wątków i brak możliwości obsługi innych żądań (nawet jeśli nie pochodzą one z usługi B). (Uwaga: Bardziej szczegółowy opis wzoru można znaleźć np. tutaj.)

Pominę szczegóły implementacji tych wzorców, ponieważ łatwo je znaleźć oficjalna dokumentacja, a bardzo chcę też pokazać uwierzytelnianie i autoryzację, o czym będzie mowa w dalszej części artykułu.

PS od tłumacza

Przeczytaj także na naszym blogu:

Źródło: www.habr.com

Dodaj komentarz