Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Прывітанне, Хабр!

Нагадваем, што ўслед за кнігай аб Кафка мы выпусцілі не менш цікавую працу аб бібліятэцы Kafka Streams API.

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Пакуль супольнасць толькі спасцігае межы магчымасцяў гэтага магутнага інструмента. Так, нядаўна выйшаў артыкул, з перакладам якога мы жадаем вас пазнаёміць. На ўласным досведзе аўтар распавядае, як зрабіць з Kafka Streams размеркаванае сховішча дадзеных. Прыемнага чытання!

Бібліятэка Apache Kafka Streams па ўсім свеце выкарыстоўваецца ў энтерпрайзе для размеркаванай струменевай апрацоўкі па-над Apache Kafka. Адзін з недаацэненых аспектаў гэтага фрэймворка складаецца ў тым, што ён дазваляе захоўваць лакальны стан, якое вырабляецца на аснове струменевай апрацоўкі.

У гэтым артыкуле я распавяду, як у нашай кампаніі атрымалася выгодна задзейнічаць гэтую магчымасць пры распрацоўцы прадукта па бяспецы хмарных прыкладанняў. Пры дапамозе Kafka Streams мы стварылі мікрасэрвісы з падзяляным станам, кожны з якіх служыць нам адмоваўстойлівай і высокадаступнай крыніцай дакладнай інфармацыі аб стане аб'ектаў у сістэме. Для нас гэта крок наперад як у стаўленні надзейнасці, так і ў выгодзе падтрымкі.

Калі вас цікавіць альтэрнатыўны падыход, які дазваляе выкарыстоўваць адзіную цэнтральную базу дадзеных для падтрымкі фармальнага стану вашых аб'ектаў - пачытайце, будзе цікава…

Чаму мы палічылі, што прыйшоў час мяняць нашы падыходы да працы з падзяляным станам.

Нам патрабавалася падтрымліваць стан розных аб'ектаў, абапіраючыся на справаздачы агентаў (напрыклад: ці падвяргаўся сайт атацы)? Да пераходу на Kafka Streams мы часцяком належылі для кіравання станам на адзіную цэнтральную базу дадзеных (+ сэрвісны API). У такога падыходу ёсць свае недахопы: у датаінтэнсіўных сітуацыях падтрымка ўзгодненасці і сінхранізацыі ператвараецца ў сапраўдны выклік. База дадзеных можа стаць вузкім месцам, або аказвацца ў стане гонкі і пакутаваць ад непрадказальнасці.

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 1: тыповы сцэнар з падзелам стану, які сустракаўся на да пераходу на
Kafka і Kafka Streams: агенты паведамляюць свае ўяўленні праз API, абноўлены стан разлічваецца праз цэнтральную базу дадзеных

Знаёмцеся з Kafka Streams - зараз стала проста ствараць мікрасэрвісы з падзяляным станам

Прыкладна год таму мы вырашылі добра перагледзець нашы сцэнары працы з падзяляным станам, каб разабрацца з такімі праблемамі. Адразу ж вырашылі паспрабаваць Kafka Streams – вядома, наколькі яна якая маштабуецца, высокадаступная і адмоваўстойлівая, які багаты ў яе струменевы функцыянал (пераўтварэнні, у тым ліку, з захаваннем стану). Якраз тое, што нам патрабавалася, не кажучы ўжо пра тое, наколькі спелая і надзейная сістэма абмену паведамленнямі склалася ў Kafka.

Кожны са створаных намі мікрасэрвісаў з захаваннем стану будаваўся на аснове інстансу Kafka Streams з даволі простай тапалогіяй. Ён складаўся з 1) крыніцы 2) працэсара з пастаянным сховішчам ключоў і значэнняў 3) сцёку:

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 2: задаецца па змаўчанні тапалогія нашых струменевых інстансаў для мікрасэрвісаў з захаваннем стану. Звярніце ўвагу: тут таксама ёсць сховішча, у якім знаходзяцца метададзеныя аб планаванні.

Пры такім новым падыходзе агенты складаюць паведамленні, якія падаюцца ў зыходны топік, а спажыўцы - скажам, сэрвіс паштовых апавяшчэнняў - прымаюць вылічаны падзялянае стан праз сцёк (выхадны топік).

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 3: новы прыклад струменя задач для сцэнара з падзялянымі мікрасэрвісамі: 1) агент спараджае паведамленне, якое паступае ў зыходны топік Kafka; 2) мікрасэрвіс з падзяляным станам (які выкарыстоўвае Kafka Streams) апрацоўвае яго і запісвае вылічаны стан у канчатковы топік Kafka; пасля чаго 3) спажыўцы прымаюць новы стан

Гэй, а гэтае ўбудаванае сховішча ключоў і значэнняў насамрэч вельмі карысна!

Як згадвалася вышэй, наша тапалогія з падзяляным станам утрымоўвае сховішча ключоў і значэнняў. Мы знайшлі некалькі варыянтаў яго выкарыстання, і два з іх апісаны ніжэй.

Варыянт #1: выкарыстанне сховішча ключоў і значэнняў пры вылічэннях

Наша першае сховішча ключоў і значэнняў утрымлівала дапаможныя дадзеныя, якія патрабаваліся нам для вылічэнняў. Напрыклад, у некаторых выпадках стан, які падзяляецца, вызначаўся па прынцыпе «большасці галасоў». У сховішчы можна было трымаць усе апошнія справаздачы агентаў аб стане некаторага аб'екта. Затым, атрымліваючы новую справаздачу ад таго ці іншага агента, мы маглі захаваць яго, выняць са сховішча справаздачы ўсіх астатніх агентаў аб стане таго ж самага аб'екта і паўтарыць вылічэнне.
Ніжэй на ілюстрацыі 4 паказана, як мы адчынялі доступ да сховішча ключоў і значэнняў апрацоўваламу метаду працэсара, так што затым можна было апрацаваць новае паведамленне.

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 4: адчыняны доступ да сховішча ключоў і значэнняў для апрацоўвальнага метаду працэсара (пасля гэтага ў кожным сцэнары, які працуе з падзяляным станам, неабходна рэалізаваць метад doProcess)

