
Бәріңе сәлем. Бұл мақалада мен сізге неліктен біз Авитода тоғыз ай бұрын Кафканы таңдағанымызды және оның не екенін айтамын. Мен пайдалану жағдайларының бірі - хабар брокерімен бөлісемін. Соңында, Кафканы сервистік тәсіл ретінде пайдаланудың қандай артықшылықтары бар екендігі туралы сөйлесейік.
проблема

Біріншіден, кішкене контекст. Біраз уақыт бұрын біз монолитті архитектурадан алшақтай бастадық, енді Avito-ның бірнеше жүздеген түрлі қызметтері бар. Олардың өз репозиторийлері, өздерінің технологиялық стектері бар және бизнес логикасының өз бөлігіне жауап береді.
Қызметтердің көптігімен байланысты проблемалардың бірі - байланыс. А қызметі көбінесе B қызметінде бар ақпаратты білгісі келеді. Бұл жағдайда А қызметі синхронды API арқылы В қызметіне қол жеткізеді. B қызметі D және D қызметтерімен не болып жатқанын білгісі келеді және олар өз кезегінде А және В қызметтеріне қызығушылық танытады. Осындай «қызық» қызметтер көп болғанда, олардың арасындағы байланыстар шиеленіскен шиеленістерге айналады.
Сонымен қатар, A қызметі кез келген уақытта қолжетімсіз болуы мүмкін. Бұл жағдайда B қызметі және оған қосылған барлық басқа қызметтер не істеуі керек? Ал егер бизнес операциясын аяқтау үшін дәйекті синхронды шақырулар тізбегі қажет болса, бүкіл операцияның сәтсіздікке ұшырау ықтималдығы одан да жоғары болады (және тізбек неғұрлым ұзақ болса, соғұрлым жоғары болады).
Технологияны таңдау

