Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud
Здраво, јас сум Сергеј Еланцев, се развивам мрежен балансер на оптоварување во Yandex.Cloud. Претходно, го водев развојот на балансерот L7 за порталот Yandex - колегите се шегуваат дека што и да правам, излегува дека е балансер. Ќе им кажам на читателите на Habr како да управуваат со оптоварувањето во облак платформа, што гледаме како идеална алатка за постигнување на оваа цел и како се движиме кон градење на оваа алатка.

Прво, да воведеме неколку термини:

  • ВИП (Виртуелна IP) - IP адреса на балансерот
  • Сервер, бекенд, пример - виртуелна машина што работи на апликација
  • RIP (Real IP) - IP адреса на серверот
  • Healthcheck - проверка на подготвеноста на серверот
  • Зона на достапност, АЗ - изолирана инфраструктура во центар за податоци
  • Регион - сојуз на различни АЗ

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

Балансерот на оптоварување често се класифицира според слојот на протоколот од моделот OSI на кој работи. Cloud Balancer работи на ниво на TCP, што одговара на четвртиот слој, L4.

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

Рамнина на податоци

Сообраќајот завршува на скапи уреди наречени гранични рутери. За да се зголеми толеранцијата на грешки, неколку такви уреди работат истовремено во еден центар за податоци. Следно, сообраќајот оди до балансери, кои објавуваат билокаст IP адреси до сите AZ преку BGP за клиенти. 

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

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

Конфигурациска рамнина

 
Клучната компонента на конфигурациската рамнина е API, преку кој се вршат основни операции со балансери: креирање, бришење, промена на составот на примероците, добивање резултати од здравствени проверки итн. Од една страна, ова е REST API, а од друго, ние во Cloud многу често ја користиме рамката gRPC, па го „преведуваме“ REST во gRPC и потоа користиме само gRPC. Секое барање води до создавање на серија асинхрони идемпотентни задачи кои се извршуваат на заеднички базен на Yandex.Cloud работници. Задачите се напишани на таков начин што може да се суспендираат во секое време, а потоа да се рестартираат. Ова обезбедува приспособливост, повторливост и евидентирање на операциите.

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Како резултат на тоа, задачата од API ќе поднесе барање до контролорот на услугата за балансирање, што е напишано во Go. Може да додава и отстранува балансери, да го менува составот на позадините и поставките. 

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Услугата ја складира својата состојба во Yandex Database, дистрибуирана управувана база на податоци што наскоро ќе можете да ја користите. Во Yandex.Cloud, како што веќе кажа, се применува концептот за храна за кучиња: ако ние самите ги користиме нашите услуги, тогаш и нашите клиенти ќе бидат среќни да ги користат. Базата на податоци Yandex е пример за имплементација на таков концепт. Ние ги складираме сите наши податоци во YDB и не треба да размислуваме за одржување и скалирање на базата на податоци: овие проблеми се решени за нас, ние ја користиме базата на податоци како услуга.

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

Контролор за здравствена проверка

Добива барања за промена на правилата за проверка, ги зачувува во YDB, дистрибуира задачи меѓу јазлите за проверка на здравјето и ги собира резултатите, кои потоа се зачувуваат во базата на податоци и се испраќаат до контролорот на loadbalancer. Тој, пак, испраќа барање за промена на составот на кластерот во податочната рамнина до loadbalancer-јазолот, за што ќе разговарам подолу.

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Ајде да зборуваме повеќе за здравствени проверки. Тие можат да се поделат во неколку класи. Ревизиите имаат различни критериуми за успех. Проверките на TCP треба успешно да воспостават врска во одредено време. Проверките на HTTP бараат и успешна врска и одговор со статусен код од 200.

Исто така, проверките се разликуваат во класата на дејствување - тие се активни и пасивни. Пасивните проверки едноставно следат што се случува со сообраќајот без да преземаат никакви посебни мерки. Ова не функционира многу добро на L4 бидејќи зависи од логиката на протоколите на повисоко ниво: на L4 нема информации за тоа колку време траела операцијата или дали завршувањето на врската било добро или лошо. Активните проверки бараат од балансерот да испраќа барања до секој пример на сервер.

