Назад да мікрасэрвісаў разам з Istio. Частка 2

Назад да мікрасэрвісаў разам з Istio. Частка 2

Заўв. перав.: Першая частка гэтага цыклу была прысвечана знаёмству з магчымасцямі Istio і іх дэманстрацыі ў дзеянні. Зараз жа гаворка пойдзе пра больш складаныя аспекты канфігурацыі і выкарыстанні гэтага service mesh, а ў прыватнасці – пра тонка наладжвальную маршрутызацыю і кіраванне сеткавым трафікам.

Нагадваем таксама, што ў артыкуле выкарыстоўваюцца канфігурацыі (маніфесты для Kubernetes і Istio) з рэпазітара istio-mastery.

Упраўленне трафікам

З Istio у кластары з'яўляюцца новыя магчымасці, якія дазваляюць забяспечыць:

  • Дынамічную маршрутызацыю запытаў: канарэечныя выкаты, A/B-тэставанне;
  • Балансаванне нагрузкі: простую і несупярэчлівую, заснаваную на хэшах;
  • Аднаўленне пасля падзенняў: таймаўты, паўторныя спробы, circuit breakers;
  • Унясенне няспраўнасцяў: затрымкі, абрыў запытаў і да т.п.

У працягу артыкула гэтыя магчымасці будуць паказаны на прыкладзе абранага прыкладання і адначасна прадстаўлены новыя канцэпцыі. Першай такой канцэпцыяй стане DestinationRules (г.зн. правілы аб атрымальніку трафіку/запытаў — заўв. перакл.), з дапамогай якіх мы актывуем A/B-тэставанне.

A/B-тэставанне: DestinationRules на практыцы

A/B-тэставанне ўжываецца ў выпадках, калі існуюць дзве версіі прыкладання (звычайна яны адрозніваюцца візуальна) і мы не ўпэўненыя на 100%, якая з іх палепшыць узаемадзеянне з карыстачом. Таму мы адначасова запускаем абедзве версіі і збіраем метрыкі.

Для дэплою другой версіі фронтэнда, неабходнай для дэманстрацыі A/B-тэставанні, выканайце наступную каманду:

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

Маніфест deployment'а для "зялёнай версіі" адрозніваецца ў двух месцах:

  1. Вобраз заснаваны на іншым тэгу istio-green,
  2. Pod'ы маюць лэйбл version: green.

Паколькі абодва deployment'а маюць лэйбл app: sa-frontend, запыты, якія маршрутызуюцца віртуальным сэрвісам sa-external-services на сэрвіс sa-frontend, будуць перанакіраваны на ўсе яго экзэмпляры і нагрузка размяркуецца пасродкам алгарытму round-robin, што прывядзе да наступнай сітуацыі:

Назад да мікрасэрвісаў разам з Istio. Частка 2
Запытаныя файлы не знойдзены

Гэтыя файлы не былі знойдзены з-за таго, што яны па-рознаму называюцца ў розных версіях дадатку. Давайце пераканаемся ў гэтым:

$ 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

Гэта азначае, што index.html, які запытвае адну версію статычных файлаў, можа быць адпраўлены балансавальнікам нагрузкі на pod'ы, якія маюць іншую версію, дзе, па зразумелых чынніках, такіх файлаў не існуе. Таму для таго, каб прыкладанне зарабіла, нам неабходна паставіць абмежаванне: «тая ж версія прыкладання, што аддала index.html, павінна абслужыць і наступныя запыты.

Мы даможамся мэты з дапамогай несупярэчлівага балансавання нагрузкі на аснове хэшаў (Consistent Hash Loadbalancing). У гэтым выпадку запыты ад аднаго кліента адпраўляюцца ў адзін і той жа асобнік бэкенда, для чаго выкарыстоўваецца прадвызначаная ўласцівасць - напрыклад, HTTP-загаловак. Рэалізуецца з дапамогай DestinationRules.

DestinationRules

Пасля таго, як VirtualService накіраваў запыт у патрэбны сэрвіс, з дапамогай DestinationRules мы можам вызначыць палітыкі, якія будуць прымяняцца да трафіку, які прызначаецца экзэмплярам гэтага сэрвісу:

Назад да мікрасэрвісаў разам з Istio. Частка 2
Упраўленне трафікам з рэсурсамі Istio

Заўвага: Уплыў рэсурсаў Istio на сеткавы трафік прадстаўлены тут у спрошчаным для разумення выглядзе. Калі быць дакладным, тое рашэнне, на які асобнік адпраўляць запыт, робіцца Envoy'ем у Ingress Gateway, наладжаным у CRD.