Жарайды, мәселелер анық. Оларды қызметтер арасында орталықтандырылған хабар алмасу жүйесін құру арқылы жоюға болады. Енді қызметтердің әрқайсысы осы хабар алмасу жүйесі туралы білуі керек. Сонымен қатар, жүйенің өзі ақауларға төзімді және көлденең масштабтауға қабілетті болуы керек, сондай-ақ апаттар болған жағдайда кейінгі өңдеу үшін қол жеткізу буферін жинақтауы керек.
Енді хабарламаны жеткізу жүзеге асырылатын технологияны таңдайық. Мұны істеу үшін алдымен одан не күтетінімізді түсінейік:
- қызметтер арасындағы хабарламалар жоғалмауы керек;
- хабарламалар қайталануы мүмкін;
- хабарламаларды бірнеше күндік тереңдікте сақтауға және оқуға болады (тұрақты буфер);
- қызметтер өздерін қызықтыратын деректерге жазыла алады;
- бірнеше қызмет бірдей деректерді оқи алады;
- хабарламалар егжей-тегжейлі, көлемді пайдалы жүктемені қамтуы мүмкін (оқиғаның күйін беру);
- Кейде хабарлардың ретіне кепілдік беру қажет.
Сондай-ақ біз үшін ең ауқымды және жоғары өткізу қабілеті бар сенімді жүйені таңдау өте маңызды болды (секундына бірнеше килобайттан кемінде 100 мың хабарлама).
Осы кезде біз RabbitMQ (жоғары rps кезінде тұрақты ұстау қиын), SkyTools-тен PGQ (жеткілікті емес және жақсы масштабталмайды) және NSQ (тұрақты емес) қоштасты. Біз осы технологиялардың барлығын өз компаниямызда қолданамыз, бірақ олар шешіліп жатқан мәселеге сәйкес келмеді.
Әрі қарай, біз үшін жаңа технологияларды қарастыра бастадық - Apache Kafka, Apache Pulsar және NATS Streaming.
Пульсар бірінші болып лақтырылды. Біз Кафка мен Пульсар өте ұқсас шешімдер деп шештік. Пульсарды ірі компаниялар сынағанына, жаңарақ болғанына және төмен кідіріс (теориялық) ұсынатынына қарамастан, біз осы екеуінің Кафканы осындай тапсырмалар үшін де-факто стандарты ретінде қалдыруды шештік. Біз болашақта Apache Pulsar-қа оралатын шығармыз.
Енді екі үміткер қалды: NATS Streaming және Apache Kafka. Біз екі шешімді де егжей-тегжейлі зерттедік және олардың екеуі де тапсырмаға сай болды. Бірақ соңында біз NATS Streaming-тің салыстырмалы жастарынан қорқатынбыз (және негізгі әзірлеушілердің бірі Тайлер Трит жобаны тастап, өз жобасын бастауға шешім қабылдағаны - Liftbridge). Сонымен қатар, NATS Streaming кластерлік режимі күшті көлденең масштабтау мүмкіндігін қамтамасыз етпеді (мүмкін, бұл 2017 жылы бөлу режимін қосқаннан кейін енді проблема емес шығар).
Дегенмен, NATS Streaming - Go бағдарламасында жазылған және Cloud Native Computing Foundation қолдайтын керемет технология. Apache Кафкадан айырмашылығы, жұмыс істеу үшін Zookeeper қажет емес (мүмкін ), өйткені ол RAFT-ті іштей жүзеге асырады. Сонымен қатар, NATS Streaming басқару оңайырақ. Болашақта бұл технологияға қайта оралатынымызды жоққа шығармаймыз.
Дегенмен, бүгінгі жеңімпаз - Апачи Кафка. Біздің сынақтарымызда ол өте жылдам (1 килобайт хабарлама көлемімен оқу және жазу үшін секундына миллионнан астам хабарлама), жеткілікті сенімді, жоғары масштабталатын және ірі компаниялардың өндірісіндегі тәжірибемен дәлелденген. Сонымен қатар, Кафка кем дегенде бірнеше ірі коммерциялық компанияларды қолдайды (біз, мысалы, Confluent нұсқасын қолданамыз) және Кафканың дамыған экожүйесі де бар.
Кафкаға шолу
Бастамас бұрын, мен бірден тамаша кітапты ұсынғым келеді - «Кафка: нақты нұсқаулық» (орысша аудармасы да бар, бірақ терминдер біраз ойландырады). Онда Кафка туралы негізгі түсінікке ие болу үшін қажет және одан да көп ақпарат бар. Apache құжаттары мен Confluent блогы да жақсы жазылған және оқуға оңай.
Олай болса, Кафка қалай жұмыс істейтінін құстың көзімен алайық. Кафканың негізгі топологиясы өндірушіден, тұтынушыдан, брокерден және зоопарктан тұрады.
делдал

