Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka

Pagpapatuloy ng pagsasalin ng isang maliit na libro:
Pag-unawa sa Mga Broker ng Mensahe
may-akda: Jakub Korab, publisher: O'Reilly Media, Inc., petsa ng publikasyon: Hunyo 2017, ISBN: 9781492049296.

Nakaraang isinalin na bahagi: Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 1 Panimula

KABANATA 3

Kafka

Ang Kafka ay binuo ng LinkedIn upang lampasan ang ilan sa mga limitasyon ng tradisyonal na mga broker ng mensahe at maiwasan ang pag-set up ng maramihang mga broker ng mensahe para sa iba't ibang point-to-point na pakikipag-ugnayan, na inilalarawan sa aklat na ito sa ilalim ng "Pag-scale up at out" sa pahina 28 . Mga kaso ng paggamit Ang LinkedIn ay higit na umasa sa one-way na pag-ingest ng napakalaking dami ng data, gaya ng mga pag-click sa page at mga log ng pag-access, habang pinapayagan pa rin ang data na iyon na magamit ng maraming system nang hindi naaapektuhan ang pagiging produktibo ng mga producer o iba pang mga consumer. Sa katunayan, ang dahilan kung bakit umiiral ang Kafka ay upang makuha ang uri ng arkitektura ng pagmemensahe na inilalarawan ng Universal Data Pipeline.

Dahil sa pinakahuling layuning ito, natural na lumitaw ang iba pang mga kinakailangan. Ang Kafka ay dapat:

  • Maging napakabilis
  • Magbigay ng mas maraming bandwidth kapag nagtatrabaho sa mga mensahe
  • Suportahan ang Publisher-Subscriber at Point-to-Point na mga modelo
  • Huwag magdahan-dahan sa pagdaragdag ng mga mamimili. Halimbawa, ang pagganap ng parehong queue at ang paksa sa ActiveMQ ay bumababa habang lumalaki ang bilang ng mga mamimili sa destinasyon.
  • Maging pahalang na nasusukat; kung ang isang broker na nagpatuloy ng mga mensahe ay magagawa lamang ito sa maximum na bilis ng disk, makatuwirang lumampas sa isang instance ng broker upang mapataas ang pagganap
  • Limitahan ang pag-access sa pag-iimbak at muling pagkuha ng mga mensahe

Upang makamit ang lahat ng ito, pinagtibay ng Kafka ang isang arkitektura na muling tinukoy ang mga tungkulin at responsibilidad ng mga kliyente at mga broker ng pagmemensahe. Ang modelo ng JMS ay napaka-broker oriented, kung saan ang broker ay may pananagutan sa pamamahagi ng mga mensahe at ang mga kliyente ay kailangang mag-alala tungkol sa pagpapadala at pagtanggap ng mga mensahe. Ang Kafka, sa kabilang banda, ay nakasentro sa kliyente, kung saan ang kliyente ay gumagamit ng marami sa mga tampok ng isang tradisyunal na broker, tulad ng patas na pamamahagi ng mga nauugnay na mensahe sa mga mamimili, kapalit ng isang napakabilis at nasusukat na broker. Para sa mga taong nagtrabaho sa tradisyonal na mga sistema ng pagmemensahe, ang pakikipagtulungan sa Kafka ay nangangailangan ng pangunahing pagbabago ng isip.
Ang direksyong pang-inhinyero na ito ay humantong sa paglikha ng isang imprastraktura sa pagmemensahe na may kakayahang pataasin ang throughput ng maraming mga order ng magnitude kumpara sa isang maginoo na broker. Tulad ng makikita natin, ang diskarte na ito ay may mga trade-off, na nangangahulugan na ang Kafka ay hindi angkop para sa ilang mga uri ng mga workload at naka-install na software.

Pinag-isang Modelo ng Destinasyon

Upang matupad ang mga kinakailangan na inilarawan sa itaas, pinagsama ng Kafka ang pag-publish-subscribe at point-to-point na pagmemensahe sa ilalim ng isang uri ng destinasyon βˆ’ paksa. Ito ay nakalilito sa mga taong nagtrabaho sa mga sistema ng pagmemensahe, kung saan ang salitang "paksa" ay tumutukoy sa isang mekanismo ng broadcast kung saan (mula sa paksa) ang pagbabasa ay hindi matitiis. Ang mga paksa ng Kafka ay dapat ituring na isang hybrid na uri ng destinasyon, gaya ng tinukoy sa panimula sa aklat na ito.

Para sa natitirang bahagi ng kabanatang ito, maliban kung tahasan naming sabihin kung hindi man, ang terminong "paksa" ay tumutukoy sa isang paksa ng Kafka.

Upang lubos na maunawaan kung paano kumikilos ang mga paksa at kung anong mga garantiya ang ibinibigay ng mga ito, kailangan muna nating tingnan kung paano ipinapatupad ang mga ito sa Kafka.
Ang bawat paksa sa Kafka ay may sariling log.
Ang mga producer na nagpapadala ng mga mensahe sa Kafka ay sumusulat sa log na ito, at ang mga consumer ay nagbabasa mula sa log gamit ang mga pointer na patuloy na sumusulong. Paminsan-minsan, tinatanggal ng Kafka ang mga pinakalumang bahagi ng log, nabasa man o hindi ang mga mensahe sa mga bahaging iyon. Ang pangunahing bahagi ng disenyo ng Kafka ay ang broker ay walang pakialam kung ang mga mensahe ay nabasa o hindi - iyon ang responsibilidad ng kliyente.

Ang mga terminong "log" at "pointer" ay hindi lumilitaw sa Dokumentasyon ng Kafka. Ang mga kilalang terminong ito ay ginagamit dito upang makatulong sa pag-unawa.