Варыянт #2: стварэнне CRUD API па-над Kafka Streams

Наладзіўшы наш базавы паток задач, мы сталі спрабаваць напісаць RESTful CRUD API для нашых мікрасэрвісаў з падзяляным станам. Мы хацелі, каб можна было здабываць стан некаторых ці ўсіх аб'ектаў, а таксама ўсталёўваць ці выдаляць стан аб'екта (гэта карысна пры падтрымцы сервернай часткі).

Для падтрымкі ўсіх API Get State, кожны раз, калі нам патрабавалася зноўку вылічаць стан пры апрацоўцы, мы надоўга ўкладвалі яго ва ўбудаванае сховішча ключоў і значэнняў. У такім выпадку становіцца досыць проста рэалізаваць такі API пры дапамозе адзінага асобніка Kafka Streams, як паказана ў ніжэйпрыведзеным лістынгу:

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 5: выкарыстанне ўбудаванага сховішча ключоў і значэнняў для атрымання перадвылічанага стану аб'екта

Абнаўленне стану аб'екта праз API таксама нескладана рэалізаваць. У прынцыпе, для гэтага трэба толькі стварыць прадзюсар Kafka, а з яго дапамогай зрабіць запіс, у якім заключана новы стан. Так гарантуецца, што ўсе паведамленні, згенераваныя праз API, будуць апрацоўвацца сапраўды гэтак жа, як і якія паступаюць ад іншых прадз'юсараў (напр. агентаў).

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 6: задаць стан аб'екта можна пры дапамозе прад'юсера Kafka

Невялікае ўскладненне: у Kafka мноства партыцый

Далей мы жадалі размеркаваць нагрузку, злучаную з апрацоўкай, і палепшыць даступнасць, падаўшы на кожны сцэнар кластар мікрасэрвісаў з падзяляным станам. Налада далася нам прасцей простага: пасля таго, як мы сканфігуравалі ўсе інстансы так, каб яны працавалі з адным і тым жа ID прыкладанні (і з тымі ж серверамі пачатковай загрузкі), практычна ўсё астатняе рабілася аўтаматычна. Мы таксама задалі, што кожны зыходны топік будзе складацца з некалькіх партыцый, каб кожнаму інстансу можна было прысвоіць падмноства такіх партыцый.

Таксама згадаю, што тут у парадку рэчаў рабіць рэзервовую копію сховішча станаў, каб, напрыклад, у выпадку аднаўлення пасля адмовы пераносіць гэтую копію на іншы інстанс. На кожнае сховішча станаў у Kafka Streams ствараецца які рэплікуецца топік з часопісам змен (у якім адсочваюцца лакальныя абнаўленні). Такім чынам, Kafka стала падстрахоўвае сховішча станаў. Таму ў выпадку адмовы таго ці іншага інстансу Kafka Streams сховішча станаў можа быць хутка адноўлена на іншым інстансе, куды пяройдуць адпаведныя партіціі. Наш тэст паказаў, што гэта робіцца за лічаныя секунды нават калі ў сховішчы знаходзяцца мільёны запісаў.

Пераходзячы ад аднаго мікрасэрвісу з падзяляным станам да кластара мікрасэрвісаў, становіцца не гэтак трывіяльна рэалізаваць Get State API. У новай сітуацыі ў сховішчы станаў кожнага мікрасэрвісу змяшчаецца толькі частка агульнай карціны (тыя аб'екты, чые ключы адлюстроўваліся на пэўную партыцыю). Прыходзілася вызначаць, на якім інстансе ўтрымоўваўся стан патрэбнага нам аб'екта, і мы рабілі гэта на падставе метададзеных струменяў, як паказана ніжэй:

Не толькі апрацоўка: Як мы зрабілі з Kafka Streams размеркаваную базу даных, і што з гэтага выйшла

Ілюстрацыя 7: пры дапамозе метададзеных патокаў мы вызначаем, з якога інстансу запытваць стан патрэбнага аб'екта; падобны падыход ужываўся з GET ALL API

асноўныя высновы

Сховішчы станаў у Kafka Streams дэ-факта могуць служыць размеркаванай базай дадзеных,

  • пастаянна рэплікуецца ў Kafka
  • Па-над такой сістэмай лёгка выбудоўваецца CRUD API
  • Апрацоўка множных партыцый атрымліваецца крыху складаней
  • Таксама магчыма дадаць адно або некалькі сховішчаў станаў у струменевую тапалогію для захоўвання дапаможных дадзеных. Такі варыянт можа выкарыстоўвацца для:
  • Доўгачасовага захоўвання дадзеных, патрэбных для вылічэнняў пры струменевай апрацоўцы
  • Доўгачасовага захоўвання дадзеных, якія могуць быць карысныя пры наступнай ініцыялізацыі струменевага інстансу
  • шмат чаго іншага…

Дзякуючы гэтым і іншым добрым якасцям Kafka Streams выдатна падыходзіць для падтрымкі глабальнага стану ў такой размеркаванай сістэме як наша. Kafka Streams паказала сябе вельмі надзейнай у прадакшэне (з моманту яе разгортвання мы практычна не гублялі паведамленняў), і мы ўпэўненыя, што гэтым яе магчымасці не абмяжоўваюцца!

Крыніца: habr.com

Дадаць каментар