Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions

Здраво, Хабр! Јас сум Артем Карамишев, шеф на тимот за системска администрација Mail.Ru Cloud Solutions (MCS). Имавме многу нови лансирања на производи во текот на изминатата година. Сакавме да осигураме дека API услугите се лесно скалабилни, толерантни на грешки и подготвени за брз раст на оптоварувањето на корисниците. Нашата платформа е имплементирана на OpenStack и сакам да ви кажам кои проблеми со толеранција на грешки моравме да ги решиме за да добиеме систем толерантен за грешки. Мислам дека ова ќе биде интересно за оние кои исто така развиваат производи на OpenStack.

Целокупната толеранција на грешки на платформата се состои од еластичноста на нејзините компоненти. Така постепено ќе поминуваме низ сите нивоа каде што ги идентификувавме ризиците и ги затворивме.

Видео верзија на оваа приказна, чиј примарен извор беше извештајот на конференцијата Uptime day 4, организирана од ТОА сума, можете да видите на каналот на YouTube Community Uptime.

Отпорност на физичката архитектура

Јавниот дел од облакот MCS сега е базиран во два центри за податоци од Tier III, меѓу нив има сопствено темно влакно, резервирано на физичко ниво по различни правци, со пропусната моќ од 200 Gbit/s. Нивото III го обезбедува потребното ниво на толеранција на грешки за физичката инфраструктура.

Темното влакно е резервирано и на физичко и на логично ниво. Процесот на резервација на каналот беше итеративен, се појавија проблеми и постојано ја подобруваме комуникацијата помеѓу центрите за податоци.

На пример, не така одамна, додека работеше во бунар во близина на еден од центрите за податоци, багер скрши цевка, а внатре во оваа цевка имаше и главен и резервен оптички кабел. Нашиот канал за комуникација со центарот за податоци, толерантен на грешки, се покажа дека е ранлив во еден момент, во бунарот. Според тоа, изгубивме дел од инфраструктурата. Донесовме заклучоци и презедовме голем број активности, вклучително и инсталирање дополнителна оптика во соседниот бунар.

Во центрите за податоци има точки на присуство на даватели на комуникација на кои ги пренесуваме нашите префикси преку BGP. За секоја мрежна насока, се избира најдобрата метрика, која овозможува на различни клиенти да им се обезбеди најдобар квалитет на врската. Ако комуникацијата преку еден провајдер се намали, ние ја обновуваме рутирањето преку достапните провајдери.

Ако провајдерот не успее, автоматски се префрламе на следниот. Во случај на дефект на еден од центрите за податоци, имаме огледална копија од нашите услуги во вториот центар за податоци, кои го преземаат целиот товар.

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
Отпорност на физичката инфраструктура

Што користиме за толеранција на грешки на ниво на апликација

Нашата услуга е изградена на голем број компоненти со отворен код.

ExaBGP е услуга која имплементира голем број функции користејќи го протоколот за динамичко рутирање базиран на BGP. Активно го користиме за да ги рекламираме нашите IP адреси на белата листа преку кои корисниците пристапуваат до API.

HAProxy е балансер со големо оптоварување кој ви овозможува да конфигурирате многу флексибилни правила за балансирање на сообраќајот на различни нивоа на моделот OSI. Го користиме за да балансираме пред сите услуги: бази на податоци, брокери за пораки, API услуги, веб-услуги, нашите внатрешни проекти - сè е зад HAProxy.

API апликација — веб апликација напишана во python, со која корисникот управува со својата инфраструктура и неговата услуга.

Апликација за работник (во натамошниот текст едноставно работник) - во услугите на OpenStack, ова е инфраструктурен демон кој ви овозможува да емитувате команди на API до инфраструктурата. На пример, креирањето диск се случува во работникот, а барањето за создавање се јавува во API на апликацијата.

Стандардна архитектура на апликации OpenStack

