Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Hoy Habr!

Ipinaaalala namin sa iyo na ang pagsunod sa aklat tungkol sa Kafka naglathala kami ng parehong kawili-wiling gawain tungkol sa aklatan Kafka Streams API.

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Sa ngayon, pinag-aaralan pa lang ng komunidad ang mga limitasyon ng makapangyarihang tool na ito. Kaya, kamakailang nai-publish ang isang artikulo, ang pagsasalin kung saan nais naming ipakilala sa iyo. Mula sa kanyang sariling karanasan, sinabi ng may-akda kung paano gawing distributed data storage ang Kafka Streams. Enjoy reading!

Apache library Mga Agos ng Kafka ginagamit sa buong mundo sa mga negosyo para sa distributed stream processing sa itaas ng Apache Kafka. Ang isa sa mga hindi gaanong pinahahalagahan na aspeto ng balangkas na ito ay nagbibigay-daan sa iyo na mag-imbak ng lokal na estado na ginawa batay sa pagproseso ng thread.

Sa artikulong ito, sasabihin ko sa iyo kung paano nagawang gamitin ng aming kumpanya ang pagkakataong ito nang kumita kapag bumubuo ng isang produkto para sa seguridad ng cloud application. Gamit ang Kafka Streams, lumikha kami ng mga shared state microservices, na ang bawat isa ay nagsisilbing fault-tolerant at mataas na available na mapagkukunan ng maaasahang impormasyon tungkol sa estado ng mga bagay sa system. Para sa amin, ito ay isang hakbang pasulong kapwa sa mga tuntunin ng pagiging maaasahan at kadalian ng suporta.

Kung interesado ka sa isang alternatibong diskarte na nagpapahintulot sa iyo na gumamit ng isang solong sentral na database upang suportahan ang pormal na estado ng iyong mga bagay, basahin ito, ito ay magiging kawili-wili...

Bakit naisip namin na oras na para baguhin ang paraan ng pagtatrabaho namin sa nakabahaging estado

Kailangan naming panatilihin ang estado ng iba't ibang bagay batay sa mga ulat ng ahente (halimbawa: inaatake ba ang site)? Bago lumipat sa Kafka Streams, madalas kaming umaasa sa isang sentral na database (+ service API) para sa pamamahala ng estado. Ang diskarte na ito ay may mga kawalan nito: mga sitwasyong masinsinang petsa ang pagpapanatili ng pare-pareho at pag-synchronize ay nagiging isang tunay na hamon. Ang database ay maaaring maging isang bottleneck o mapunta sa kondisyon ng lahi at magdusa mula sa unpredictability.

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Figure 1: Isang tipikal na senaryo ng split-state na nakita bago ang paglipat sa
Mga Kafka at Kafka Stream: ipinapahayag ng mga ahente ang kanilang mga pananaw sa pamamagitan ng API, ang na-update na estado ay kinakalkula sa pamamagitan ng isang sentral na database

Kilalanin ang Kafka Streams, na ginagawang madali ang paggawa ng mga shared state microservices

Humigit-kumulang isang taon na ang nakalipas, nagpasya kaming suriing mabuti ang aming mga ibinahaging sitwasyon ng estado upang matugunan ang mga isyung ito. Agad naming napagpasyahan na subukan ang Kafka Stream - alam namin kung gaano ito nasusukat, lubos na magagamit at hindi mapagparaya sa fault, at kung gaano kayaman ang streaming functionality nito (mga pagbabago, kabilang ang mga stateful). Kung ano lang ang kailangan namin, hindi banggitin kung gaano kalaki at maaasahan ang sistema ng pagmemensahe sa Kafka.

Ang bawat isa sa mga stateful na microservice na ginawa namin ay binuo sa ibabaw ng isang halimbawa ng Kafka Streams na may medyo simpleng topology. Binubuo ito ng 1) isang source 2) isang processor na may patuloy na key-value store 3) isang lababo:

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Figure 2: Ang default na topology ng aming streaming instances para sa stateful microservices. Tandaan na mayroon ding repository dito na naglalaman ng metadata ng pagpaplano.