Ang modelong ito ay ganap na naiiba mula sa ActiveMQ, kung saan ang mga mensahe mula sa lahat ng mga pila ay iniimbak sa parehong log, at minarkahan ng broker ang mga mensahe bilang tinanggal pagkatapos na basahin ang mga ito.
Maghukay tayo ng kaunti nang mas malalim at tingnan ang log ng paksa nang mas detalyado.
Ang Kafka log ay binubuo ng ilang mga partisyon (Figure 3-1). Ginagarantiyahan ng Kafka ang mahigpit na pag-order sa bawat partisyon. Nangangahulugan ito na ang mga mensaheng nakasulat sa partition sa isang tiyak na pagkakasunud-sunod ay babasahin sa parehong pagkakasunud-sunod. Ang bawat partition ay ipinatupad bilang isang rolling log file na naglalaman ng subset (subset) ng lahat ng mensaheng ipinadala sa paksa ng mga producer nito. Ang nilikhang paksa ay naglalaman, bilang default, ng isang partisyon. Ang ideya ng mga partisyon ay ang pangunahing ideya ng Kafka para sa pahalang na pag-scale.

Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka
Larawan 3-1. Mga Partisyon ng Kafka

Kapag nagpadala ang isang producer ng mensahe sa isang paksa ng Kafka, ito ang magpapasya kung saang partition ipapadala ang mensahe. Titingnan natin ito nang mas detalyado sa ibang pagkakataon.

Nagbabasa ng mga mensahe

Ang kliyenteng gustong basahin ang mga mensahe ay namamahala ng pinangalanang pointer na tinatawag pangkat ng mamimili, na tumuturo sa offset mga mensahe sa partisyon. Ang offset ay isang incremental na posisyon na nagsisimula sa 0 sa simula ng isang partition. Ang pangkat ng consumer na ito, na isinangguni sa API sa pamamagitan ng user-defined group_id, ay tumutugma sa isang lohikal na mamimili o sistema.

Karamihan sa mga system ng pagmemensahe ay nagbabasa ng data mula sa patutunguhan gamit ang maraming pagkakataon at mga thread upang iproseso ang mga mensahe nang magkatulad. Kaya, kadalasang magkakaroon ng maraming pagkakataon ng consumer na nagbabahagi ng parehong grupo ng consumer.

Ang problema sa pagbasa ay maaaring ilarawan sa mga sumusunod:

  • Ang paksa ay may maraming partisyon
  • Maraming mga grupo ng mga mamimili ang maaaring gumamit ng isang paksa sa parehong oras
  • Ang isang pangkat ng mga mamimili ay maaaring magkaroon ng maraming magkakahiwalay na pagkakataon

Ito ay isang hindi trivial na maraming-sa-maraming problema. Upang maunawaan kung paano pinangangasiwaan ng Kafka ang mga ugnayan sa pagitan ng mga grupo ng consumer, mga pagkakataon ng consumer, at mga partisyon, tingnan natin ang isang serye ng mga unti-unting mas kumplikadong mga sitwasyon sa pagbabasa.

Mga consumer at consumer group

Kunin natin bilang panimulang punto ang isang paksa na may isang partition (Figure 3-2).

Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka
Larawan 3-2. Nagbabasa ang consumer mula sa partition

Kapag ang isang consumer instance ay kumonekta sa sarili nitong group_id sa paksang ito, ito ay itatalaga ng read partition at isang offset sa partition na iyon. Ang posisyon ng offset na ito ay maaaring i-configure sa client bilang isang pointer sa pinakakamakailang posisyon (pinakabagong mensahe) o pinakamaagang posisyon (pinakamatandang mensahe). Ang mga mamimili ay humihiling (mga botohan) ng mga mensahe mula sa paksa, na nagiging sanhi ng mga ito na sunod-sunod na basahin mula sa log.
Ang offset na posisyon ay regular na ibinabalik sa Kafka at iniimbak bilang mga mensahe sa isang panloob na paksa _consumer_offsets. Ang mga nabasang mensahe ay hindi pa rin tinatanggal, hindi tulad ng isang regular na broker, at maaaring i-rewind ng kliyente ang offset upang muling iproseso ang mga natingnan nang mensahe.

Kapag kumonekta ang pangalawang lohikal na consumer gamit ang ibang group_id, namamahala ito ng pangalawang pointer na independiyente sa una (Figure 3-3). Kaya, ang isang paksa ng Kafka ay kumikilos tulad ng isang pila kung saan mayroong isang mamimili at tulad ng isang normal na paksa sa pag-publish-subscribe (pub-sub) kung saan maraming mga consumer ang naka-subscribe, na may karagdagang benepisyo na ang lahat ng mga mensahe ay nakaimbak at maaaring maproseso nang maraming beses.

Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka
Larawan 3-3. Dalawang consumer sa magkaibang grupo ng consumer ang nagbabasa mula sa parehong partition

Mga mamimili sa isang pangkat ng mga mamimili

Kapag ang isang consumer instance ay nagbabasa ng data mula sa isang partition, ito ay may ganap na kontrol sa pointer at nagpoproseso ng mga mensahe tulad ng inilarawan sa nakaraang seksyon.
Kung ilang pagkakataon ng mga consumer ang konektado sa parehong group_id sa isang paksa na may isang partition, kung gayon ang instance na huling nakakonekta ay bibigyan ng kontrol sa pointer at mula sa sandaling iyon ay matatanggap nito ang lahat ng mga mensahe (Figure 3-4).

Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka
Larawan 3-4. Dalawang consumer sa iisang consumer group ang nagbasa mula sa parehong partition