З дапамогай Destination Rules мы можам наладзіць балансаванне нагрузкі так, каб выкарыстоўваліся несупярэчлівыя хэшы і гарантаваліся адказы аднаго і таго ж асобніка сэрвісу аднаму і таму ж карыстачу. Наступная канфігурацыя дазваляе дамагчыся гэтага (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 - хэш будзе генеравацца на аснове змесціва HTTP-загалоўка version.

Ужывяце канфігурацыю наступнай камандай:

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

А зараз выканайце каманду ніжэй і пераканайцеся, што атрымліваеце патрэбныя файлы, калі паказваеце загаловак version:

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

Заўвага: Каб дадаваць розныя значэнні ў загалоўку і тэставаць вынікі прама ў браўзэры, можна скарыстацца гэтым пашырэннем да Chrome (Або вось гэтым для Firefox - заўв. перав.).

Наогул жа, у DestinationRules ёсць больш магчымасцяў у вобласці балансавання нагрузкі - падрабязнасці ўдакладняйце ў афіцыйнай дакументацыі.

Перад тым, як вывучаць VirtualService далей, выдалім "зялёную версію" прыкладання і адпаведнае правіла па кірунку трафіку, выканаўшы наступныя каманды:

$ 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

Люстраванне: Virtual Services на практыцы

Зацяненне («экранаванне») ці Mirroring («люстраванне») ужываецца ў тых выпадках, калі мы жадаем пратэставаць змену ў production, не закрануўшы канчатковых карыстачоў: для гэтага мы дублюем («люстраваны») запыты на другі асобнік, дзе здзейсненыя патрэбныя змены, і глядзім на наступствы. Прасцей кажучы, гэта калі ваш(а) калега выбірае самы крытычны issue і робіць pull request у выглядзе такога велізарнага камяка бруду, што ніхто не можа ў рэчаіснасці зрабіць яму рэўю.

Каб праверыць гэты сцэнар у дзеянні, створым другі асобнік SA-Logic з багамі.buggy), выканаўшы наступную каманду:

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

І зараз выканаем каманду, каб пераканацца, што ўсе асобнікі з app=sa-logic маюць яшчэ і лэйблы з адпаведнымі версіямі:

$ 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

Сэрвіс sa-logic накіраваны на pod'ы з лэйблам app=sa-logic, таму ўсе запыты будуць размеркаваны паміж усімі асобнікамі:

Назад да мікрасэрвісаў разам з Istio. Частка 2

… але мы жадаем, каб запыты накіроўваліся на асобнікі з версіяй v1 і люстэркаваліся на асобнікі з версіяй v2:

Назад да мікрасэрвісаў разам з Istio. Частка 2

Даб'емся гэтага праз VirtualService у камбінацыі з DestinationRule, дзе правілы вызначаць падмноствы і маршруты VirtualService да пэўнага падмноства.

Вызначэнне падмноства ў Destination Rules