Повеќето балансери на товар самите вршат проверки на живост. Во Cloud, решивме да ги одвоиме овие делови од системот за да ја зголемиме приспособливоста. Овој пристап ќе ни овозможи да го зголемиме бројот на балансери додека го одржуваме бројот на барања за здравствена проверка до услугата. Проверките се вршат од одделни јазли за проверка на здравјето, низ кои целите за проверка се делат и се реплицираат. Не можете да вршите проверки од еден домаќин, бидејќи може да не успее. Тогаш нема да ја добиеме состојбата на примероците што ги проверил. Вршиме проверки на која било од случаите од најмалку три јазли за проверка на здравјето. Ние ги разделуваме целите на проверките помеѓу јазлите користејќи конзистентни алгоритми за хаширање.

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

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

Разликата е во тоа што клиентите поднесуваат барања до ВИП, додека здравствените проверки поднесуваат барања до секој поединечен RIP. Тука се појавува интересен проблем: им даваме можност на нашите корисници да создаваат ресурси во сиви IP мрежи. Да замислиме дека има двајца различни сопственици на облак кои ги кријат своите услуги зад балансери. Секој од нив има ресурси во подмрежата 10.0.0.1/24, со исти адреси. Треба да можете некако да ги разликувате и тука треба да се нурнете во структурата на виртуелната мрежа Yandex.Cloud. Подобро е да дознаете повеќе детали во видео од настанот за:облак, сега ни е важно мрежата да е повеќеслојна и да има тунели кои може да се разликуваат по id на подмрежата.

Јазлите за здравствена проверка контактираат со балансери користејќи таканаречени квази-IPv6 адреси. Квази-адреса е IPv6 адреса со IPv4 адреса и идентификација на корисничка подмрежа вградена во неа. Сообраќајот стигнува до балансерот, кој ја извлекува адресата на изворот IPv4 од него, го заменува IPv6 со IPv4 и го испраќа пакетот до мрежата на корисникот.

Обратниот сообраќај оди на ист начин: балансерот гледа дека дестинацијата е сива мрежа од здравствените проверувачи и го конвертира IPv4 во IPv6.

VPP - срцето на податочната рамнина

Балансерот е имплементиран со помош на технологијата за обработка на пакети (VPP), рамка од Cisco за сериска обработка на мрежниот сообраќај. Во нашиот случај, рамката работи на врвот на библиотеката за управување со мрежен простор со кориснички простор - Комплет за развој на податоци за рамнина (DPDK). Ова обезбедува високи перформанси за обработка на пакети: многу помалку прекини се случуваат во кернелот и нема контекстни прекинувачи помеѓу просторот на јадрото и корисничкиот простор. 

VPP оди уште подалеку и истиснува уште повеќе перформанси од системот со комбинирање на пакети во серии. Добивките од перформансите доаѓаат од агресивната употреба на кешот на модерните процесори. Се користат и кешовите на податоци (пакетите се обработуваат во „вектори“, податоците се блиску еден до друг) и кешот на инструкции: во VPP, обработката на пакети следи график, чии јазли содржат функции што ја извршуваат истата задача.

На пример, обработката на IP пакетите во VPP се случува по следниот редослед: прво, заглавјата на пакетите се анализираат во јазолот за парсирање, а потоа се испраќаат до јазолот, кој понатаму ги препраќа пакетите според табелите за рутирање.

Малку хардкор. Авторите на VPP не толерираат компромиси во употребата на кешот на процесорот, така што типичниот код за обработка на вектор на пакети содржи рачна векторизација: постои процесорска јамка во која се обработува ситуација како „имаме четири пакети во редот“, потоа исто за двајца, па - за еден. Инструкциите за претходно преземање често се користат за вчитување податоци во кешовите за да се забрза пристапот до нив во следните повторувања.