Ang mode na ito ng pagproseso, kung saan ang bilang ng mga pagkakataon ng consumer ay lumampas sa bilang ng mga partisyon, ay maaaring ituring na isang uri ng eksklusibong mamimili. Ito ay maaaring maging kapaki-pakinabang kung kailangan mo ng "active-passive" (o "hot-warm") clustering ng iyong mga consumer instance, bagama't ang pagpapatakbo ng maraming consumer nang magkatulad ("active-active" o "hot-hot") ay mas karaniwan kaysa sa mga mamimili. Naka-standby.

Ang pag-uugali ng pamamahagi ng mensahe na ito na inilarawan sa itaas ay maaaring nakakagulat kumpara sa kung paano kumikilos ang isang normal na pila ng JMS. Sa modelong ito, ang mga mensaheng ipinadala sa queue ay pantay na ipapamahagi sa pagitan ng dalawang consumer.

Kadalasan, kapag gumawa kami ng maraming pagkakataon ng mga consumer, ginagawa namin ito para magproseso ng mga mensahe nang magkatulad, o para mapabilis ang pagbabasa, o para mapataas ang katatagan ng proseso ng pagbabasa. Dahil isang instance ng consumer lang ang makakapagbasa ng data mula sa isang partition sa isang pagkakataon, paano ito makakamit sa Kafka?

Ang isang paraan upang gawin ito ay ang paggamit ng isang halimbawa ng consumer upang basahin ang lahat ng mga mensahe at ipasa ang mga ito sa thread pool. Habang pinapataas ng diskarteng ito ang throughput ng pagpoproseso, pinatataas nito ang pagiging kumplikado ng lohika ng consumer at walang ginagawa upang mapataas ang tibay ng sistema ng pagbabasa. Kung bumaba ang isang kopya ng consumer dahil sa pagkawala ng kuryente o katulad na kaganapan, hihinto ang pagbabawas.

Ang kanonikal na paraan upang malutas ang problemang ito sa Kafka ay ang paggamit ng bОhigit pang mga partisyon.

Pagkahati

Ang mga partisyon ay ang pangunahing mekanismo para sa pag-parallelize ng pagbabasa at pag-scale ng isang paksa na lampas sa bandwidth ng isang instance ng broker. Upang mas maunawaan ito, isaalang-alang natin ang isang sitwasyon kung saan mayroong isang paksa na may dalawang partisyon at isang mamimili ang nag-subscribe sa paksang ito (Figure 3-5).

Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka
Larawan 3-5. Ang isang mamimili ay nagbabasa mula sa maraming partisyon

Sa sitwasyong ito, binibigyan ng kontrol ang consumer sa mga pointer na tumutugma sa group_id nito sa parehong partition at magsisimulang magbasa ng mga mensahe mula sa parehong partition.
Kapag ang karagdagang consumer para sa parehong group_id ay idinagdag sa paksang ito, muling inilalaan ng Kafka ang isa sa mga partisyon mula sa una hanggang sa pangalawang consumer. Pagkatapos nito, ang bawat pagkakataon ng mamimili ay magbabasa mula sa isang partisyon ng paksa (Figure 3-6).

Upang matiyak na ang mga mensahe ay naproseso nang magkatulad sa 20 mga thread, kailangan mo ng hindi bababa sa 20 mga partisyon. Kung may mas kaunting mga partisyon, maiiwan ka sa mga mamimili na walang dapat gawin, tulad ng inilarawan nang mas maaga sa talakayan ng mga eksklusibong mamimili.

Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 3. Kafka
Larawan 3-6. Dalawang consumer sa iisang consumer group ang nagbabasa mula sa magkaibang partition

Ang scheme na ito ay lubos na binabawasan ang pagiging kumplikado ng Kafka broker kumpara sa pamamahagi ng mensahe na kinakailangan upang mapanatili ang JMS queue. Dito hindi mo kailangang mag-alala tungkol sa mga sumusunod na punto:

  • Sinong consumer ang dapat makatanggap ng susunod na mensahe, batay sa round-robin na paglalaan, kasalukuyang kapasidad ng mga prefetch buffer, o mga nakaraang mensahe (tulad ng para sa mga pangkat ng mensahe ng JMS).
  • Aling mga mensahe ang ipinadala sa kung aling mga mamimili at kung dapat silang muling ihatid kung sakaling mabigo.

Ang kailangan lang gawin ng Kafka broker ay magpasa ng mga mensahe nang sunud-sunod sa mamimili kapag hiniling sila ng huli.

Gayunpaman, ang mga kinakailangan para sa parallelizing ang pag-proofread at muling pagpapadala ng mga nabigong mensahe ay hindi nawawala - ang responsibilidad para sa mga ito ay ipinapasa lamang mula sa broker patungo sa kliyente. Nangangahulugan ito na dapat silang isaalang-alang sa iyong code.

Nagpapadala ng mga mensahe

Responsibilidad ng producer ng mensaheng iyon na magpasya kung saang partition magpapadala ng mensahe. Upang maunawaan ang mekanismo kung saan ito ginagawa, kailangan muna nating isaalang-alang kung ano ang eksaktong ipinapadala natin.

Samantalang sa JMS gumagamit kami ng istraktura ng mensahe na may metadata (mga header at property) at isang katawan na naglalaman ng payload (payload), sa Kafka ang mensahe ay ipares ang "key-value". Ang payload ng mensahe ay ipinadala bilang isang halaga. Ang susi, sa kabilang banda, ay pangunahing ginagamit para sa paghahati at dapat maglaman tukoy na susi ng lohika ng negosyoupang ilagay ang mga kaugnay na mensahe sa parehong partisyon.

Sa Kabanata 2, tinalakay namin ang senaryo ng online na pagtaya kung saan ang mga nauugnay na kaganapan ay kailangang iproseso sa pagkakasunud-sunod ng isang consumer:

  1. Ang user account ay na-configure.
  2. Ang pera ay kredito sa account.
  3. Ang isang taya ay ginawa na nag-withdraw ng pera mula sa account.

