Wyłącznik Istio: wyłączanie wadliwych pojemników

Wakacje dobiegły końca i wracamy z drugim postem z serii Istio Service Mesh.

Wyłącznik Istio: wyłączanie wadliwych pojemników

Dzisiejszym tematem jest wyłącznik, co w języku rosyjskim oznacza „wyłącznik”, w potocznym języku – „wyłącznik”. Tylko w Istio ta maszyna rozłącza nie zwarty lub przeciążony obwód, ale uszkodzone pojemniki.

Jak to powinno działać idealnie

Gdy mikrousługi są zarządzane przez Kubernetes, na przykład w ramach platformy OpenShift, automatycznie skalują się w górę i w dół w zależności od obciążenia. Ponieważ mikrousługi działają w zasobnikach, w jednym punkcie końcowym może znajdować się wiele instancji skonteneryzowanej mikrousługi, a Kubernetes będzie kierować żądania i równoważyć obciążenie między nimi. I – idealnie – wszystko to powinno działać idealnie.

Pamiętamy, że mikroserwisy są małe i efemeryczne. Efemeryczność, czyli łatwość pojawiania się i znikania, jest często niedoceniana. Narodziny i śmierć kolejnej instancji mikrousługi w podzespole są dość oczekiwanymi rzeczami, OpenShift i Kubernetes radzą sobie z tym dobrze i wszystko działa świetnie - ale znowu w teorii.

Jak to naprawdę działa

A teraz wyobraźcie sobie, że konkretna instancja mikrousługi, czyli kontenera, stała się bezużyteczna: albo nie odpowiada (błąd 503), albo, co jest bardziej nieprzyjemne, odpowiada, ale zbyt wolno. Innymi słowy, działa nieprawidłowo lub nie odpowiada na żądania, ale nie jest automatycznie usuwany z puli. Co należy zrobić w tym przypadku? Ponowić próbę? Czy powinienem usunąć go ze schematu routingu? A co to znaczy „za wolno” – ile to jest w liczbach i kto je ustala? Może po prostu daj sobie spokój i spróbuj ponownie później? Jeśli tak, to ile później?

Co to jest wyrzucanie puli w Istio

I tutaj Istio przychodzi z pomocą ze swoimi maszynami zabezpieczającymi wyłączniki automatyczne, które tymczasowo usuwają wadliwe kontenery z puli zasobów routingu i równoważenia obciążenia, wdrażając procedurę Pool Ejection.

Korzystając ze strategii wykrywania wartości odstających, Istio wykrywa pody krzywych, które są poza linią i usuwa je z puli zasobów na określony czas, zwany oknem uśpienia.

Aby pokazać jak to działa w Kubernetesie na platformie OpenShift zacznijmy od zrzutu ekranu normalnie działających mikroserwisów z przykładu w repozytorium Demo programistów Red Hat. Tutaj mamy dwa zasobniki, v1 i v2, każdy obsługujący jeden kontener. Gdy reguły routingu Istio nie są używane, Kubernetes domyślnie stosuje równomiernie zrównoważony routing okrężny:

Wyłącznik Istio: wyłączanie wadliwych pojemników

Przygotowanie na wypadek

Przed wykonaniem wyrzucenia puli musisz utworzyć regułę routingu Istio. Załóżmy, że chcemy dystrybuować żądania między podami w stosunku 50/50. Dodatkowo zwiększymy liczbę kontenerów v2 z jednego do dwóch, w następujący sposób:

oc scale deployment recommendation-v2 --replicas=2 -n tutorial

Teraz ustawiamy regułę routingu tak, aby ruch był rozdzielany pomiędzy podami w stosunku 50/50.

Wyłącznik Istio: wyłączanie wadliwych pojemników
Oto jak wygląda wynik tej reguły:

Wyłącznik Istio: wyłączanie wadliwych pojemników
Zarzucić można temu, że to ekran nie 50/50, a 14:9, ale z biegiem czasu sytuacja będzie się poprawiać.

Robienie usterki

Teraz wyłączmy jeden z dwóch kontenerów v2, abyśmy mieli jeden zdrowy kontener v1, jeden zdrowy kontener v2 i jeden wadliwy kontener v2:

Wyłącznik Istio: wyłączanie wadliwych pojemników

Naprawianie usterki

Mamy więc wadliwy pojemnik i czas na Pool Ejection. Stosując bardzo prostą konfigurację, wykluczymy ten uszkodzony kontener z wszelkich schematów routingu na 15 sekund w nadziei, że powróci do prawidłowego stanu (restart lub przywrócenie wydajności). Tak wygląda ten konfig i efekty jego pracy:

Wyłącznik Istio: wyłączanie wadliwych pojemników
Wyłącznik Istio: wyłączanie wadliwych pojemników
Jak widać, uszkodzony kontener v2 nie jest już używany do routingu żądań, ponieważ został usunięty z puli. Ale po 15 sekundach automatycznie powróci do basenu. Właściwie właśnie pokazaliśmy, jak działa Pool Ejection.

Zacznijmy budować architekturę

Pool Ejection w połączeniu z możliwościami monitorowania Istio umożliwia rozpoczęcie tworzenia struktury automatycznej wymiany wadliwych kontenerów w celu ograniczenia, jeśli nie wyeliminowania, przestojów i awarii.