n_left_from = frame->n_vectors;
while (n_left_from > 0)
{
    vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
    // ...
    while (n_left_from >= 4 && n_left_to_next >= 2)
    {
        // processing multiple packets at once
        u32 next0 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        u32 next1 = SAMPLE_NEXT_INTERFACE_OUTPUT;
        // ...
        /* Prefetch next iteration. */
        {
            vlib_buffer_t *p2, *p3;

            p2 = vlib_get_buffer (vm, from[2]);
            p3 = vlib_get_buffer (vm, from[3]);

            vlib_prefetch_buffer_header (p2, LOAD);
            vlib_prefetch_buffer_header (p3, LOAD);

            CLIB_PREFETCH (p2->data, CLIB_CACHE_LINE_BYTES, STORE);
            CLIB_PREFETCH (p3->data, CLIB_CACHE_LINE_BYTES, STORE);
        }
        // actually process data
        /* verify speculative enqueues, maybe switch current next frame */
        vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
                to_next, n_left_to_next,
                bi0, bi1, next0, next1);
    }

    while (n_left_from > 0 && n_left_to_next > 0)
    {
        // processing packets by one
    }

    // processed batch
    vlib_put_next_frame (vm, node, next_index, n_left_to_next);
}

Значи, Healthchecks разговара преку IPv6 со VPP, што ги претвора во IPv4. Ова го прави јазол во графикот, кој го нарекуваме алгоритамски NAT. За обратен сообраќај (и конверзија од IPv6 во IPv4) постои истиот алгоритамски NAT јазол.

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

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

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Првиот јазол се лепливи сесии. Го складира хашот на 5-дупла за воспоставените седници. 5-tuple ги вклучува адресата и портата на клиентот од кој се пренесуваат информациите, адресата и портите на ресурсите достапни за примање сообраќај, како и мрежниот протокол. 

Хешот од 5 души ни помага да вршиме помалку пресметки во последователниот конзистентен јазол за хаширање, како и подобро да се справиме со промените на списокот на ресурси зад балансерот. Кога пакетот за кој нема сесија ќе пристигне до балансерот, тој се испраќа до конзистентен јазол за хаширање. Ова е местото каде што се случува балансирањето со користење на доследно хеширање: избираме ресурс од списокот на достапни ресурси „во живо“. Следно, пакетите се испраќаат до јазолот NAT, кој всушност ја заменува одредишната адреса и повторно ги пресметува контролните суми. Како што можете да видите, ги следиме правилата на VPP - како да се допаѓа, групирајќи слични пресметки за да ја зголемиме ефикасноста на кешот на процесорот.

Доследно хаширање

Зошто го избравме и што е тоа? Прво, да ја разгледаме претходната задача - избор на ресурс од листата. 

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Со неконзистентно хаширање, се пресметува хашот на дојдовниот пакет и се избира ресурс од листата со остатокот од делењето на овој хаш со бројот на ресурси. Сè додека списокот останува непроменет, оваа шема работи добро: ние секогаш испраќаме пакети со исти 5-точки до истата инстанца. Ако, на пример, некој ресурс престана да одговара на здравствени проверки, тогаш за значителен дел од хашовите изборот ќе се промени. TCP врските на клиентот ќе бидат прекинати: пакетот што претходно стигнал до примерот А може да почне да го достигнува примерот Б, кој не е запознаен со сесијата за овој пакет.

Доследно хаширање го решава опишаниот проблем. Најлесен начин да се објасни овој концепт е следниов: замислете дека имате прстен на кој ги дистрибуирате ресурсите по хаш (на пример, преку IP:port). Изборот на ресурс е вртење на тркалото под агол, кој се одредува според хашот на пакетот.

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Ова ја минимизира прераспределбата на сообраќајот кога се менува составот на ресурсите. Бришењето ресурс ќе влијае само на делот од конзистентниот прстен за хаширање во кој се наоѓал ресурсот. Додавањето ресурс исто така ја менува дистрибуцијата, но имаме леплив јазол за сесии, кој ни овозможува да не ги префрламе веќе воспоставените сесии на нови ресурси.