Падмноствы (subsets) вызначаюцца наступнай канфігурацыяй (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. Хост (host) вызначае, што гэтае правіла ўжываецца толькі да выпадкаў, калі маршрут ідзе ў бок сэрвісу. sa-logic;
  2. Назвы (name) падмноства выкарыстоўваюцца пры маршрутызацыі на экзэмпляры падмноства;
  3. Лейбл (label) вызначае пары ключ-значэнне, якім павінны адпавядаць асобнікі, каб стаць часткай падмноства.

Ужывяце канфігурацыю наступнай камандай:

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

Цяпер, калі падмноства вызначаны, можна рухацца далей і наладзіць VirtualService, каб прымяніць правілы да запытаў да sa-logic, каб яны:

  1. Маршрутызаваліся да падмноства v1,
  2. Люстэркаваліся да падмноства v2.

Наступны маніфест дазваляе дамагчыся задуманага (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

Тлумачэнні тут не патрабуюцца, так што проста паглядзім у дзеянні:

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

Дадамо нагрузку выклікам такой каманды:

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

Паглядзім на вынікі ў Grafana, дзе можна ўбачыць, што версія з багамі (buggy) прыводзіць да збою для ~60 % запытаў, але ніводны з гэтых збояў не закранае канчатковых карыстальнікаў, паколькі ім адказвае працуючы сэрвіс.

Назад да мікрасэрвісаў разам з Istio. Частка 2
Паспяховасць адказаў розных версій сервісу sa-logic

Тут мы ўпершыню ўбачылі, як VirtualService прымяняецца ў адносінах да Envoy'ям нашых сэрвісаў: калі sa-web-app робіць запыт да sa-logic, ён праходзіць праз sidecar Envoy, які - праз VirtualService - настроены на маршрутызацыю запыту да падмноства v1 і люстраванню запыту да падмноства v2 сэрвісу sa-logic.

Ведаю: вы паспелі ўжо падумаць, што Virtual Services простыя. У наступным раздзеле мы пашырым гэтае меркаванне тым, што яны яшчэ і па-сапраўднаму пышныя.

Канарэечныя выкаты

Canary Deployment - працэс выкочвання новай версіі прыкладання для невялікай колькасці карыстальнікаў. Яго выкарыстоўваюць, каб пераканацца ў адсутнасці праблем у рэлізе і толькі пасля гэтага, ужо будучы ўпэўненым у дастатковай яго (рэлізу) якасці, распаўсюдзіць на большую аўдыторыю.

Для дэманстрацыі канарэечных выкатаў мы працягнем працу з падмноствам buggy у sa-logic.

Не будзем драбязніцца і адразу ж адправім 20% карыстачоў на версію з багамі (яна і будзе ўяўляць наш канарэечны выкат), а пакінутыя 80% - на нармальны сэрвіс. Для гэтага прымянім наступны 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 - гэта вага (weight), які вызначае працэнт запытаў, якія будуць накіраваны на атрымальніка або падмноства атрымальніка.

Абновім мінулую канфігурацыю VirtualService для sa-logic наступнай камандай:

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

… і адразу ж убачым, што частка запытаў прыводзіць да збояў:

$ 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 актывуюць канарэечныя выкаты: у дадзеным выпадку мы звузілі патэнцыйныя наступствы ад праблем да 20% ад карыстацкай базы. Выдатна! Цяпер у кожным выпадку, калі мы не ўпэўненыя ў сваім кодзе (іншымі словамі – заўсёды…), мы можам выкарыстоўваць люстраванне і канарэечныя выкаты.

Таймаўты і паўторныя спробы

Але не заўсёды багі аказваюцца ў кодзе. У спісе з «8 памылак у размеркаваных вылічэннях» на першым месцы значыцца памылковае меркаванне, што «сетка надзейная». Насамрэч сетка ня надзейная, і з гэтай прычыны нам патрэбныя таймаўты (timeouts) і паўторныя спробы (паўторныя спробы).

Для дэманстрацыі мы працягнем выкарыстоўваць тую ж праблему версію sa-logic (buggy), а ненадзейнасць сеткі будзем сімуляваць выпадковымі збоямі.

Няхай наш сэрвіс з багамі мае 1/3 шанец на занадта доўгі адказ, 1/3 – на завяршэнне з памылкай Internal Server Error і 1/3 – на паспяховую аддачу старонкі.

Каб змякчыць наступствы ад падобных праблем і зрабіць жыццё карыстальнікаў лепшым, мы можам:

  1. дадаць таймаўт, калі сэрвіс адказвае даўжэй 8 секунд,
  2. рабіць паўторную спробу, калі ў запыту адбываецца збой.

Для рэалізацыі скарыстаемся такім вызначэннем рэсурсу (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. Таймаўт для запыту ўсталяваны ў 8 секунд;
  2. Паўторныя спробы запытаў прадпрымаюцца па 3 разы;
  3. І кожная спроба лічыцца няўдалай, калі час адказу перавышае 3 сэкунды.

Так мы дамагліся аптымізацыі, паколькі карыстачу не прыйдзецца чакаць больш за 8 секунд і мы зробім тры новыя спробы атрымаць адказ у выпадку збояў, падвышаючы шанец на паспяховы адказ.

Ужывайце абноўленую канфігурацыю наступнай камандай:

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

І праверце ў графіках Grafana, што колькасць паспяховых адказаў стала звыш:

Назад да мікрасэрвісаў разам з Istio. Частка 2
Паляпшэнні ў статыстыцы паспяховых адказаў пасля дадання таймаўтаў і паўторных спроб

Перад тым, як пераходзіць да наступнай часткі (а дакладней - ужо да наступнай часткі артыкула, т.к. у гэтай практычных эксперыментаў больш не будзе - заўв. перакл.), выдаліце sa-logic-buggy і VirtualService, выканаўшы наступныя каманды:

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

Патэрны Circuit Breaker і Bulkhead

Гаворка ідзе пра два важныя патэрны ў мікрасэрвіснай архітэктуры, якія дазваляюць дамагчыся самастойнага аднаўлення. (self-healing) сэрвісаў.

аўтаматычны выключальнік («аўтаматычны выключальнік») выкарыстоўваецца для спынення запытаў, якія паступаюць на асобнік сэрвісу, які лічыцца нездаровым, і яго аднаўлення ў той час, як запыты кліентаў перанакіроўваюцца на здаровыя экзэмпляры гэтага сэрвісу (што павышае працэнт паспяховых адказаў). (Заўв. перакл.: Больш падрабязнае апісанне патэрна можна знайсці, напрыклад, тут.)

Пераборка («перагародка») ізалюе збоі ў сэрвісах ад паразы ўсёй сістэмы. Напрыклад, сэрвіс B зламаны, а іншы сэрвіс (кліент сэрвісу B) робіць запыт да сэрвісу B, у выніку чаго ён выдаткуе свой пул патокаў і не зможа абслугоўваць іншыя запыты (нават калі яны не адносяцца да сэрвісу B). (Заўв. перакл.: Больш падрабязнае апісанне патэрна можна знайсці, напрыклад, тут.)

Я апушчу дэталі па рэалізацыі гэтых патэрнаў, таму што іх лёгка знайсці ў афіцыйнай дакументацыі, а таксама вельмі ўжо хочацца паказаць аўтэнтыфікацыю і аўтарызацыю, пра што і пойдзе размова ў наступнай частцы артыкула.

PS ад перакладчыка

Чытайце таксама ў нашым блогу:

Крыніца: habr.com

Дадаць каментар