Повеќето услуги кои се развиени за OpenStack се обидуваат да следат една парадигма. Услугата обично се состои од 2 дела: API и работници (заднински извршители). Како по правило, API е апликација WSGI во python, која се лансира или како независен процес (демон), или со помош на готов веб-сервер Nginx или Apache. API го обработува барањето на корисникот и пренесува дополнителни инструкции до апликацијата на работникот за извршување. Преносот се случува со помош на брокер за пораки, обично RabbitMQ, а другите се слабо поддржани. Кога пораките ќе стигнат до брокерот, работниците ги обработуваат и, доколку е потребно, враќаат одговор.

Оваа парадигма вклучува изолирани заеднички точки на неуспех: RabbitMQ и базата на податоци. Но, RabbitMQ е изолиран во една услуга и, теоретски, може да биде индивидуален за секоја услуга. Така, во MCS ги одделуваме овие услуги колку што е можно повеќе за секој поединечен проект, создаваме посебна база на податоци, посебна RabbitMQ; Овој пристап е добар бидејќи во случај на несреќа на некои ранливи точки не се расипува целата услуга, туку само дел од неа.

Бројот на работни апликации е неограничен, така што API може лесно да се скалира хоризонтално зад балансерите со цел да ги зголеми перформансите и толеранцијата на грешки.

Некои услуги бараат координација во рамките на услугата кога се случуваат сложени последователни операции помеѓу API и работниците. Во овој случај, се користи единствен центар за координација, систем за кластери како што се Redis, Memcache, итн., кој му овозможува на еден работник да му каже на друг дека оваа задача му е доделена („ве молиме не преземајте ја“). Ние користиме etcd. Како по правило, работниците активно комуницираат со базата на податоци, пишуваат и читаат информации од таму. Ние користиме mariadb како база на податоци, која се наоѓа во мултимастер кластер.

Оваа класична единечна услуга е организирана на начин општо прифатен за OpenStack. Може да се смета како затворен систем, за кој методите на скалирање и толеранција на грешки се сосема очигледни. На пример, за толеранција на грешки на API, доволно е да се стави балансер пред нив. Скалирањето на работниците се постигнува со зголемување на нивниот број.

Слаба точка во целата шема се RabbitMQ и MariaDB. Нивната архитектура заслужува посебна статија Во оваа статија сакам да се фокусирам на толеранцијата на грешки во API.

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
Архитектура на апликации Openstack. Балансирање и толеранција на грешки на облак платформата

Направете го HAProxy балансерот толерантен на грешки користејќи ExaBGP

За да ги направиме нашите API-а скалабилни, брзи и толерантни на грешки, пред нив ставаме балансирач на оптоварување. Избравме HAProxy. Според мое мислење, ги има сите потребни карактеристики за нашата задача: балансирање на неколку OSI нивоа, интерфејс за управување, флексибилност и приспособливост, голем број методи за балансирање, поддршка за табели за сесии.

Првиот проблем што требаше да се реши беше толеранцијата на грешки на самиот балансер. Едноставното инсталирање на балансер, исто така, создава точка на неуспех: балансерот се расипува и услугата паѓа. За да спречиме тоа да се случи, користевме HAProxy во врска со ExaBGP.

ExaBGP ви овозможува да имплементирате механизам за проверка на состојбата на услугата. Го користевме овој механизам за да ја провериме функционалноста на HAProxy и, во случај на проблеми, да ја оневозможиме услугата HAProxy од BGP.

Шема ExaBGP+HAProxy

  1. На три сервери го инсталираме потребниот софтвер ExaBGP и HAProxy.
  2. На секој сервер создаваме интерфејс за враќање на јамката.
  3. На сите три сервери ја доделуваме истата бела IP адреса на овој интерфејс.
  4. Бела IP адреса се рекламира на Интернет преку ExaBGP.

Толеранцијата на грешки се постигнува со рекламирање на иста IP адреса од сите три сервери. Од мрежна гледна точка, истата адреса е достапна од три различни следни скокови. Рутерот гледа три идентични правци, го избира највисокиот приоритет од нив врз основа на сопствената метрика (ова е обично истата опција), а сообраќајот оди само на еден од серверите.

Во случај на проблеми со работата на HAProxy или дефект на серверот, ExaBGP престанува да ја објавува маршрутата и сообраќајот непречено се префрла на друг сервер.