Kung ang bawat kaganapan ay isang mensaheng nai-post sa isang paksa, ang natural na susi ay ang account ID.
Kapag ipinadala ang isang mensahe gamit ang Kafka Producer API, ipinapasa ito sa isang partition function na, dahil sa mensahe at kasalukuyang estado ng Kafka cluster, ibabalik ang ID ng partition kung saan dapat ipadala ang mensahe. Ang tampok na ito ay ipinatupad sa Java sa pamamagitan ng interface ng Partitioner.

Mukhang ganito ang interface na ito:

interface Partitioner {
    int partition(String topic,
        Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);
}

Ang pagpapatupad ng Partitioner ay gumagamit ng default na pangkalahatang layunin na hashing algorithm sa ibabaw ng key upang matukoy ang partition, o round-robin kung walang key na tinukoy. Ang default na halaga na ito ay mahusay na gumagana sa karamihan ng mga kaso. Gayunpaman, sa hinaharap ay nais mong magsulat ng iyong sarili.

Pagsusulat ng iyong sariling diskarte sa paghati

Tingnan natin ang isang halimbawa kung saan mo gustong magpadala ng metadata kasama ang payload ng mensahe. Ang payload sa aming halimbawa ay isang tagubilin upang magdeposito sa account ng laro. Ang pagtuturo ay isang bagay na gusto naming matiyak na hindi mababago sa paghahatid at nais na makatiyak na ang pinagkakatiwalaang upstream na sistema lamang ang makakapagpasimula ng pagtuturong iyon. Sa kasong ito, ang mga sistema ng pagpapadala at pagtanggap ay sumasang-ayon sa paggamit ng isang lagda upang patunayan ang mensahe.
Sa normal na JMS, tumukoy lang kami ng property na "signature ng mensahe" at idagdag ito sa mensahe. Gayunpaman, ang Kafka ay hindi nagbibigay sa amin ng isang mekanismo para sa pagpasa ng metadata, isang susi lamang at isang halaga.

Dahil ang halaga ay isang bank transfer payload na ang integridad ay gusto naming panatilihin, wala kaming pagpipilian kundi tukuyin ang istraktura ng data na gagamitin sa key. Ipagpalagay na kailangan namin ng isang account ID para sa paghahati, dahil ang lahat ng mga mensahe na nauugnay sa isang account ay dapat na maiproseso sa pagkakasunud-sunod, gagawa kami ng sumusunod na istraktura ng JSON:

{
  "signature": "541661622185851c248b41bf0cea7ad0",
  "accountId": "10007865234"
}

Dahil ang halaga ng lagda ay mag-iiba-iba depende sa payload, ang default na diskarte sa pag-hash ng interface ng Partitioner ay hindi mapagkakatiwalaang ipapangkat ang mga nauugnay na mensahe. Samakatuwid, kakailanganin naming magsulat ng sarili naming diskarte na mag-parse sa key na ito at maghahati sa halaga ng accountId.

Kasama sa Kafka ang mga checksum upang matukoy ang katiwalian ng mga mensahe sa tindahan at may kumpletong hanay ng mga tampok na panseguridad. Gayunpaman, kung minsan ay lumalabas ang mga kinakailangan na partikular sa industriya, gaya ng nasa itaas.

Dapat tiyakin ng diskarte sa partitioning ng user na napupunta sa parehong partition ang lahat ng nauugnay na mensahe. Bagama't ito ay tila simple, ang kinakailangan ay maaaring kumplikado sa pamamagitan ng kahalagahan ng pag-order ng mga nauugnay na mensahe at kung paano naayos ang bilang ng mga partisyon sa isang paksa.

Ang bilang ng mga partition sa isang paksa ay maaaring magbago sa paglipas ng panahon, dahil maaari silang idagdag kung ang trapiko ay lampas sa mga paunang inaasahan. Kaya, ang mga message key ay maaaring iugnay sa partition kung saan sila orihinal na ipinadala, na nagpapahiwatig ng isang bahagi ng estado na ibabahagi sa pagitan ng mga pagkakataon ng producer.

Isa pang salik na dapat isaalang-alang ay ang pantay na pamamahagi ng mga mensahe sa mga partisyon. Karaniwan, ang mga susi ay hindi ibinabahagi nang pantay-pantay sa mga mensahe, at hindi ginagarantiyahan ng mga hash function ang isang patas na pamamahagi ng mga mensahe para sa isang maliit na hanay ng mga key.
Mahalagang tandaan na gayunpaman pinili mong hatiin ang mga mensahe, ang separator mismo ay maaaring kailangang muling gamitin.

Isaalang-alang ang kinakailangan upang kopyahin ang data sa pagitan ng mga cluster ng Kafka sa iba't ibang heyograpikong lokasyon. Para sa layuning ito, ang Kafka ay may kasamang command line tool na tinatawag na MirrorMaker, na ginagamit upang basahin ang mga mensahe mula sa isang cluster at ilipat ang mga ito sa isa pa.

Dapat na maunawaan ng MirrorMaker ang mga susi ng kinokopyang paksa upang mapanatili ang kaugnay na pagkakasunud-sunod sa pagitan ng mga mensahe kapag kinokopya sa pagitan ng mga cluster, dahil maaaring hindi pareho ang bilang ng mga partition para sa paksang iyon sa dalawang cluster.

Ang mga custom na diskarte sa partitioning ay medyo bihira, dahil ang default na hashing o round robin ay gumagana nang maayos sa karamihan ng mga sitwasyon. Gayunpaman, kung kailangan mo ng matibay na garantiya sa pag-order o kailangan mong kunin ang metadata mula sa mga payload, kung gayon ang paghati ay isang bagay na dapat mong tingnang mabuti.