Sa bagong diskarte na ito, ang mga ahente ay bumubuo ng mga mensahe na ipinadala sa pinagmulang paksa, at ang mga mamimili—sabihin, isang serbisyo sa pag-abiso sa mail—ay natatanggap ang nakalkulang ibinahaging estado sa pamamagitan ng lababo (output topic).

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Figure 3: Bagong halimbawang daloy ng gawain para sa isang senaryo na may mga nakabahaging microservice: 1) ang ahente ay bumubuo ng isang mensahe na dumarating sa paksa ng pinagmulan ng Kafka; 2) pinoproseso ito ng isang microservice na may nakabahaging estado (gamit ang Kafka Streams) at isinusulat ang kinakalkulang estado sa huling paksa ng Kafka; pagkatapos nito 3) tinatanggap ng mga mamimili ang bagong estado

Uy, talagang lubhang kapaki-pakinabang ang built-in na key-value store na ito!

Gaya ng nabanggit sa itaas, ang aming shared state topology ay naglalaman ng key-value store. Nakakita kami ng ilang mga opsyon para sa paggamit nito, at dalawa sa mga ito ang inilalarawan sa ibaba.

Opsyon #1: Gumamit ng key-value store para sa mga kalkulasyon

Ang aming unang key-value store ay naglalaman ng auxiliary data na kailangan namin para sa mga kalkulasyon. Halimbawa, sa ilang mga kaso ang ibinahaging estado ay tinutukoy ng prinsipyo ng "mga boto ng karamihan". Maaaring hawakan ng repositoryo ang lahat ng pinakabagong ulat ng ahente sa katayuan ng ilang bagay. Pagkatapos, kapag nakatanggap kami ng bagong ulat mula sa isang ahente o iba pa, maaari naming i-save ito, kunin ang mga ulat mula sa lahat ng iba pang ahente tungkol sa estado ng parehong bagay mula sa imbakan, at ulitin ang pagkalkula.
Ipinapakita ng Figure 4 sa ibaba kung paano namin inilantad ang key/value store sa paraan ng pagpoproseso ng processor para maproseso ang bagong mensahe.

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Larawan 4: Binubuksan namin ang access sa key-value store para sa paraan ng pagproseso ng processor (pagkatapos nito, dapat ipatupad ng bawat script na gumagana sa shared state ang pamamaraan doProcess)

Opsyon #2: Paglikha ng CRUD API sa ibabaw ng Kafka Streams

Nang maitatag ang aming pangunahing daloy ng gawain, sinimulan naming subukang magsulat ng isang RESTful CRUD API para sa aming mga ibinahaging microservice ng estado. Nais naming makuha ang estado ng ilan o lahat ng mga bagay, pati na rin itakda o alisin ang estado ng isang bagay (kapaki-pakinabang para sa suporta sa backend).

Upang suportahan ang lahat ng Get State API, sa tuwing kailangan naming kalkulahin ang estado sa panahon ng pagproseso, inimbak namin ito sa isang built-in na key-value store sa loob ng mahabang panahon. Sa kasong ito, nagiging medyo simple ang pagpapatupad ng naturang API gamit ang isang halimbawa ng Kafka Streams, tulad ng ipinapakita sa listahan sa ibaba:

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Figure 5: Paggamit ng built-in na key-value store upang makuha ang precomputed na estado ng isang bagay

Ang pag-update ng estado ng isang bagay sa pamamagitan ng API ay madali ding ipatupad. Karaniwan, ang kailangan mo lang gawin ay lumikha ng isang producer ng Kafka at gamitin ito upang gumawa ng isang tala na naglalaman ng bagong estado. Tinitiyak nito na ang lahat ng mga mensaheng nabuo sa pamamagitan ng API ay mapoproseso sa parehong paraan tulad ng mga natanggap mula sa iba pang mga producer (hal. mga ahente).

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Figure 6: Maaari mong itakda ang estado ng isang bagay gamit ang Kafka producer

