
Сәлем, Хабр! Мен Артем Карамышев, жүйе әкімшілігі тобының жетекшісімін . Өткен жылы бізде көптеген жаңа өнімдер шығарылды. Біз API қызметтерінің оңай масштабталатын, ақауларға төзімді және пайдаланушы жүктемесінің жылдам өсуіне дайын болуын қамтамасыз еткіміз келді. Біздің платформа OpenStack жүйесінде жүзеге асырылады және мен сізге ақауларға төзімді жүйені алу үшін қандай компоненттердің ақауларына төзімділік мәселелерін шешу керек екенін айтқым келеді. Менің ойымша, бұл OpenStack-те өнімдерді әзірлейтіндер үшін қызықты болады.
Платформаның жалпы ақауларға төзімділігі оның құрамдас бөліктерінің тұрақтылығынан тұрады. Сондықтан біз тәуекелдерді анықтап, оларды жапқан барлық деңгейлерден біртіндеп өтеміз.
Бұл оқиғаның бейне нұсқасы, оның негізгі көзі Uptime day 4 конференциясындағы есеп болды, ұйымдастырған , көруге болады .
Физикалық архитектураның төзімділігі
MCS бұлтының жалпыға ортақ бөлігі қазір екі деңгейлі III деректер орталықтарында негізделген, олардың арасында физикалық деңгейде әртүрлі маршруттар бойынша сақталған, өткізу қабілеті 200 Гбит/с болатын өзінің қараңғы талшығы бар. III деңгей физикалық инфрақұрылым үшін ақауларға төзімділіктің қажетті деңгейін қамтамасыз етеді.
Қараңғы талшық физикалық және логикалық деңгейде сақталады. Арналарды брондау процесі қайталанатын болды, проблемалар туындады және біз деректер орталықтары арасындағы байланысты үнемі жетілдіреміз.
Мәселен, көп ұзамай деректер орталықтарының бірінің жанындағы құдықта жұмыс істеп жатқанда экскаватор құбырды сындырып, бұл құбырдың ішінде магистральдық және резервтік оптикалық кабель де болған. Дата орталығымен ақауға төзімді байланыс арнамыз бір нүктеде, ұңғымада осал болып шықты. Сәйкесінше, біз инфрақұрылымның бір бөлігін жоғалттық. Қорытынды жасап, бірқатар шараларды қолға алдық, соның ішінде көрші ұңғымаға қосымша оптика орнату.
Деректер орталықтарында біз BGP арқылы префикстерімізді тарататын байланыс провайдерлерінің қатысу нүктелері бар. Әрбір желі бағыты үшін әртүрлі клиенттерге ең жақсы қосылым сапасын қамтамасыз етуге мүмкіндік беретін ең жақсы көрсеткіш таңдалады. Егер бір провайдер арқылы байланыс үзілсе, біз маршрутымызды қолжетімді провайдерлер арқылы қалпына келтіреміз.
Егер провайдер сәтсіз болса, біз автоматты түрде келесіге ауысамыз. Дата орталықтарының бірі істен шыққан жағдайда, бізде бүкіл жүктемені алатын екінші деректер орталығында қызметтеріміздің айнадағы көшірмесі бар.