Ang scalability at performance benefits ng Kafka ay nagmumula sa paglilipat ng ilan sa mga responsibilidad ng tradisyunal na broker sa kliyente. Sa kasong ito, isang desisyon ang ginawa upang ipamahagi ang mga potensyal na nauugnay na mensahe sa ilang mga mamimili na nagtatrabaho nang magkatulad.

Kailangan ding harapin ng mga JMS broker ang mga naturang pangangailangan. Kapansin-pansin, ang mekanismo para sa pagpapadala ng mga nauugnay na mensahe sa parehong consumer, na ipinatupad sa pamamagitan ng JMS Message Groups (isang variation sa diskarte sa sticky load balancing (SLB)), ay nangangailangan din sa nagpadala na markahan ang mga mensahe bilang nauugnay. Sa kaso ng JMS, ang broker ang may pananagutan sa pagpapadala ng grupong ito ng mga nauugnay na mensahe sa isang consumer sa marami, at paglilipat ng pagmamay-ari ng grupo kung mahulog ang consumer.

Mga Kasunduan sa Producer

Ang paghahati ay hindi lamang ang dapat isaalang-alang kapag nagpapadala ng mga mensahe. Tingnan natin ang mga paraan ng send() ng klase ng Producer sa Java API:

Future < RecordMetadata > send(ProducerRecord < K, V > record);
Future < RecordMetadata > send(ProducerRecord < K, V > record, Callback callback);

Dapat pansinin kaagad na ang parehong mga pamamaraan ay nagbabalik ng Hinaharap, na nagpapahiwatig na ang operasyon ng pagpapadala ay hindi ginanap kaagad. Ang resulta ay ang isang mensahe (ProducerRecord) ay nakasulat sa send buffer para sa bawat aktibong partition at ipinadala sa broker bilang background thread sa Kafka client library. Bagama't ginagawa nitong napakabilis ang mga bagay, nangangahulugan ito na maaaring mawalan ng mga mensahe ang isang walang karanasan na application kung ihihinto ang proseso nito.

Gaya ng nakasanayan, may paraan upang gawing mas maaasahan ang pagpapatakbo ng pagpapadala sa halaga ng pagganap. Ang laki ng buffer na ito ay maaaring itakda sa 0, at ang pagpapadala ng thread ng aplikasyon ay mapipilitang maghintay hanggang sa makumpleto ang paglipat ng mensahe sa broker, tulad ng sumusunod:

RecordMetadata metadata = producer.send(record).get();

Higit pa tungkol sa pagbabasa ng mga mensahe

Ang pagbabasa ng mga mensahe ay may mga karagdagang kumplikado na kailangang pag-isipan. Hindi tulad ng JMS API, na maaaring magpatakbo ng isang tagapakinig ng mensahe bilang tugon sa isang mensahe, ang Mamimili Kafka lamang ang mga botohan. Tingnan natin ang pamamaraan poll()ginagamit para sa layuning ito:

ConsumerRecords < K, V > poll(long timeout);

Ang return value ng method ay isang container structure na naglalaman ng maraming object rekord ng mamimili mula sa posibleng ilang partisyon. rekord ng mamimili ay mismong may hawak na object para sa isang key-value pair na may nauugnay na metadata, gaya ng partition kung saan ito nagmula.

Tulad ng tinalakay sa Kabanata 2, dapat nating isaisip kung ano ang mangyayari sa mga mensahe pagkatapos na matagumpay o hindi matagumpay na naproseso ang mga ito, halimbawa, kung hindi maproseso ng kliyente ang mensahe o kung ito ay abort. Sa JMS, pinangasiwaan ito sa pamamagitan ng mode ng pagkilala. Tatanggalin ng broker ang matagumpay na naprosesong mensahe, o muling ihahatid ang hilaw o pekeng mensahe (ipagpalagay na ginamit ang mga transaksyon).
Ibang-iba ang trabaho ng Kafka. Ang mga mensahe ay hindi tinatanggal sa broker pagkatapos ng pag-proofread, at kung ano ang mangyayari sa pagkabigo ay responsibilidad ng mismong proofreading code.

Tulad ng nasabi na namin, ang pangkat ng consumer ay nauugnay sa offset sa log. Ang posisyon ng log na nauugnay sa offset na ito ay tumutugma sa susunod na mensahe na ibibigay bilang tugon sa poll(). Ang punto sa oras kung kailan tumataas ang offset na ito ay mapagpasyahan para sa pagbabasa.

Pagbabalik sa modelo ng pagbasa na tinalakay kanina, ang pagpoproseso ng mensahe ay binubuo ng tatlong yugto:

  1. Kunin ang isang mensahe para sa pagbabasa.
  2. Iproseso ang mensahe.
  3. Kumpirmahin ang mensahe.

Ang mamimili ng Kafka ay may kasamang opsyon sa pagsasaayos enable.auto.commit. Ito ay isang madalas na ginagamit na default na setting, tulad ng karaniwan sa mga setting na naglalaman ng salitang "auto".

Bago ang Kafka 0.10, ang isang kliyente na gumagamit ng opsyong ito ay magpapadala ng offset ng huling mensaheng nabasa sa susunod na tawag poll() pagkatapos ng pagproseso. Nangangahulugan ito na ang anumang mga mensahe na nakuha na ay maaaring iproseso muli kung naproseso na ng kliyente ang mga ito ngunit hindi inaasahang nawasak bago tumawag. poll(). Dahil hindi pinapanatili ng broker ang anumang estado tungkol sa kung ilang beses nabasa ang isang mensahe, hindi malalaman ng susunod na mamimili na kukuha ng mensaheng iyon ang anumang masamang nangyari. Ang pag-uugaling ito ay pseudo-transaktional. Ang offset ay ginawa lamang kung ang mensahe ay matagumpay na naproseso, ngunit kung ang kliyente ay nag-abort, ang broker ay magpapadala muli ng parehong mensahe sa isa pang kliyente. Ang gawi na ito ay naaayon sa garantiya sa paghahatid ng mensahe "kahit isang beses".