Така, постигнавме толеранција на грешки на балансерот.

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
Толеранција на грешки на HAProxy балансерите

Шемата се покажа како несовршена: научивме како да резервираме HAProxy, но не научивме како да го дистрибуираме товарот во рамките на услугите. Затоа, малку ја проширивме оваа шема: преминавме на балансирање помеѓу неколку бели IP адреси.

Балансирање врз основа на DNS плус BGP

Прашањето за балансирање на оптоварување за нашиот HAProxy останува нерешено. Сепак, тоа може да се реши многу едноставно, како што направивме овде.

За да балансирате три сервери ќе ви требаат 3 бели IP адреси и стариот добар DNS. Секоја од овие адреси се определува на интерфејсот за повраток на секој HAProxy и се рекламира на Интернет.

Во OpenStack, за управување со ресурси, се користи директориум за услуги, кој го одредува API на крајната точка на одредена услуга. Во овој директориум регистрираме име на домен - public.infra.mail.ru, кое се решава преку DNS со три различни IP адреси. Како резултат на тоа, добиваме дистрибуција на оптоварување помеѓу три адреси преку DNS.

Но, бидејќи кога објавуваме бели IP адреси, не ги контролираме приоритетите за избор на сервер, ова сè уште не се балансира. Вообичаено, само еден сервер ќе биде избран врз основа на стажот на IP адресата, а другите два ќе бидат неактивен бидејќи не се специфицирани метрики во BGP.

Почнавме да испраќаме рути преку ExaBGP со различни метрики. Секој балансер ги рекламира сите три бели IP адреси, но една од нив, главната за овој балансер, се рекламира со минимална метрика. Така, додека сите три балансери се во функција, повиците до првата IP адреса одат до првиот балансер, повиците кон вториот кон вториот и повиците кон третата кон третата.

Што се случува кога еден од балансерите ќе падне? Ако некој балансер не успее, неговата главна адреса сè уште се рекламира од другите два, а сообраќајот се прераспределува меѓу нив. Така, на корисникот му даваме неколку IP адреси одеднаш преку DNS. Со балансирање по DNS и различни метрики, добиваме рамномерна распределба на оптоварувањето кај сите три балансери. И во исто време не губиме толеранција на грешки.

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
Балансирање на HAProxy врз основа на DNS + BGP

Интеракција помеѓу ExaBGP и HAProxy

Така, имплементиравме толеранција на грешки во случај серверот да замине, врз основа на прекин на објавувањето на маршрутите. Но, HAProxy може да се исклучи поради други причини освен неуспех на серверот: грешки во администрацијата, неуспеси во рамките на услугата. И во овие случаи сакаме да го отстраниме скршениот балансер од под оптоварување и ни треба поинаков механизам.

Затоа, проширувајќи ја претходната шема, имплементиравме чукање на срцето помеѓу ExaBGP и HAProxy. Ова е софтверска имплементација на интеракцијата помеѓу ExaBGP и HAProxy, кога ExaBGP користи сопствени скрипти за да го провери статусот на апликациите.

За да го направите ова, треба да конфигурирате здравствен проверувач во конфигурацијата ExaBGP, која може да го провери статусот на HAProxy. Во нашиот случај, го конфигуриравме здравствениот заднина во HAProxy, а од страната ExaBGP проверуваме со едноставно барање GET. Ако објавата престане да се случува, тогаш најверојатно HAProxy не работи и нема потреба да се рекламира.

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
HAProxy здравствена проверка

HAProxy Peers: синхронизација на сесии

Следното нешто што треба да се направи е да се синхронизираат сесиите. Кога работите преку дистрибуирани балансери, тешко е да се организира складирање на информации за сесиите на клиентите. Но, HAProxy е еден од ретките балансери кои можат да го направат ова поради функционалноста Peers - способноста за пренос на табели за сесии помеѓу различни процеси на HAProxy.