Брокер деректеріңізді сақтауға жауапты. Барлық деректер екілік пішінде сақталады және брокер олардың не екенін және олардың құрылымы қандай екенін аз біледі.
Әрбір логикалық оқиға түрі әдетте жеке тақырыпта орналасады. Мысалы, хабарландыруды жасау оқиғасы item.created тақырыбына, ал оны өзгерту оқиғасы item.changed тақырыбына түсуі мүмкін. Тақырыптарды оқиға классификаторлары ретінде қарастыруға болады. Тақырып деңгейінде конфигурация параметрлерін орнатуға болады, мысалы:
- сақталған деректер көлемі және/немесе оның жасы (сақтау.байт, сақтау.мс);
- деректердің артық болу факторы (репликация факторы);
- бір хабарламаның максималды өлшемі (макс.хабар.байт);
- тақырыпқа деректерді жазуға болатын тұрақты көшірмелердің ең аз саны (min.insync.replicas);
- ықтимал деректер жоғалуы бар синхронды емес артта қалған репликада ауыстырып қосуды орындау мүмкіндігі (unclean.leader.election.enable);
- және тағы басқалар ().
Өз кезегінде әрбір тақырып бір немесе бірнеше бөлімдерге бөлінеді. Оқиғалар ақыр соңында партияларда болады. Егер кластерде бірнеше брокер болса, онда бөлімдер барлық брокерлерге (мүмкіндігінше) біркелкі бөлінеді, бұл бір тақырыпты жазу және оқу жүктемесін бірден бірнеше брокерлер бойынша масштабтауға мүмкіндік береді.
Дискіде әрбір бөлімге арналған деректер сегменттік файлдар түрінде сақталады, олар әдепкі бойынша бір гигабайтқа тең (log.segment.bytes арқылы басқарылады). Маңызды мүмкіндік - деректер сегменттердегі бөлімдерден (сақтау іске қосылғанда) жойылады (бөлімнен бір оқиғаны жою мүмкін емес, сіз тек бүкіл сегментті және белсенді еместі ғана жоя аласыз).
Зоопер
Zookeeper метадеректер қоймасы және үйлестіруші ретінде әрекет етеді. Ол брокерлердің тірі екенін айта алады (сіз бұны zookeeper-shell пәрменімен зоопарк қызметкерінің көзімен қарауға болады) ls /brokers/ids), қай брокер контроллер болып табылады (get /controller), бөлімдер олардың көшірмелерімен синхрондауда ма (get /brokers/topics/topic_name/partitions/partition_number/state). Сондай-ақ, өндіруші мен тұтынушы алдымен қай брокерде қандай тақырыптар мен бөлімдер сақталғанын білу үшін зоопарк қызметкеріне барады. Тақырып үшін 1-ден жоғары репликация коэффициенті көрсетілген жағдайларда зоопарк қай бөлімдердің жетекші екенін көрсетеді (олар жазылады және одан оқылады). Брокер істен шыққан жағдайда, жаңа көшбасшы бөлімдері туралы ақпарат zookeeper-ге жазылады (1.1.0 нұсқасынан асинхронды түрде, ).
Кафканың ескі нұсқаларында зоопарк офсеттерді сақтауға жауапты болды, бірақ қазір олар арнайы тақырыпта сақталады. __consumer_offsets брокерде (бірақ сіз әлі де осы мақсаттар үшін зоопаркты пайдалана аласыз).
Деректерді асқабаққа айналдырудың ең оңай жолы - зоопарктан алынған ақпаратты жоғалту. Мұндай сценарийде нені және қайдан оқу керектігін түсіну өте қиын болады.
өндіруші
Продюсер көбінесе Apache Kafka-ға деректерді тікелей жазатын қызмет болып табылады. Өндіруші тақырыптық хабарларды сақтайтын тақырыпты таңдап, оған ақпарат жаза бастайды. Мысалы, өндіруші жарнама қызметі болуы мүмкін. Бұл жағдайда ол тақырыптық тақырыптарға «жарнама жасалды», «жарнама жаңартылды», «жарнама жойылды» және т.б. оқиғаларды жібереді. Әрбір оқиға кілт-мән жұбы болып табылады.
Әдепкі бойынша барлық оқиғалар, егер кілт көрсетілмесе (реттеуді жоғалту) және кілт бар болса (бір бөлімде тапсырыс беру) MurmurHash (кілт) арқылы айналымды пайдалану арқылы тақырып бөлімдері арасында таратылады.
Бірден айта кететін жайт, Кафка оқиғалардың ретіне тек бір топта кепілдік береді. Бірақ іс жүзінде бұл жиі проблема емес. Мысалы, бір мәлімдемеге жасалған барлық өзгерістерді бір бөлімге қосуға сенімді бола аласыз (осылайша бұл өзгерістердің декларацияда ретін сақтай отырып). Оқиға өрістерінің бірінде реттік нөмірді де жіберуге болады.
Тұтынушылардың