Sa Kafka 0.10, ang client code ay binago upang ang commit ay na-trigger sa pana-panahon ng client library, gaya ng na-configure auto.commit.interval.ms. Ang gawi na ito ay nasa pagitan ng JMS AUTO_ACKNOWLEDGE at DUPS_OK_ACKNOWLEDGE mode. Kapag gumagamit ng autocommit, ang mga mensahe ay maaaring isagawa kahit na ang mga ito ay aktwal na naproseso - ito ay maaaring mangyari sa kaso ng isang mabagal na mamimili. Kung nag-abort ang isang consumer, kukunin ng susunod na consumer ang mga mensahe, simula sa nakatalagang posisyon, na maaaring magresulta sa isang hindi nakuhang mensahe. Sa kasong ito, hindi nawala sa Kafka ang mga mensahe, hindi lang naproseso ng reading code ang mga ito.

Ang mode na ito ay may parehong pangako tulad ng sa bersyon 0.9: ang mga mensahe ay maaaring iproseso, ngunit kung ito ay nabigo, ang offset ay maaaring hindi maisagawa, na posibleng magdulot ng pagdoble ng paghahatid. Ang mas maraming mensahe na kinukuha mo kapag nagsasagawa poll(), mas maraming problemang ito.

Gaya ng tinalakay sa β€œPagbabasa ng Mga Mensahe mula sa isang Queue” sa pahina 21, walang isang beses na paghahatid ng mensahe sa isang sistema ng pagmemensahe kapag ang mga failure mode ay isinasaalang-alang.

Sa Kafka, mayroong dalawang paraan para mag-commit (mag-commit) ng offset (offset): awtomatiko at manu-mano. Sa parehong mga kaso, ang mga mensahe ay maaaring iproseso nang maraming beses kung ang mensahe ay naproseso ngunit nabigo bago ang commit. Maaari mo ring piliing huwag iproseso ang mensahe kung nangyari ang commit sa background at nakumpleto ang iyong code bago ito maproseso (marahil sa Kafka 0.9 at mas maaga).

Makokontrol mo ang manu-manong offset commit na proseso sa Kafka consumer API sa pamamagitan ng pagtatakda ng parameter enable.auto.commit sa false at tahasang pagtawag sa isa sa mga sumusunod na pamamaraan:

void commitSync();
void commitAsync();

Kung gusto mong iproseso ang mensaheng "kahit isang beses", dapat mong manu-manong gawin ang offset commitSync()sa pamamagitan ng pagpapatupad ng utos na ito kaagad pagkatapos iproseso ang mga mensahe.

Hindi pinapayagan ng mga paraang ito na kilalanin ang mga mensahe bago ang mga ito iproseso, ngunit wala silang ginagawa upang maalis ang mga potensyal na pagkaantala sa pagproseso habang nagpapakita ng pagiging transactional. Walang mga transaksyon sa Kafka. Ang kliyente ay walang kakayahan na gawin ang mga sumusunod:

  • Awtomatikong ibalik ang isang pekeng mensahe. Ang mga mamimili mismo ay dapat humawak ng mga pagbubukod na nagmumula sa mga may problemang payload at backend outage, dahil hindi sila makakaasa sa broker upang muling maghatid ng mga mensahe.
  • Magpadala ng mga mensahe sa maraming paksa sa isang atomic operation. Tulad ng makikita natin sa ilang sandali, ang kontrol sa iba't ibang mga paksa at partisyon ay maaaring manatili sa iba't ibang mga makina sa cluster ng Kafka na hindi nagko-coordinate ng mga transaksyon kapag ipinadala. Sa oras ng pagsulat na ito, ilang gawain ang ginawa upang gawin itong posible sa KIP-98.
  • Iugnay ang pagbabasa ng isang mensahe mula sa isang paksa sa pagpapadala ng isa pang mensahe sa isa pang paksa. Muli, ang arkitektura ng Kafka ay nakasalalay sa maraming mga independiyenteng makina na tumatakbo bilang isang bus at walang pagtatangka na ginawa upang itago ito. Halimbawa, walang mga bahagi ng API na magbibigay-daan sa iyong mag-link mamimili ΠΈ Producer sa isang transaksyon. Sa JMS, ito ay ibinigay ng object sesyonmula sa kung saan ay nilikha MessageProducers ΠΈ MessageConsumers.

Kung hindi tayo makakaasa sa mga transaksyon, paano tayo makakapagbigay ng mga semantika na mas malapit sa mga ibinigay ng mga tradisyunal na sistema ng pagmemensahe?

Kung may posibilidad na ang offset ng consumer ay maaaring tumaas bago maproseso ang mensahe, tulad ng sa panahon ng pag-crash ng consumer, kung gayon ang consumer ay walang paraan upang malaman kung ang consumer group nito ay nakaligtaan ang mensahe kapag ito ay itinalaga ng isang partition. Kaya ang isang diskarte ay i-rewind ang offset sa nakaraang posisyon. Ang Kafka consumer API ay nagbibigay ng mga sumusunod na pamamaraan para dito:

void seek(TopicPartition partition, long offset);
void seekToBeginning(Collection < TopicPartition > partitions);

pamamaraan Hanapin() maaaring gamitin sa pamamaraan
offsetsForTimes(Map timestampToSearch) upang i-rewind sa isang estado sa ilang partikular na punto sa nakaraan.