Постојат различни методи на балансирање: едноставни како на пр кружен робин, и проширена, кога ќе се памети сесијата на клиентот и секој пат кога тој завршува на истиот сервер како порано. Сакавме да ја спроведеме втората опција.

HAProxy користи залепени табели за да ги зачува сесиите на клиентот на овој механизам. Тие ја зачувуваат оригиналната IP адреса на клиентот, избраната целна адреса (заднина) и некои информации за услугата. Вообичаено, табелите со стапчиња се користат за складирање на пар извор-IP + дестинација-ИП, што е особено корисно за апликации кои не можат да го пренесат контекстот на сесијата на корисникот кога се префрлаат на друг балансер, на пример, во режимот за балансирање RoundRobin.

Ако стапче масата се научи да се движи помеѓу различни HAProxy процеси (помеѓу кои се случува балансирање), нашите балансери ќе можат да работат со еден базен од табели со стапчиња. Ова ќе овозможи беспрекорно префрлување на мрежата на клиентот, доколку еден од балансерите не успее, работата со сесиите на клиентот ќе продолжи на истите заднини што беа избрани претходно.

За правилно функционирање, мора да се реши проблемот со изворната IP адреса на балансерот од кој е воспоставена сесијата. Во нашиот случај, ова е динамична адреса на интерфејсот loopback.

Правилната работа на врсниците се постигнува само под одредени услови. Односно, TCP тајминутите мора да бидат доволно големи или префрлувањето мора да биде доволно брзо за TCP сесијата да нема време да се прекине. Сепак, тоа овозможува непречено префрлување.

Во IaaS имаме услуга изградена со користење на истата технологија. Ова Load Balancer како услуга за OpenStack, која се нарекува Октавија. Се заснова на два HAProxy процеси и првично вклучува поддршка за врсниците. Тие се покажаа одлични во оваа услуга.

Сликата шематски го прикажува движењето на табелите помеѓу три HAProxy инстанци, предложена е конфигурација за тоа како ова може да се конфигурира:

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
HAProxy Peers (синхронизација на сесии)

Ако ја имплементирате истата шема, нејзината работа мора внимателно да се тестира. Не е факт дека ќе работи на ист начин 100% од времето. Но, барем нема да ги изгубите табелите со стапчиња кога треба да ја запомните изворната IP IP на клиентот.

Ограничување на бројот на истовремени барања од ист клиент

Сите услуги што се јавно достапни, вклучувајќи ги и нашите API, може да бидат предмет на лавини барања. Причините за нив можат да бидат сосема различни, од кориснички грешки до насочени напади. Ние периодично сме DDoSed од IP адреси. Клиентите често прават грешки во нивните скрипти и ни даваат мини-DDoS.

На еден или друг начин, мора да се обезбеди дополнителна заштита. Очигледното решение е да се ограничи бројот на барања за API и да не се троши време на процесорот за обработка на малициозни барања.

За да ги имплементираме ваквите ограничувања, ние користиме ограничувања на стапката, организирани врз основа на HAProxy, користејќи ги истите табели со стапчиња. Поставувањето ограничувања е прилично едноставно и ви овозможува да го ограничите корисникот според бројот на барања до API. Алгоритмот ја памети изворната IP IP од која се поднесуваат барањата и го ограничува бројот на истовремени барања од еден корисник. Се разбира, го пресметавме просечниот профил на оптоварување на API за секоја услуга и поставивме граница од ≈ 10 пати од оваа вредност. Продолжуваме внимателно да ја следиме ситуацијата и да го држиме прстот на пулсот.

Како изгледа ова во пракса? Имаме клиенти кои постојано ги користат нашите API за автоматско скалирање. Тие создаваат приближно две до триста виртуелни машини наутро и ги бришат навечер. За OpenStack, создавањето виртуелна машина, исто така со PaaS услуги, бара најмалку 1000 барања за API, бидејќи интеракцијата помеѓу услугите се јавува и преку API.

Ваквиот пренос на задачи предизвикува прилично голем товар. Го проценивме ова оптоварување, собравме дневни врвови, десеткратно ги зголемивме и ова стана наша граница на стапка. Го држиме прстот на пулсот. Често гледаме ботови и скенери кои се обидуваат да погледнат во нас за да видат дали имаме CGA скрипти што може да се стартуваат, ние активно ги сечеме.