Физикалық инфрақұрылымның тұрақтылығы
Қолданба деңгейіндегі ақауларға төзімділік үшін не қолданамыз
Біздің қызметіміз бірнеше ашық бастапқы құрамдастарға негізделген.
ExaBGP BGP негізіндегі динамикалық бағыттау хаттамасын пайдаланып, бірқатар функцияларды жүзеге асыратын қызмет болып табылады. Біз оны пайдаланушылар API интерфейсіне кіретін ақ тізімдегі IP мекенжайларымызды жарнамалау үшін белсенді түрде қолданамыз.
HAProxy OSI үлгісінің әртүрлі деңгейлерінде өте икемді трафикті теңестіру ережелерін конфигурациялауға мүмкіндік беретін жоғары жүктеме балансы болып табылады. Біз оны барлық қызметтердің алдында теңгерімдеу үшін қолданамыз: дерекқорлар, хабарлама брокерлері, API қызметтері, веб-қызметтері, біздің ішкі жобаларымыз - бәрі HAProxy-дің артында.
API қолданбасы — пайдаланушы өзінің инфрақұрылымын және қызметін басқаратын python тілінде жазылған веб-қосымша.
Жұмысшының өтініші (бұдан әрі жай жұмысшы) - OpenStack қызметтерінде бұл инфрақұрылымға API пәрмендерін таратуға мүмкіндік беретін инфрақұрылымдық демон. Мысалы, дискіні жасау жұмысшыда, ал жасау сұрауы API қолданбасында орын алады.
Стандартты OpenStack қолданбалы архитектурасы
OpenStack үшін әзірленген көптеген қызметтер бір парадигманы ұстануға тырысады. Қызмет әдетте 2 бөліктен тұрады: API және жұмысшылар (бағдарлама орындаушылар). Әдетте, API - бұл тәуелсіз процесс (демон) ретінде немесе дайын Nginx немесе Apache веб-серверін пайдалану арқылы іске қосылатын python тіліндегі WSGI қолданбасы. API пайдаланушы сұрауын өңдейді және орындау үшін жұмысшы қолданбасына қосымша нұсқауларды жібереді. Тасымалдау хабарлама брокерінің көмегімен жүзеге асырылады, әдетте RabbitMQ, басқаларына нашар қолдау көрсетіледі. Хабарламалар брокерге жеткенде, оларды жұмысшылар өңдейді және қажет болған жағдайда жауап қайтарады.
Бұл парадигма оқшауланған жалпы сәтсіздік нүктелерін қамтиды: RabbitMQ және дерекқор. Бірақ RabbitMQ бір қызмет ішінде оқшауланған және теориялық тұрғыдан әрбір қызмет үшін жеке болуы мүмкін. Сондықтан MCS-те біз бұл қызметтерді мүмкіндігінше бөлеміз; әрбір жеке жоба үшін жеке мәліметтер базасын, бөлек RabbitMQ жасаймыз. Бұл тәсіл жақсы, өйткені кейбір осал нүктелерде апат болған жағдайда бүкіл қызмет емес, оның бір бөлігі ғана бұзылады.
Жұмысшы қолданбаларының саны шектеусіз, сондықтан API өнімділік пен ақауларға төзімділікті арттыру үшін теңдестіргіштердің артында көлденеңінен оңай масштабтауға болады.
API интерфейстері мен жұмысшылар арасында күрделі дәйекті операциялар орын алған кезде кейбір қызметтер қызмет ішінде үйлестіруді қажет етеді. Бұл жағдайда бірыңғай үйлестіру орталығы пайдаланылады, Redis, Memcache және т.б. сияқты кластерлік жүйе, бұл бір жұмысшыға бұл тапсырманың өзіне жүктелгенін айтуға мүмкіндік береді («оны қабылдамаңыз»). Біз т.б. Әдетте, жұмысшылар мәліметтер базасымен белсенді түрде байланысады, сол жерден ақпаратты жазады және оқиды. Біз mariadb-ті мультимастерлік кластерде орналасқан дерекқор ретінде пайдаланамыз.
Бұл классикалық жалғыз қызмет OpenStack үшін жалпы қабылданған тәртіпте ұйымдастырылған. Оны жабық жүйе ретінде қарастыруға болады, ол үшін масштабтау әдістері мен ақауларға төзімділік айтарлықтай айқын. Мысалы, API ақауларына төзімділік үшін олардың алдына балансизаторды қою жеткілікті. Жұмысшылар санын арттыру олардың санын көбейту арқылы жүзеге асырылады.
Бүкіл схемадағы әлсіз нүкте - RabbitMQ және MariaDB. Олардың архитектурасы бөлек мақалаға лайық.Бұл мақалада мен API ақауларына төзімділікке назар аударғым келеді.