Implicitly, ang paggamit ng diskarteng ito ay nangangahulugan na napakalamang na ang ilang mga mensahe na naunang naproseso ay mababasa at mapoproseso muli. Upang maiwasan ito, maaari naming gamitin ang idempotent na pagbabasa, tulad ng inilarawan sa Kabanata 4, upang subaybayan ang mga dating natingnang mensahe at alisin ang mga duplicate.

Bilang kahalili, ang iyong consumer code ay maaaring panatilihing simple, hangga't ang pagkawala ng mensahe o pagdoble ay katanggap-tanggap. Kapag isinasaalang-alang namin ang mga kaso ng paggamit kung saan karaniwang ginagamit ang Kafka, tulad ng paghawak ng mga kaganapan sa log, sukatan, pagsubaybay sa pag-click, atbp., naiintindihan namin na ang pagkawala ng mga indibidwal na mensahe ay malamang na hindi magkaroon ng malaking epekto sa mga nakapalibot na application. Sa ganitong mga kaso, ang mga default na halaga ay ganap na katanggap-tanggap. Sa kabilang banda, kung ang iyong aplikasyon ay kailangang magpadala ng mga pagbabayad, dapat mong maingat na pangalagaan ang bawat indibidwal na mensahe. Ang lahat ay bumaba sa konteksto.

Ipinapakita ng mga personal na obserbasyon na habang tumataas ang intensity ng mga mensahe, bumababa ang halaga ng bawat indibidwal na mensahe. Ang mga malalaking mensahe ay may posibilidad na maging mahalaga kapag tiningnan sa isang pinagsama-samang anyo.

Mataas na Availability

Ang diskarte ni Kafka sa mataas na kakayahang magamit ay ibang-iba sa diskarte ng ActiveMQ. Dinisenyo ang Kafka sa paligid ng mga scale-out cluster kung saan ang lahat ng instance ng broker ay tumatanggap at namamahagi ng mga mensahe nang sabay-sabay.

Ang isang Kafka cluster ay binubuo ng maraming instance ng broker na tumatakbo sa iba't ibang mga server. Ang Kafka ay idinisenyo upang tumakbo sa ordinaryong standalone na hardware, kung saan ang bawat node ay may sariling nakalaang storage. Ang paggamit ng network attached storage (SAN) ay hindi inirerekomenda dahil maraming compute node ang maaaring makipagkumpitensya para sa oras.Π«e mga pagitan ng imbakan at lumikha ng mga salungatan.

Si Kafka ay laging naka-on sistema. Maraming malalaking gumagamit ng Kafka ang hindi kailanman isinara ang kanilang mga kumpol at ang software ay palaging nag-a-update sa isang sunud-sunod na pag-restart. Ito ay nakakamit sa pamamagitan ng paggarantiya ng pagiging tugma sa nakaraang bersyon para sa mga mensahe at pakikipag-ugnayan sa pagitan ng mga broker.

Mga broker na nakakonekta sa isang cluster ng server ZooKeeper, na gumaganap bilang isang configuration data registry at ginagamit upang i-coordinate ang mga tungkulin ng bawat broker. Ang ZooKeeper mismo ay isang distributed system na nagbibigay ng mataas na kakayahang magamit sa pamamagitan ng pagtitiklop ng impormasyon sa pamamagitan ng pagtatatag korum.

Sa base case, ang isang paksa ay ginawa sa isang Kafka cluster na may mga sumusunod na katangian:

  • Ang bilang ng mga partisyon. Tulad ng tinalakay kanina, ang eksaktong halaga na ginamit dito ay nakasalalay sa nais na antas ng parallel na pagbasa.
  • Tinutukoy ng replication factor (factor) kung ilang instance ng broker sa cluster ang dapat maglaman ng mga log para sa partition na ito.

Gamit ang ZooKeepers para sa koordinasyon, sinusubukan ng Kafka na pantay na ipamahagi ang mga bagong partisyon sa mga broker sa cluster. Ginagawa ito ng isang pagkakataon na gumaganap bilang isang Controller.

Sa runtime para sa bawat bahagi ng paksa Controller magtalaga ng mga tungkulin sa isang broker pinuno (pinuno, guro, nagtatanghal) at mga tagasunod (tagasunod, alipin, subordinates). Ang broker, na kumikilos bilang pinuno para sa partisyon na ito, ay responsable para sa pagtanggap ng lahat ng mga mensahe na ipinadala dito ng mga producer at pamamahagi ng mga mensahe sa mga mamimili. Kapag ipinadala ang mga mensahe sa isang partition ng paksa, ginagaya ang mga ito sa lahat ng node ng broker na kumikilos bilang mga tagasunod para sa partisyon na iyon. Ang bawat node na naglalaman ng mga log para sa isang partition ay tinatawag replika. Ang isang broker ay maaaring kumilos bilang isang pinuno para sa ilang mga partisyon at bilang isang tagasunod para sa iba.

Ang isang tagasunod na naglalaman ng lahat ng mga mensahe na hawak ng pinuno ay tinatawag naka-synchronize na replika (isang replica na nasa isang naka-synchronize na estado, in-sync na replica). Kung ang isang broker na kumikilos bilang pinuno para sa isang partisyon ay bumaba, anumang broker na napapanahon o naka-synchronize para sa partisyon na iyon ay maaaring pumalit sa tungkulin ng pinuno. Ito ay isang hindi kapani-paniwalang napapanatiling disenyo.