Како да ја ажурирате вашата база на кодови без да забележат корисниците

Ние, исто така, имплементираме толеранција на грешки на ниво на процеси за распоредување кодови. Може да има дефекти за време на пуштањето во употреба, но нивното влијание врз достапноста на услугата може да се минимизира.

Постојано ги ажурираме нашите услуги и мора да се погрижиме базата на кодови да се ажурира без да влијае на корисниците. Успеавме да го решиме овој проблем користејќи ги управувачките способности на HAProxy и имплементацијата на Graceful Shutdown во нашите услуги.

За да се реши овој проблем, неопходно беше да се обезбеди контрола на балансерот и „правилно“ исклучување на услугите:

  • Во случајот со HAProxy, контролата се врши преку статистичка датотека, која во суштина е сокет и е дефинирана во конфигурацијата HAProxy. Можете да испраќате команди до него преку stdio. Но, нашата главна алатка за контрола на конфигурацијата е ниска, така што има вграден модул за управување со HAProxy. Кои активно ги користиме.
  • Повеќето од нашите услуги API и Engine поддржуваат грациозни технологии за исклучување: при исклучување, тие чекаат да се заврши тековната задача, било да е тоа барање http или некоја услуга за задача. Истото се случува и со работникот. Ги знае сите задачи што ги прави и завршува кога успешно ќе заврши сè.

Благодарение на овие две точки, безбедниот алгоритам за нашето распоредување изгледа вака.

  1. Развивачот составува нов пакет код (за нас ова е RPM), го тестира во околината на dev, го тестира во фазата и го остава во складиштето на фазата.
  2. Програмерот ја поставува задачата за распоредување со најдетален опис на „артефактите“: верзијата на новиот пакет, опис на новата функционалност и други детали за распоредувањето доколку е потребно.
  3. Администраторот на системот го започнува ажурирањето. Ја лансира книгата за игри Ansible, која пак го прави следново:
    • Зема пакет од складиштето на сцената и го користи за ажурирање на верзијата на пакетот во складиштето на производи.
    • Составува листа на задни делови на ажурираната услуга.
    • Ја исклучува првата услуга што се ажурира во HAProxy и чека неговите процеси да завршат со работа. Благодарение на благодатното исклучување, уверени сме дека сите тековни барања на клиентите ќе завршат успешно.
    • Откако API-то и работниците се целосно прекинати и HAProxy е исклучен, кодот се ажурира.
    • Ansible работи услуги.
    • За секоја услуга, се влечат одредени „рачки“, кои вршат тестирање на единицата на одреден број претходно дефинирани тестови на клучеви. Се случува основна проверка на новиот код.
    • Ако не се пронајдени грешки во претходниот чекор, се активира задниот дел.
    • Ајде да преминеме на следниот бекенд.
  4. Откако ќе се ажурираат сите задни делови, се стартуваат функционалните тестови. Ако недостасуваат, тогаш развивачот ја разгледува секоја нова функционалност што ја создал.

Ова го комплетира распоредувањето.

Како се имплементира веб-архитектура толерантна за грешки во платформата Mail.ru Cloud Solutions
Циклус за ажурирање на услугата

Оваа шема не би функционирала доколку немаме едно правило. Ние ги поддржуваме и старата и новата верзија во битка. Однапред, во фазата на развој на софтвер, е пропишано дека дури и ако има промени во базата на податоци за услуги, тие нема да го скршат претходниот код. Како резултат на тоа, базата на кодови постепено се ажурира.

Заклучок

Споделувајќи ги моите сопствени размислувања за WEB архитектура толерантна за грешки, би сакал уште еднаш да ги забележам нејзините клучни точки:

  • толеранција на физичка грешка;
  • толеранција на грешки во мрежата (балансери, BGP);
  • толеранција на грешки на користениот и развиен софтвер.

Стабилно време на работа на сите!

Извор: www.habr.com

Додадете коментар