Maliit na komplikasyon: Maraming partisyon ang Kafka

Susunod, gusto naming ipamahagi ang pag-load sa pagpoproseso at pagbutihin ang kakayahang magamit sa pamamagitan ng pagbibigay ng isang kumpol ng mga shared-state na microservice sa bawat senaryo. Ang pag-setup ay madali lang: sa sandaling na-configure namin ang lahat ng mga pagkakataon upang tumakbo sa ilalim ng parehong ID ng application (at ang parehong mga server ng bootstrap), halos lahat ng iba pa ay awtomatikong ginawa. Tinukoy din namin na ang bawat paksang pinagmumulan ay bubuo ng ilang mga partisyon, upang ang bawat pagkakataon ay maitatalaga ng isang subset ng naturang mga partisyon.

Babanggitin ko rin na karaniwang kasanayan ang gumawa ng backup na kopya ng state store para, halimbawa, sa kaso ng pagbawi pagkatapos ng pagkabigo, ilipat ang kopyang ito sa ibang pagkakataon. Para sa bawat tindahan ng estado sa Kafka Streams, isang replicated na paksa ang nilikha na may log ng pagbabago (na sumusubaybay sa mga lokal na update). Kaya, patuloy na bina-back up ni Kafka ang tindahan ng estado. Samakatuwid, kung sakaling mabigo ang isa o isa pang halimbawa ng Kafka Streams, ang tindahan ng estado ay maaaring mabilis na maibalik sa isa pang pagkakataon, kung saan mapupunta ang mga kaukulang partisyon. Ipinakita ng aming mga pagsusuri na ginagawa ito sa loob ng ilang segundo, kahit na mayroong milyun-milyong talaan sa tindahan.

Ang paglipat mula sa isang microservice na may nakabahaging estado patungo sa isang kumpol ng mga microservice, nagiging hindi gaanong mahalaga na ipatupad ang Get State API. Sa bagong sitwasyon, ang state store ng bawat microservice ay naglalaman lamang ng bahagi ng pangkalahatang larawan (yung mga bagay na ang mga key ay nakamapa sa isang partikular na partition). Kinailangan naming matukoy kung aling instance ang naglalaman ng estado ng bagay na kailangan namin, at ginawa namin ito batay sa metadata ng thread, tulad ng ipinapakita sa ibaba:

Hindi lamang pagpoproseso: Paano kami gumawa ng isang distributed database mula sa Kafka Streams, at kung ano ang nagmula rito

Figure 7: Gamit ang stream metadata, tinutukoy namin kung saang pagkakataon itatanong ang estado ng gustong bagay; isang katulad na diskarte ang ginamit sa GET ALL API

Pangunahing natuklasan

Ang mga tindahan ng estado sa Kafka Streams ay maaaring magsilbi bilang isang de facto na ipinamamahaging database,

  • patuloy na ginagaya sa Kafka
  • Ang isang CRUD API ay madaling maitayo sa ibabaw ng naturang sistema
  • Ang paghawak ng maramihang mga partisyon ay medyo mas kumplikado
  • Posible ring magdagdag ng isa o higit pang state store sa streaming topology para mag-imbak ng auxiliary data. Maaaring gamitin ang pagpipiliang ito para sa:
  • Pangmatagalang imbakan ng data na kailangan para sa mga kalkulasyon sa panahon ng pagpoproseso ng stream
  • Pangmatagalang pag-iimbak ng data na maaaring maging kapaki-pakinabang sa susunod na pagkakataong mai-provision ang streaming instance
  • higit pa...

Ang mga ito at iba pang mga pakinabang ay ginagawang angkop ang Kafka Streams para sa pagpapanatili ng pandaigdigang estado sa isang distributed system tulad ng sa amin. Ang Kafka Streams ay napatunayang napaka maaasahan sa produksyon (halos wala kaming nawala na mensahe mula noong i-deploy ito), at tiwala kaming hindi titigil doon ang mga kakayahan nito!

Pinagmulan: www.habr.com

Magdagdag ng komento