Тұтынушы Apache Kafka деректерін алуға жауапты. Жоғарыдағы мысалға оралсақ, тұтынушы модерация қызметі болуы мүмкін. Бұл қызмет жарнама қызметінің тақырыбына жазылады және жаңа жарнама пайда болғанда, ол оны қабылдап, кейбір көрсетілген саясаттарға сәйкестігін талдайды.
Апачи Кафка тұтынушы қандай соңғы оқиғаларды алғанын есіне алады (ол үшін қызмет тақырыбы пайдаланылады __consumer__offsets), осылайша оқу сәтті болса, тұтынушы бір хабарламаны екі рет алмауын қамтамасыз етеді. Дегенмен, enable.auto.commit = true опциясын қолдансаңыз және тұтынушының тақырыптағы орнын бақылау жұмысын толығымен Кафкаға тапсырсаңыз, . Өндірістік кодта көбінесе тұтынушының позициясы қолмен басқарылады (әзірлеуші оқылған оқиғаның орындалуы қажет сәтті басқарады).
Бір тұтынушы жеткіліксіз болған жағдайда (мысалы, жаңа оқиғалар ағыны өте үлкен), тұтынушылар тобында оларды біріктіру арқылы тағы бірнеше тұтынушыларды қосуға болады. Тұтынушы тобы логикалық тұрғыдан тұтынушымен бірдей, бірақ деректер топ мүшелері арасында таратылады. Бұл әрбір қатысушыға хабарламалардың өз үлесін алуға мүмкіндік береді, осылайша оқу жылдамдығын кеңейтеді.
Тест нәтижелері

Мен мұнда көп түсіндірме мәтін жазбаймын, тек алынған нәтижелермен бөлісемін. Тестілеу 3 физикалық машинада (12 процессор, 384 ГБ жедел жады, 15к SAS DISK, 10 Гбит/с Net) жүргізілді, брокерлер мен зоопарк lxc-де орналастырылды.
Өнімділік сынағы
Тестілеу барысында келесі нәтижелер алынды.
- 1 продюсердің бір уақытта 9 КБ хабарлама жазу жылдамдығы секундына 1300000 XNUMX XNUMX оқиғаны құрайды.
- 1 КБ хабарламаларды 9 тұтынушының бір уақытта оқу жылдамдығы секундына 1500000 XNUMX XNUMX оқиғаны құрайды.
Ақауларға төзімділік сынағы
Тестілеу барысында келесі нәтижелер алынды (3 брокер, 3 зоопарк).
- Брокерлердің бірінің жұмысының қалыпты түрде тоқтатылуы кластердің тоқтауына немесе қолжетімсіз болуына әкелмейді. Жұмыс әдеттегідей жалғасуда, бірақ қалған брокерлердің жұмысы ауыр.
- Үш брокерлер кластері және min.isr = 2 болған жағдайда екі брокердің қалыпты түрде тоқтатылуы кластердің жазу үшін қолжетімсіз, бірақ оқу үшін қолжетімді болуына әкеледі. Егер min.isr = 1 болса, кластер оқуға да, жазуға да қолжетімді болады. Дегенмен, бұл режим жоғары деректер қауіпсіздігі талабына қайшы келеді.
- Zookeeper серверлерінің бірінің қалыпты түрде тоқтатылуы кластердің тоқтауына немесе қолжетімсіз болуына себеп болмайды. Жұмыс әдеттегідей жалғасуда.
- Екі Zookeeper серверінің қалыптан тыс жабылуы Zookeeper серверлерінің кем дегенде біреуі қалпына келгенше кластердің қолжетімсіздігіне әкеледі. Бұл мәлімдеме 3 серверден тұратын Zookeeper кластері үшін дұрыс. Нәтижесінде, зерттеулерден кейін ақауларға төзімділікті арттыру үшін Zookeeper кластерін 5 серверге дейін ұлғайту туралы шешім қабылданды.
Кафка қызмет ретінде