NASA ma jedno głośne motto – Porażka nie wchodzi w grę, którego autor uważany jest za dyrektora lotu Gene Kranz. Można to przetłumaczyć na rosyjski jako „Porażka nie wchodzi w grę”, a oznacza to, że wszystko można sprawić, by zadziałało, jeśli masz wystarczającą wolę. Jednak w prawdziwym życiu niepowodzenia nie zdarzają się po prostu, są nieuniknione, wszędzie i we wszystkim. A jak sobie z nimi poradzić w przypadku mikroserwisów? Naszym zdaniem lepiej polegać nie na sile woli, a na możliwościach kontenerów, Kubernetes, Red Hat OpenShifti Podobnie.

Istio, jak pisaliśmy powyżej, realizuje koncepcję wyłączników, która doskonale sprawdziła się w świecie fizycznym. I tak jak wyłącznik elektryczny wyłącza problematyczną część obwodu, oprogramowanie Istio Circuit Breaker otwiera połączenie między strumieniem żądań a kontenerem problemów, gdy coś jest nie tak z punktem końcowym, na przykład gdy serwer się zawiesił lub zaczął działać. Kierowco zwolnij.

Co więcej, w drugim przypadku problemów jest tylko więcej, gdyż hamulce jednego kontenera nie tylko powodują kaskadę opóźnień w dostępie do niego służb i w rezultacie zmniejszają wydajność całego systemu, ale także generują powtarzające się żądań do i tak już wolno działającej usługi, co tylko pogarsza sytuację.

Przerywacz w teorii

Circuit Breaker to serwer proxy kontrolujący przepływ żądań do punktu końcowego. Gdy ten punkt przestanie działać lub w zależności od określonych ustawień zacznie zwalniać, proxy zrywa połączenie z kontenerem. Ruch jest następnie przekierowywany do innych kontenerów, po prostu ze względu na równoważenie obciążenia. Połączenie pozostaje otwarte przez dane okno uśpienia, powiedzmy dwie minuty, a następnie jest uznawane za półotwarte. Próba wysłania kolejnego żądania decyduje o dalszym stanie połączenia. Jeśli wszystko jest w porządku z usługą, połączenie wraca do stanu roboczego i ponownie zostaje zamknięte. Jeśli nadal coś jest nie tak z usługą, połączenie zostanie rozłączone i okno uśpienia zostanie ponownie włączone. Oto jak wygląda uproszczony diagram stanu wyłącznika:

Wyłącznik Istio: wyłączanie wadliwych pojemników
Warto tutaj zaznaczyć, że wszystko to dzieje się na poziomie, że tak powiem, architektury systemu. Zatem w pewnym momencie będziesz musiał nauczyć swoje aplikacje współpracy z wyłącznikiem, na przykład podając w odpowiedzi wartość domyślną lub, jeśli to możliwe, ignorować istnienie usługi. Stosowany jest w tym celu wzór grodzi, ale wykracza to poza zakres tego artykułu.

Wyłącznik automatyczny w praktyce

Na przykład uruchomimy dwie wersje naszego mikrousługi rekomendacyjnej na OpenShift. Wersja 1 będzie działać dobrze, ale w wersji 2 wbudujemy opóźnienie, aby symulować spowolnienie na serwerze. Aby zobaczyć wyniki użyj narzędzia oblężenie:

siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io

Wyłącznik Istio: wyłączanie wadliwych pojemników
Wszystko wydaje się działać, ale jakim kosztem? Na pierwszy rzut oka mamy 100% dostępności, ale przyjrzyjmy się bliżej – maksymalny czas trwania transakcji to aż 12 sekund. Jest to wyraźnie wąskie gardło i należy je rozszerzyć.

Aby to zrobić, użyjemy Istio, aby wyeliminować wywołania powolnych kontenerów. Tak wygląda odpowiednia konfiguracja przy użyciu wyłącznika:

Wyłącznik Istio: wyłączanie wadliwych pojemników
Ostatnia linijka z parametrem httpMaxRequestsPerConnection sygnalizuje, że należy rozłączyć połączenie przy próbie utworzenia kolejnego - drugiego - połączenia oprócz już istniejącego. Ponieważ nasz kontener symuluje powolną usługę, takie sytuacje będą pojawiać się okresowo, a wtedy Istio zwróci błąd 503, ale oto co pokaże oblężenie:

Wyłącznik Istio: wyłączanie wadliwych pojemników

OK, mamy wyłącznik automatyczny, co dalej?

Dlatego wdrożyliśmy automatyczne zamykanie bez dotykania kodu źródłowego samych usług. Wykorzystując Circuit Breaker i opisaną powyżej procedurę Pool Ejection, możemy usuwać kontenery hamulcowe z puli zasobów do czasu, aż powrócą do normy, a także sprawdzać ich stan z określoną częstotliwością - w naszym przykładzie są to dwie minuty (parametr SleepWindow).

Należy pamiętać, że zdolność aplikacji do reagowania na błąd 503 jest nadal ustawiana na poziomie kodu źródłowego. Istnieje wiele strategii korzystania z wyłącznika, w zależności od sytuacji.

W następnym poście: Porozmawiamy o śledzeniu i monitorowaniu, które jest już wbudowane lub łatwo dodane do Istio, a także o tym, jak celowo wprowadzać błędy do systemu.

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

Dodaj komentarz