Разгледавме што се случува со директниот сообраќај помеѓу балансерот и ресурсите. Сега да го погледнеме повратниот сообраќај. Ја следи истата шема како проверениот сообраќај - преку алгоритамски NAT, односно преку обратен NAT 44 за сообраќај на клиенти и преку NAT 46 за сообраќај за здравствени проверки. Ние се придржуваме до нашата сопствена шема: го обединуваме сообраќајот за здравствени проверки и сообраќајот на вистински корисници.

Loadbalancer-јазол и склопени компоненти

Составот на балансери и ресурси во VPP е пријавен од локалната услуга - loadbalancer-node. Се претплати на протокот на настани од loadbalancer-controller и може да ја нацрта разликата помеѓу моменталната VPP состојба и целната состојба добиена од контролорот. Добиваме затворен систем: настаните од API доаѓаат до контролорот за балансирање, кој му доделува задачи на контролорот за здравствена проверка за да ја провери „живоста“ на ресурсите. Тоа, пак, доделува задачи на јазолот за проверка на здравјето и ги собира резултатите, по што ги испраќа назад до контролорот за балансирање. Loadbalancer-node се претплати на настани од контролорот и ја менува состојбата на VPP. Во таков систем, секоја услуга знае само она што е неопходно за соседните услуги. Бројот на приклучоци е ограничен и имаме можност да работиме и да размериме различни сегменти независно.

Архитектура на мрежен балансер на оптоварување во Yandex.Cloud

Кои прашања беа избегнати?

Сите наши услуги во контролната рамнина се напишани во Go и имаат добри карактеристики на скалирање и доверливост. Go има многу библиотеки со отворен код за изградба на дистрибуирани системи. Активно користиме GRPC, сите компоненти содржат имплементација со отворен код за откривање на услуги - нашите услуги ги следат меѓусебните перформанси, можат динамично да го менуваат својот состав и го поврзавме ова со балансирање на GRPC. За метрика, ние исто така користиме решение со отворен код. Во рамнината на податоци, добивме пристојни перформанси и голема резерва на ресурси: се покажа дека е многу тешко да се состави држач на кој би можеле да се потпреме на перформансите на VPP, наместо на железна мрежна картичка.

Проблеми и решенија

Што не функционираше толку добро? Go има автоматско управување со меморијата, но протекувањето на меморијата сепак се случува. Најлесен начин да се справите со нив е да пуштате горутини и не заборавајте да ги прекинете. Готова храна: Гледајте ја потрошувачката на меморија на вашите програми Go. Често добар показател е бројот на горутини. Има и плус во оваа приказна: во Go е лесно да се добијат податоци за време на траење - потрошувачка на меморија, број на работи горутини и многу други параметри.

Исто така, Go можеби не е најдобриот избор за функционални тестови. Тие се доста опширни, а стандардниот пристап на „водење сè во CI во серија“ не е многу погоден за нив. Факт е дека функционалните тестови бараат повеќе ресурси и предизвикуваат вистински тајмаути. Поради ова, тестовите може да не успеат бидејќи процесорот е зафатен со тестови на единицата. Заклучок: Ако е можно, извршете „тешки“ тестови одделно од тестовите на единицата. 

Микросервисната архитектура на настани е посложена од монолит: собирањето логови на десетици различни машини не е многу погодно. Заклучок: ако правите микросервиси, веднаш размислете за следење.

Нашите планови

Ќе лансираме внатрешен балансер, балансирач на IPv6, ќе додадеме поддршка за скриптите на Kubernetes, ќе продолжиме да ги делиме нашите услуги (во моментов само здравствениот јазол и здравствената проверка-ctrl се разделени), ќе додадеме нови здравствени проверки, а исто така ќе спроведеме паметна агрегација на проверки. Ја разгледуваме можноста нашите услуги да ги направиме уште понезависни - за да не комуницираат директно меѓу себе, туку користејќи редица за пораки. Неодамна во Cloud се појави услуга компатибилна со SQS Ред за пораки на Yandex.

Неодамна се случи јавното објавување на Yandex Load Balancer. Истражува документација на услугата, управувајте со балансерите на начин погоден за вас и зголемете ја толеранцијата на грешки на вашите проекти!

Извор: www.habr.com

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