Openstack қолданбасының архитектурасы. Бұлтты платформаның теңдестіру және ақауларға төзімділігі
ExaBGP көмегімен HAProxy балансизаторын ақауларға төзімді ету
API интерфейстерін масштабталатын, жылдам және қателерге төзімді ету үшін біз олардың алдына жүктеме теңестірушісін қоямыз. Біз HAProxy таңдадық. Менің ойымша, ол біздің міндетіміз үшін барлық қажетті сипаттамаларға ие: бірнеше OSI деңгейлерінде теңгерімдеу, басқару интерфейсі, икемділік және масштабтау, теңдестіру әдістерінің үлкен саны, сеанс кестелерін қолдау.
Ең бірінші шешуді қажет ететін мәселе балансизатордың ақауға төзімділігі болды. Теңгерімді орнату да сәтсіздік нүктесін тудырады: теңгерімдегіш бұзылады және қызмет істен шығады. Мұның алдын алу үшін біз HAProxy бағдарламасын ExaBGP-мен бірге қолдандық.
ExaBGP сізге қызметтің күйін тексеру механизмін енгізуге мүмкіндік береді. Біз бұл механизмді HAProxy функционалдығын тексеру үшін қолдандық және ақаулық туындаған жағдайда BGP-ден HAProxy қызметін өшіреміз.
ExaBGP+HAProxy схемасы
- Біз ExaBGP және HAProxy қажетті бағдарламалық жасақтаманы үш серверге орнатамыз.
- Біз әрбір серверде кері байланыс интерфейсін жасаймыз.
- Барлық үш серверде біз осы интерфейске бірдей ақ IP мекенжайын тағайындаймыз.
- Ақ IP мекенжайы ExaBGP арқылы Интернетке жарияланады.
Ақауларға төзімділікке барлық үш серверден бірдей IP мекенжайын жарнамалау арқылы қол жеткізіледі. Желі тұрғысынан бір мекенжайға келесі үш түрлі секіру арқылы қол жеткізуге болады. Маршрутизатор үш бірдей бағытты көреді, олардың ең жоғары басымдылығын өз метрикасына негізделген таңдайды (бұл әдетте бірдей опция) және трафик серверлердің біріне ғана өтеді.
HAProxy жұмысында ақаулар немесе сервер сәтсіздігі жағдайында ExaBGP маршрутты жариялауды тоқтатады және трафик басқа серверге оңай ауысады.
Осылайша, балансизатордың ақауларға төзімділігіне қол жеткіздік.

HAProxy балансизаторларының ақауларға төзімділігі
Схема жетілмеген болып шықты: біз HAProxy қалай резервтеу керектігін білдік, бірақ қызметтер ішінде жүктемені қалай бөлуге болатынын білмедік. Сондықтан, біз бұл схеманы аздап кеңейттік: біз бірнеше ақ IP мекенжайлары арасындағы теңгерімдеуге көштік.
DNS плюс BGP негізінде теңдестіру
Біздің HAProxy үшін жүктемені теңестіру мәселесі әлі шешілмеген. Дегенмен, біз мұнда жасағандай, оны өте қарапайым шешуге болады.
Үш серверді теңестіру үшін сізге 3 ақ IP мекенжайы және жақсы ескі DNS қажет. Бұл мекенжайлардың әрқайсысы әрбір HAProxy кері байланыс интерфейсінде анықталады және Интернетке жарнамаланады.
OpenStack-те ресурстарды басқару үшін белгілі бір қызметтің API соңғы нүктесін көрсететін қызмет каталогы пайдаланылады. Бұл каталогта біз үш түрлі IP мекенжайлары арқылы DNS арқылы шешілетін public.infra.mail.ru домен атауын тіркейміз. Нәтижесінде біз DNS арқылы үш мекенжай арасында жүктеменің таралуын аламыз.
Бірақ ақ IP мекенжайларын жариялаған кезде біз серверді таңдау басымдықтарын бақыламайтындықтан, бұл әлі теңдестірілмейді. Әдетте, IP мекенжайының жұмыс өтілі негізінде тек бір сервер таңдалады, ал қалған екеуі бос болады, себебі BGP-де ешқандай көрсеткіштер көрсетілмеген.
Біз әртүрлі көрсеткіштермен ExaBGP арқылы маршруттарды жібере бастадық. Әрбір теңгерімдеуші барлық үш ақ IP мекенжайын жарнамалайды, бірақ олардың біреуі, берілген балансизаторға арналған негізгісі, ең аз көрсеткішпен жарнамаланады. Осылайша, барлық үш теңгергіш жұмыс істеп тұрғанда, бірінші IP мекенжайына қоңыраулар бірінші теңгерімдеушіге, екіншісіне қоңырау шалу және үшіншіден үшіншіге қоңырау шалу.
Теңестірушілердің бірі құлағанда не болады? Егер кез келген теңгерімдеуші істен шықса, оның негізгі мекенжайы бұрынғы екеуінен жарнамаланады және трафик олардың арасында қайта бөлінеді. Осылайша, пайдаланушыға DNS арқылы бірден бірнеше IP мекенжайларын береміз. DNS және әртүрлі көрсеткіштер бойынша теңгерімдеу арқылы біз барлық үш теңгергіштер бойынша жүктемені біркелкі бөлуді аламыз. Сонымен қатар біз қателікке төзімділікті жоғалтпаймыз.