Біз Кафканың бізге жүктелген тапсырманы шешуге мүмкіндік беретін тамаша технология екеніне сенімдіміз (хабарлама брокерін жүзеге асыру). Дегенмен, біз қызметтерге Кафкаға тікелей кіруге тыйым салуды шештік және оны деректер шинасы қызметімен жабамыз. Неліктен біз мұны істедік? Шын мәнінде, бірнеше себептер бар.
Data-bus Кафкамен интеграцияға қатысты барлық тапсырмаларды өз мойнына алды (тұтынушылар мен өндірушілерді енгізу және конфигурациялау, бақылау, ескерту, тіркеу, масштабтау және т.б.). Осылайша, хабарлама брокерімен интеграция мүмкіндігінше қарапайым.
Data-bus бізге Кафкамен жұмыс істеу үшін белгілі бір тілден немесе кітапханадан абстракциялауға мүмкіндік берді.
Деректер шинасы басқа қызметтерге сақтау қабатын абстракциялауға мүмкіндік берді. Мүмкін бір сәтте біз Кафканы Пульсарға ауыстырамыз және ешкім ештеңені байқамайды (барлық қызметтер тек API деректер автобусы туралы біледі).
Деректер шинасы оқиға схемаларын тексеруді қабылдады.
Аутентификация деректер шинасы арқылы жүзеге асырылады.
Деректер шинасы арқылы біз Кафка нұсқаларын тоқтаусыз тыныш жаңарта аламыз, өндірушілердің, тұтынушылардың, брокерлердің және т.б. конфигурацияларды орталықтан басқара аламыз.
Data-bus бізге Кафкада жоқ қажетті мүмкіндіктерді қосуға мүмкіндік берді (мысалы, тақырыптарды тексеру, кластердегі аномалияларды бақылау, DLQ құру және т.б.).
Деректер шинасы барлық қызметтер үшін орталықтандырылған ауыстыруды жүзеге асыруға мүмкіндік береді.
Қазіргі уақытта хабарлама брокеріне оқиғаларды жіберуді бастау үшін сізге қызмет кодына шағын кітапхананы қосу жеткілікті. Мұның бәрі. Сізде кодтың бір жолымен жазу, оқу және масштабтау мүмкіндігі бар. Бүкіл іске асыру сізден жасырылған, тек бірнеше пакеттік өлшем тұтқалары шығып тұрады. Сорғыштың астында деректер шинасы қызметі Kubernetes-те өндіруші және тұтынушы даналарының қажетті санын арттырады және оларды қажетті конфигурациямен қамтамасыз етеді, бірақ мұның бәрі сіздің қызметіңіз үшін ашық.
Әрине, күміс оқ жоқ және бұл тәсілдің өз шектеулері бар.
- Деректер шинасына үшінші тарап кітапханаларына қарағанда, үйде қолдау көрсету қажет.
- Деректер шинасы қызметтер мен хабар брокері арасындағы өзара әрекеттесу санын көбейтеді, бұл жалаң Кафкамен салыстырғанда төмен өнімділікке әкеледі.
- Қызметтерден барлығын оңай жасыру мүмкін емес, біз деректер автобусында KSQL немесе Kafka Streams функционалдығын қайталағымыз келмейді, сондықтан кейде қызметтерге тікелей өтуге рұқсат беруіміз керек.
Біздің жағдайда, артықшылықтар кемшіліктерден асып түсті және хабарлама брокерін бөлек қызметпен қамту туралы шешім ақталды. Жұмыс істеген жылы бізде ауыр апаттар мен проблемалар болған жоқ.
PS Менің дос қызым Екатерина Обаляеваға осы мақаладағы керемет суреттері үшін рахмет. Егер сіз оларды ұнатсаңыз, алда тағы да иллюстрациялар бар.
Ақпарат көзі: www.habr.com