Bahagi ng configuration ng producer ang parameter mga acks, na tumutukoy kung gaano karaming mga replika ang dapat kilalanin (kilalain) ang pagtanggap ng isang mensahe bago magpatuloy ang pagpapadala ng thread ng application: 0, 1, o lahat. Kung nakatakda sa lahat, pagkatapos kapag natanggap ang isang mensahe, magpapadala ang pinuno ng kumpirmasyon pabalik sa producer sa sandaling makatanggap ito ng mga kumpirmasyon (pagkilala) ng tala mula sa ilang mga pahiwatig (kabilang ang sarili nito) na tinukoy ng setting ng paksa min.insync.replicas (default 1). Kung ang mensahe ay hindi matagumpay na mai-replicate, pagkatapos ay itatapon ng producer ang isang pagbubukod sa aplikasyon (NotEnoughReplicas o NotEnoughReplicasAfterAppend).

Ang isang tipikal na configuration ay lumilikha ng isang paksa na may replication factor na 3 (1 leader, 2 followers bawat partition) at ang parameter min.insync.replicas ay nakatakda sa 2. Sa kasong ito, papayagan ng cluster ang isa sa mga broker na namamahala sa partition ng paksa na bumaba nang hindi naaapektuhan ang mga application ng kliyente.

Ibinabalik tayo nito sa pamilyar nang trade-off sa pagitan ng pagganap at pagiging maaasahan. Nangyayari ang pagtitiklop sa gastos ng karagdagang oras ng paghihintay para sa mga kumpirmasyon (pagkilala) mula sa mga tagasunod. Bagaman, dahil tumatakbo ito nang magkatulad, ang pagtitiklop sa hindi bababa sa tatlong node ay may parehong pagganap sa dalawa (hindi pinapansin ang pagtaas sa paggamit ng bandwidth ng network).

Sa pamamagitan ng paggamit ng scheme ng pagtitiklop na ito, matalinong iniiwasan ni Kafka ang pangangailangang pisikal na isulat ang bawat mensahe sa disk na may operasyon. sync(). Ang bawat mensahe na ipinadala ng producer ay isusulat sa partition log, ngunit tulad ng tinalakay sa Kabanata 2, ang pagsusulat sa isang file ay unang ginagawa sa buffer ng operating system. Kung ang mensaheng ito ay ginagaya sa isa pang halimbawa ng Kafka at nasa memorya nito, ang pagkawala ng pinuno ay hindi nangangahulugan na ang mensahe mismo ay nawala - maaari itong kunin ng isang naka-synchronize na replika.
Pagtanggi na gawin ang operasyon sync() Nangangahulugan na ang Kafka ay makakatanggap ng mga mensahe nang kasing bilis ng pagkakasulat nito sa memorya. Sa kabaligtaran, kung mas matagal mo maiiwasan ang pag-flush ng memory sa disk, mas mabuti. Para sa kadahilanang ito, karaniwan para sa mga broker ng Kafka na maglaan ng 64 GB o higit pa sa memorya. Ang paggamit ng memory na ito ay nangangahulugan na ang isang Kafka instance ay madaling tumakbo sa bilis ng maraming libong beses na mas mabilis kaysa sa isang tradisyunal na broker ng mensahe.

Maaari ding i-configure ang Kafka para ilapat ang operasyon sync() sa mga pakete ng mensahe. Dahil ang lahat sa Kafka ay naka-package, talagang gumagana ito nang maayos para sa maraming mga kaso ng paggamit at isang kapaki-pakinabang na tool para sa mga gumagamit na nangangailangan ng napakalakas na garantiya. Karamihan sa purong pagganap ng Kafka ay nagmumula sa mga mensaheng ipinadala sa broker bilang mga packet at na ang mga mensaheng ito ay binabasa mula sa broker sa sunud-sunod na mga bloke gamit ang walang kopya mga operasyon (mga operasyon kung saan ang gawain ng pagkopya ng data mula sa isang lugar ng memorya patungo sa isa pa ay hindi ginaganap). Ang huli ay isang malaking performance at resource gain at posible lamang sa pamamagitan ng paggamit ng pinagbabatayan na log data structure na tumutukoy sa partition scheme.

Posible ang mas mahusay na pagganap sa isang cluster ng Kafka kaysa sa isang Kafka broker, dahil ang mga partition ng paksa ay maaaring lumaki sa maraming magkakahiwalay na makina.

Mga resulta ng

Sa kabanatang ito, tiningnan namin kung paano muling isinalarawan ng arkitektura ng Kafka ang ugnayan sa pagitan ng mga kliyente at broker upang magbigay ng isang hindi kapani-paniwalang mahusay na pipeline ng pagmemensahe, na may throughput na maraming beses na mas malaki kaysa sa isang karaniwang broker ng mensahe. Napag-usapan namin ang functionality na ginagamit nito para makamit ito at panandaliang tiningnan ang architecture ng mga application na nagbibigay ng functionality na ito. Sa susunod na kabanata, titingnan natin ang mga karaniwang problema na kailangan ng mga application na nakabatay sa pagmemensahe na lutasin at talakayin ang mga diskarte sa pagharap sa kanila. Tatapusin namin ang kabanata sa pamamagitan ng pagbalangkas kung paano pag-usapan ang tungkol sa mga teknolohiya sa pagmemensahe sa pangkalahatan upang masuri mo ang pagiging angkop ng mga ito para sa iyong mga kaso ng paggamit.

Nakaraang isinalin na bahagi: Pag-unawa sa mga broker ng mensahe. Pag-aaral ng mekanika ng pagmemensahe gamit ang ActiveMQ at Kafka. Kabanata 1

Tapos na ang pagsasalin: tele.gg/middle_java

Upang patuloy ...

Ang mga rehistradong user lamang ang maaaring lumahok sa survey. Mag-sign in, pakiusap

Ginagamit ba ang Kafka sa iyong organisasyon?

  • Oo

  • Hindi

  • Dati ginagamit, ngayon hindi na

  • Plano naming gamitin

38 user ang bumoto. 8 na user ang umiwas.

Pinagmulan: www.habr.com

Magdagdag ng komento