DNS + BGP негізіндегі HAProxy теңдестіру
ExaBGP және HAProxy арасындағы өзара әрекеттесу
Осылайша, біз маршруттар туралы хабарландыруды тоқтатуға негізделген сервер кеткен жағдайда ақауларға төзімділікті енгіздік. Бірақ HAProxy сервердің істен шығуынан басқа себептермен өшірілуі мүмкін: әкімшілік қателер, қызметтегі сәтсіздіктер. Біз бұл жағдайда да бұзылған теңгерімді жүктің астынан алып тастағымыз келеді және бізге басқа механизм қажет.
Сондықтан, алдыңғы схеманы кеңейте отырып, біз ExaBGP және HAProxy арасында жүрек соғуын енгіздік. Бұл ExaBGP қолданбалардың күйін тексеру үшін теңшелетін сценарийлерді пайдаланған кезде, ExaBGP және HAProxy арасындағы өзара әрекеттесудің бағдарламалық құралын іске асыру.
Мұны істеу үшін ExaBGP конфигурациясында денсаулықты тексеру құралын конфигурациялау қажет, ол HAProxy күйін тексере алады. Біздің жағдайда біз денсаулық серверін HAProxy бағдарламасында конфигурацияладық және ExaBGP жағынан қарапайым GET сұрауымен тексереміз. Егер хабарландыру тоқтатылса, HAProxy жұмыс істемейді және оны жарнамалаудың қажеті жоқ.

HAProxy денсаулықты тексеру
HAProxy Peers: сеансты синхрондау
Келесі нәрсе сеанстарды синхрондау болды. Бөлінген балансерлер арқылы жұмыс істегенде, клиент сеанстары туралы ақпаратты сақтауды ұйымдастыру қиын. Бірақ HAProxy - бұл Peers функционалдығы - сеанс кестелерін әртүрлі HAProxy процестері арасында тасымалдау мүмкіндігі арқасында мұны істей алатын бірнеше теңгерімдердің бірі.
Теңестірудің әртүрлі әдістері бар: қарапайым, мысалы , және кеңейтілген, клиент сеансы есте қалғанда және ол бұрынғыдай серверде аяқталған сайын. Біз екінші нұсқаны жүзеге асырғымыз келді.
HAProxy осы механизмнің клиент сеанстарын сақтау үшін таяқша кестелерін пайдаланады. Олар клиенттің бастапқы IP-мекен-жайын, таңдалған мақсатты мекенжайды (бағдарлама) және кейбір қызмет ақпаратын сақтайды. Әдетте, таяқша кестелері бастапқы-IP + тағайындау-IP жұбын сақтау үшін пайдаланылады, бұл әсіресе басқа теңгергішке ауысқанда, мысалы, RoundRobin теңдестіру режимінде пайдаланушы сеансының мәтінмәнін тасымалдай алмайтын қолданбалар үшін пайдалы.
Егер таяқшалар үстелі әртүрлі HAProxy процестері арасында қозғалуға үйретілсе (олардың арасында теңгерімдеу орын алады), біздің теңгергіштер таяқша кестелерінің бір пулымен жұмыс істей алады. Бұл теңгерімдеушілердің бірі істен шыққан жағдайда клиент желісін үздіксіз ауыстыруға мүмкіндік береді; клиент сеанстарымен жұмыс бұрын таңдалған серверлерде жалғасады.
Дұрыс жұмыс істеу үшін сеанс құрылған балансизатордың бастапқы IP мекенжайының мәселесі шешілуі керек. Біздің жағдайда бұл кері байланыс интерфейсіндегі динамикалық мекенжай.
Құрдастардың дұрыс жұмыс істеуіне белгілі бір жағдайларда ғана қол жеткізіледі. Яғни, TCP сеансын аяқтауға уақыт болмайтындай TCP күту уақыттары жеткілікті үлкен болуы керек немесе ауысу жеткілікті жылдам болуы керек. Дегенмен, ол үздіксіз ауысуға мүмкіндік береді.
IaaS жүйесінде бізде дәл сол технологияны қолдана отырып жасалған қызмет бар. Бұл , ол Octavia деп аталады. Ол екі HAProxy процесіне негізделген және бастапқыда құрдастар үшін қолдауды қамтиды. Олар бұл қызметте өздерін тамаша көрсетті.
Суретте үш HAProxy данасы арасындағы тең кестелердің қозғалысы схемалық түрде көрсетілген, оны конфигурациялауға болатын конфигурация ұсынылады:

