Святы завяршыліся, і мы вяртаемся з нашым другім пастом з серыі па Istio Service Mesh.
Сённяшняя тэма - Circuit Breaker, што ў перакладзе на рускую электратэхнічны азначае "аўтаматычны выключальнік", у прастамоўі - "аўтамат абароны". Толькі ў Istio гэты аўтамат адключае не які караціў або перагружаны ланцуг, а няспраўныя кантэйнеры.
Як гэта павінна працаваць у ідэале
Калі мікрасэрвісы кіруюцца Kubernetes'ам, напрыклад, у рамках платформы OpenShift, яны аўтаматычна маштабуецца ўверх-уніз у залежнасці ад нагрузкі. Паколькі мікрасэрвісы працуюць у pod'ах, на адной канчатковай кропцы можа быць адразу некалькі асобнікаў кантэйнерызаванага мікрасэрвісу, а Kubernetes будзе маршрутызаваць запыты і балансаваць нагрузку паміж імі. І - у ідэале - усё гэта павінна выдатна працаваць.
Мы памятаем, што мікрасэрвісы - маленькія і эфемерныя. Эфемернасць, якая тут азначае прастату ўзнікнення і знікнення, часта недаацэньваюць. Нараджэнне і смерць чарговага асобніка мікрасэрвісу ў pod'е - рэчы цалкам чаканыя, OpenShift і Kubernetes з гэтым добра спраўляюцца, і ўсё выдатна працуе - але зноў жа ў тэорыі.
Як гэта працуе на самой справе
А зараз прадстаўце, што нейкі пэўны асобнік мікрасэрвісу, то бок кантэйнер, прыйшоў у непрыдатнасць: альбо не адказвае (памылка 503), альбо – што непрыемней – рэагуе, але занадта павольна. Інакш кажучы, ён падглючвае ці не адказвае на запыты, але з пула ён пры гэтым аўтаматычна не прыбіраецца. Што трэба рабіць у гэтым выпадку? Паўтарыць спробу? Прыбраць яго са схемы маршрутызацыі? І што значыць "занадта павольна" - колькі гэта ў лічбах, і хто іх вызначае? Можа, проста даць яму паўзу і паспрабаваць пазней? Калі так, то наколькі пазней?
Што такое Pool Ejection у Istio
І тут на дапамогу прыходзіць Istio са сваімі аўтаматамі абароны Circuit Breaker, якія часова прыбіраюць няспраўныя кантэйнеры з пула рэсурсаў маршрутызацыі і балансаванні нагрузкі, рэалізуючы працэдуру Pool Ejection.
Выкарыстоўваючы стратэгію выяўлення адхіленняў (outlier detection), Istio дэтэктуе крывыя pod'ы, якія выбіваюцца з агульнага шэрагу, і прыбірае іх з пула рэсурсаў на зададзены час, якое завецца "акно сну" (sleep window).
Каб паказаць, як гэта працуе ў Kubernetes на платформе OpenShift, пачнем са скрыншота нармальна працуючых мікрасэрвісаў з прыкладу ў рэпазітары
Рыхтуемся да збою
Перш чым рабіць Pool Ejection, трэба стварыць правіла маршрутызацыі Istio. Дапушчальны, мы жадаем размяркоўваць запыты паміж pod'амі ў стаўленні 50/50. Акрамя таго, мы павялічым колькасць кантэйнераў v2 з аднаго да двух, вось так:
oc scale deployment recommendation-v2 --replicas=2 -n tutorial
Зараз задаем правіла маршрутызацыі, каб трафік размяркоўваўся паміж pod'амі ў стаўленні 50/50.
А вось як выглядае вынік працы гэтага правіла:
Можна прычапіцца, што на гэтым скрыне не 50/50, а 14:9, але з часам сітуацыя выправіцца.
Уладкоўваем збой
А зараз вывядзем са строю адзін з двух кантэйнераў v2, каб у нас быў адзін спраўны кантэйнер v1, адзін спраўны кантэйнер v2 і адзін няспраўны кантэйнер v2:
Чынім збой
Такім чынам, у нас ёсць няспраўны кантэйнер, і надышоў час Pool Ejection. З дапамогай вельмі простага канфіга мы выключым гэты збойны кантэйнер з любых схем маршрутызацыі на 15 секунд у разліку на тое, што ён сам вернецца ў спраўны стан (альбо перазапусціцца, альбо адновіць прадукцыйнасць). Вось як выглядае гэты канфіг і вынікі яго працы:
Як бачна, няспраўны кантэйнер v2 больш не выкарыстоўваецца пры маршрутызацыі запытаў, паколькі яго прыбралі з пула. Але па заканчэнні 15 секунд ён аўтаматычна вернецца ў пул. Уласна, мы толькі што паказалі, як працуе Pool Ejection.
Пачынаем будаваць архітэктуру
Pool Ejection у спалучэнні з магчымасцямі маніторынгу Istio дазваляе пачаць выбудоўваць фрэймворк аўтаматычнай замены няспраўных кантэйнераў, каб скараціць, а то і зусім ухіліць прастоі і збоі.
У NASA ёсць адзін гучны дэвіз - Failure Is Not an Option, аўтарам якога лічыцца кіраўнік палётаў
Istio, як мы ўжо пісалі вышэй, рэалізуе выдатна зарэкамендавалую сябе ў фізічным свеце канцэпцыю аўтаматычных выключальнікаў. І як электрычны аўтамат адключае праблемны ўчастак ланцуга, так і праграмны Circuit Breaker у Istio размыкае сувязь паміж струменем запытаў і праблемным кантэйнерам, калі з канчатковай кропкай нешта не ў парадку, напрыклад, калі сервер зваліўся ці пачаў тармазіць.
Прычым у другім выпадку праблем толькі больш, паколькі тормазы аднаго кантэйнера не толькі выклікаюць каскад затрымак у якія звяртаюцца да яго сэрвісах і, як следства, змяншаюць прадукцыйнасць сістэмы ў цэлым, але і спараджаюць паўтор запытаў да і так ужо павольна працавальнаму сэрвісу, што толькі пагаршае сітуацыю .
Circuit Breaker у тэорыі
Circuit Breaker - гэта проксі, які кантралюе паток да запытаў да канчатковай кропкі. Калі гэтая кропка перастае працаваць ці - у залежнасці ад зададзеных налад - пачынае тармазіць, проксі разрывае сувязь з кантэйнерам. Трафік пасля гэтага перанакіроўваецца на іншыя кантэйнеры, ну проста з-за балансавання нагрузкі. Сувязь застаецца растуленай (open) на працягу зададзенага акна сну, скажам, дзве хвіліны, а затым лічыцца напаўразмкнутай (half-open). Спроба даслаць наступны запыт вызначае далейшы стан сувязі. Калі з сэрвісам усё ОК, сувязь вяртаецца ў працоўны стан і зноў становіцца замкнёнай (closed). Калі ж з сэрвісам па-ранейшаму нешта не тое, сувязь размыкаецца і зноўку ўключаецца акно сну. Вось як выглядае спрошчаная дыяграма змены станаў Circuit Breaker:
Тут важна адзначыць, што ўсё гэта адбываецца на ўзроўні, так бы мовіць, сістэмнай архітэктуры. Таму ў нейкі момант вам давядзецца навучыць свае прыкладанні працаваць з Circuit Breaker, напрыклад, прадастаўляць у адказ значэнне па змаўчанні ці ж, калі гэта магчыма, ігнараваць існаванне сэрвісу. Для гэтага выкарыстоўваецца bulkhead pattern, але ён выходзіць за рамкі гэтага артыкула.
Circuit Breaker на практыцы
Для прыкладу мы запусцім на OpenShift дзве версіі нашага мікрасэрвісу рэкамендацый. Версія 1 будзе працаваць нармальна, а вось у v2 мы ўбудуем затрымку, каб імітаваць тормазы на серверы. Для прагляду вынікаў выкарыстоўваецца інструмент
siege -r 2 -c 20 -v customer-tutorial.$(minishift ip).nip.io
Усё быццам бы працуе, але якім коштам? На першы погляд у нас 100% даступнасць, але прыгледзьцеся - максімальная працягласць транзакцыі складае цэлых 12 секунд. Гэта відавочна вузкае месца, і яго трэба расшываць.
Для гэтага мы з дапамогай Istio выключым звароты да павольных кантэйнераў. Вось як выглядае адпаведны канфіг з выкарыстаннем Circuit Breaker:
Апошні радок з параметрам httpMaxRequestsPerConnection сігналізуе, што сувязь з павінна размыкацца пры спробе стварыць яшчэ адно - другое - падлучэнне ў дадатак да ўжо наяўнага. Паколькі наш кантэйнер імітуе які тармозіць сэрвіс, такія сітуацыі будуць перыядычна ўзнікаць, і тады Istio будзе вяртаць памылку 503, а вось што пакажа siege:
Добра, у нас ёсць Circuit Breaker, што далей?
Такім чынам, мы рэалізавалі аўтаматычнае адключэнне, зусім не чапаючы зыходны код саміх сэрвісаў. Выкарыстоўваючы Circuit Breaker і апісаную вышэй працэдуру Pool Ejection, мы можам прыбіраць з пула рэсурсаў тармазныя кантэйнеры датуль, пакуль яны не прыйдуць у норму, і правяраць іх стан з зададзенай перыядычнасцю у нашым прыкладзе, гэта дзве хвіліны (параметр sleepWindow).
Звярніце ўвагу, што здольнасць прыкладання рэагаваць на памылку 503 усё яшчэ задаецца на ўзроўні яго зыходнага кода. Існуе мноства стратэгій працы з Circuit Breaker, якія прымяняюцца ў залежнасці ад сітуацыі.
У наступным пасце: раскажам аб трасіроўцы і маніторынгу, якія ўжо ўбудаваны або лёгка дадаюцца ў Istio, а таксама аб тым, як уносіць памылкі ў сістэму наўмысна.
Крыніца: habr.com