HAProxy Peers (сеансты синхрондау)
Егер сіз сол схеманы жүзеге асырсаңыз, оның жұмысы мұқият тексерілуі керек. Бұл 100% уақытта бірдей жұмыс істейтіні шындық емес. Бірақ, ең болмағанда, клиенттің бастапқы IP мекенжайын есте сақтау қажет болғанда, таяқша кестелерін жоғалтпайсыз.
Бір клиенттен бір уақыттағы сұраулар санын шектеу
Жалпыға қолжетімді кез келген қызметтер, соның ішінде API интерфейстері сұраныстардың көшкініне ұшырауы мүмкін. Олардың себептері пайдаланушы қателерінен мақсатты шабуылдарға дейін мүлдем басқаша болуы мүмкін. Біз мерзімді түрде IP мекенжайлары бойынша DDoS береміз. Клиенттер сценарийлерінде жиі қателеседі және бізге мини-DDoS береді.
Қалай болғанда да, қосымша қорғаныс қамтамасыз етілуі керек. Ашық шешім - API сұрауларының санын шектеу және зиянды сұрауларды өңдеуге CPU уақытын жоғалтпау.
Мұндай шектеулерді жүзеге асыру үшін біз HAProxy негізінде ұйымдастырылған тарифтік шектеулерді қолданамыз, сол кестелерді пайдаланамыз. Шектеулерді орнату өте қарапайым және пайдаланушыны API сұрауларының саны бойынша шектеуге мүмкіндік береді. Алгоритм сұраулар жасалатын бастапқы IP-ді есте сақтайды және бір пайдаланушының бір уақыттағы сұрауларының санын шектейді. Әрине, біз әрбір қызмет үшін API жүктемесінің орташа профилін есептедік және осы мәннен ≈ 10 есе артық шектеу орнаттық. Біз жағдайды мұқият қадағалап, саусағымызды тамыр соғуын жалғастырамыз.
Бұл іс жүзінде қалай көрінеді? Біздің автоматты масштабтау API интерфейсін үнемі қолданатын тұтынушыларымыз бар. Олар таңертең шамамен екі-үш жүз виртуалды машина жасайды және кешке оларды жояды. OpenStack үшін PaaS қызметтерімен бірге виртуалды машинаны жасау үшін кемінде 1000 API сұраулары қажет, өйткені қызметтер арасындағы өзара әрекеттесу API арқылы да жүзеге асады.
Мұндай тапсырмаларды беру айтарлықтай үлкен жүктемені тудырады. Біз бұл жүктемені бағаладық, күнделікті шыңдарды жинадық, оларды он есеге арттырдық, бұл біздің тарифтік шектеуімізге айналды. Біз саусағымызды импульсте ұстаймыз. Бізде іске қосуға болатын CGA сценарийлері бар-жоғын білу үшін бізге қарауға тырысатын боттар мен сканерлерді жиі көреміз, біз оларды белсенді түрде кесіп жатырмыз.
Пайдаланушылар байқамай код базасын қалай жаңартуға болады
Біз сондай-ақ кодты орналастыру процестері деңгейінде қателерге төзімділікті енгіземіз. Іске қосу кезінде ақаулар болуы мүмкін, бірақ олардың қызмет қолжетімділігіне әсерін азайтуға болады.
Біз өз қызметтерімізді үнемі жаңартып отырамыз және пайдаланушыларға әсер етпестен кодтық базаның жаңартылуын қамтамасыз етуіміз керек. Біз бұл мәселені HAProxy басқару мүмкіндіктері мен қызметтерімізде Graceful Shutdown енгізу арқылы шеше алдық.
Бұл мәселені шешу үшін балансизаторды бақылауды және қызметтердің «дұрыс» өшірілуін қамтамасыз ету қажет болды:
- HAProxy жағдайында басқару шын мәнінде ұяшық болып табылатын және HAProxy конфигурациясында анықталған статистикалық файл арқылы орындалады. Оған stdio арқылы пәрмендер жіберуге болады. Бірақ біздің негізгі конфигурацияны басқару құралы ыңғайлы, сондықтан оның HAProxy басқаруға арналған кірістірілген модулі бар. Біз оны белсенді түрде қолданамыз.
- API және Engine қызметтеріміздің көпшілігі керемет өшіру технологияларын қолдайды: өшіру кезінде олар http сұрауы немесе қандай да бір қызмет тапсырмасы болсын, ағымдағы тапсырманың аяқталуын күтеді. Жұмысшыда да солай болады. Ол орындап жатқан барлық тапсырмаларды біледі және бәрін сәтті аяқтағаннан кейін аяқталады.
Осы екі нүктенің арқасында біздің орналастырудың қауіпсіз алгоритмі келесідей көрінеді.
- Әзірлеуші кодтың жаңа пакетін жинайды (біз үшін бұл RPM), оны әзірлеуші ортасында сынайды, оны кезеңде сынайды және оны кезең репозиторийінде қалдырады.
- Әзірлеуші «артефактілердің» егжей-тегжейлі сипаттамасымен орналастыру тапсырмасын қояды: жаңа буманың нұсқасы, жаңа функцияның сипаттамасы және қажет болған жағдайда орналастыру туралы басқа мәліметтер.
- Жүйе әкімшісі жаңартуды бастайды. Ansible ойын кітабын іске қосады, ол өз кезегінде келесі әрекеттерді орындайды:
- Кезең репозиторийінен буманы алады және оны өнім репозиторийіндегі бума нұсқасын жаңарту үшін пайдаланады.
- Жаңартылған қызмет серверлерінің тізімін құрастырады.
- HAProxy жүйесінде жаңартылатын бірінші қызметті өшіреді және оның процестерінің аяқталуын күтеді. Керемет өшірудің арқасында біз клиенттің барлық ағымдағы сұраулары сәтті аяқталатынына сенімдіміз.
- API және жұмысшылар толығымен тоқтатылғаннан кейін және HAProxy өшірілгеннен кейін код жаңартылады.
- Ansible қызметтерін іске қосады.
- Әрбір қызмет үшін алдын ала анықталған бірқатар кілт сынақтарында бірлік сынауын жүзеге асыратын белгілі бір «тұтқалар» тартылады. Жаңа кодты негізгі тексеру жүргізіледі.
- Алдыңғы қадамда қателер табылмаса, сервер белсендіріледі.
- Келесі серверге көшейік.
- Барлық серверлер жаңартылғаннан кейін функционалдық сынақтар іске қосылады. Егер олар жоқ болса, әзірлеуші өзі жасаған кез келген жаңа функцияны қарайды.
Бұл орналастыруды аяқтайды.

Қызметті жаңарту циклі
Егер бізде бір ереже болмаса, бұл схема жұмыс істемес еді. Біз шайқаста ескі және жаңа нұсқаларды қолдаймыз. Алдын ала, бағдарламалық жасақтаманы әзірлеу кезеңінде, тіпті сервистік деректер базасында өзгерістер болса да, олар бұрынғы кодты бұзбайтындығы белгіленген. Нәтижесінде кодтық база біртіндеп жаңартылады.
қорытынды
Ақауларға төзімді WEB архитектурасы туралы өз ойларыммен бөлісе отырып, мен оның негізгі тұстарын тағы бір рет атап өткім келеді:
- физикалық ақауларға төзімділік;
- желі ақауларына төзімділік (балансерлер, BGP);
- пайдаланылатын және әзірленген бағдарламалық құралдың ақауларға төзімділігі.
Барлығына тұрақты жұмыс уақыты!
Ақпарат көзі: www.habr.com
