Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka

Vazhdimi i përkthimit të një libri të vogël:
Kuptimi i ndërmjetësve të mesazheve
autor: Jakub Korab, botues: O'Reilly Media, Inc., data e botimit: Qershor 2017, ISBN: 9781492049296.

Pjesa e mëparshme e përkthyer: Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 1 Hyrje

KAPITULLI 3

Kafka

Kafka u zhvillua nga LinkedIn për të kapërcyer disa nga kufizimet e ndërmjetësve tradicionalë të mesazheve dhe për të shmangur nevojën për të vendosur ndërmjetësues të shumëfishtë mesazhesh për ndërveprime të ndryshme pikë-për-pikë, gjë që përshkruhet në këtë libër nën "Shkallëzimi dhe largimi" në faqen 28. Rastet e përdorimit LinkedIn është mbështetur kryesisht në gëlltitjen e njëanshme të sasive shumë të mëdha të të dhënave, të tilla si klikimet e faqeve dhe regjistrat e aksesit, ndërkohë që ende lejon që ato të dhëna të përdoren nga sisteme të shumta pa ndikuar në produktivitetin e prodhuesve ose konsumatorëve të tjerë. Në fakt, arsyeja pse Kafka ekziston është për të marrë llojin e arkitekturës së mesazheve që përshkruan Universal Data Pipeline.

Duke pasur parasysh këtë qëllim përfundimtar, natyrshëm u ngritën kërkesa të tjera. Kafka duhet:

  • Jini jashtëzakonisht të shpejtë
  • Siguroni më shumë gjerësi bande kur punoni me mesazhe
  • Mbështetja e modeleve Publisher-Subscriber dhe Point-to-Point
  • Mos u ngadalësoni me shtimin e konsumatorëve. Për shembull, performanca e radhës dhe e temës në ActiveMQ degradon ndërsa numri i konsumatorëve në destinacion rritet.
  • Të jetë i shkallëzuar horizontalisht; nëse një ndërmjetës që vazhdon mesazhet mund ta bëjë këtë vetëm me shpejtësinë maksimale të diskut, atëherë ka kuptim të shkohet përtej një shembulli të vetëm ndërmjetësi për të rritur performancën
  • Kufizoni aksesin në ruajtjen dhe rimarrjen e mesazheve

Për të arritur të gjitha këto, Kafka adoptoi një arkitekturë që ripërcaktoi rolet dhe përgjegjësitë e klientëve dhe ndërmjetësve të mesazheve. Modeli JMS është shumë i orientuar drejt ndërmjetësit, ku ndërmjetësi është përgjegjës për shpërndarjen e mesazheve dhe klientët duhet të shqetësohen vetëm për dërgimin dhe marrjen e mesazheve. Kafka, nga ana tjetër, është i përqendruar te klienti, me klientin që merr shumë nga tiparet e një ndërmjetësi tradicional, si shpërndarja e drejtë e mesazheve përkatëse për konsumatorët, në këmbim të një ndërmjetësi jashtëzakonisht të shpejtë dhe të shkallëzuar. Për njerëzit që kanë punuar me sistemet tradicionale të mesazheve, puna me Kafkën kërkon një ndryshim rrënjësor të mendjes.
Ky drejtim inxhinierik ka çuar në krijimin e një infrastrukture mesazhesh të aftë për të rritur xhiron me shumë shkallë në krahasim me një ndërmjetës konvencional. Siç do të shohim, kjo qasje vjen me kompensime, që do të thotë se Kafka nuk është i përshtatshëm për lloje të caktuara ngarkesash pune dhe softuer të instaluar.

Modeli i unifikuar i destinacionit

Për të përmbushur kërkesat e përshkruara më sipër, Kafka ka kombinuar publikim-pajtim dhe mesazhe pikë-për-pikë nën një lloj destinacioni - temë. Kjo është konfuze për njerëzit që kanë punuar me sistemet e mesazheve, ku fjala "temë" i referohet një mekanizmi transmetimi nga i cili (nga tema) leximi nuk është i qëndrueshëm. Temat e Kafkës duhet të konsiderohen si një lloj destinacioni hibrid, siç përcaktohet në hyrje të këtij libri.

Për pjesën e mbetur të këtij kapitulli, përveç nëse shprehimisht shprehimisht ndryshe, termi "temë" do t'i referohet një teme të Kafkës.

Për të kuptuar plotësisht se si sillen temat dhe çfarë garancish ofrojnë, fillimisht duhet të shohim se si ato zbatohen në Kafka.
Çdo temë në Kafka ka regjistrin e vet.
Prodhuesit që i dërgojnë mesazhe Kafkës i shkruajnë këtij regjistri dhe konsumatorët lexojnë nga regjistri duke përdorur tregues që ecin vazhdimisht përpara. Periodikisht, Kafka fshin pjesët më të vjetra të regjistrit, pavarësisht nëse mesazhet në ato pjesë janë lexuar apo jo. Një pjesë qendrore e dizajnit të Kafkës është se ndërmjetësi nuk i intereson nëse mesazhet lexohen apo jo - kjo është përgjegjësi e klientit.

Termat "log" dhe "tregues" nuk shfaqen në Dokumentacioni i Kafkës. Këto terma të njohura përdoren këtu për të ndihmuar të kuptuarit.

Ky model është krejtësisht i ndryshëm nga ActiveMQ, ku mesazhet nga të gjitha radhët ruhen në të njëjtin regjistër dhe ndërmjetësi i shënon mesazhet si të fshira pasi të jenë lexuar.
Le të gërmojmë pak më thellë dhe të shohim më në detaje regjistrin e temës.
Regjistri Kafka përbëhet nga disa ndarje (Figura 3 1-). Kafka garanton renditje strikte në çdo ndarje. Kjo do të thotë që mesazhet e shkruara në ndarje në një rend të caktuar do të lexohen në të njëjtin rend. Çdo ndarje zbatohet si një skedar log që përmban nëngrup (nëngrupi) i të gjitha mesazheve të dërguara në temë nga prodhuesit e tij. Tema e krijuar përmban, si parazgjedhje, një ndarje. Ideja e ndarjeve është ideja qendrore e Kafkës për shkallëzim horizontal.

Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka
Figura 3-1. Ndarëse Kafka

Kur një producent i dërgon një mesazh një teme të Kafkës, ai vendos se cilës ndarje t'ia dërgojë mesazhin. Ne do ta shikojmë këtë më në detaje më vonë.

Leximi i mesazheve

Klienti që dëshiron të lexojë mesazhet menaxhon një tregues të quajtur të quajtur grupi i konsumatorëve, e cila tregon për kompensuar mesazhet në ndarje. Një kompensim është një pozicion në rritje që fillon me 0 në fillim të një ndarjeje. Ky grup konsumatori, i referuar në API nëpërmjet grupit_id të përcaktuar nga përdoruesi, korrespondon me një konsumator ose sistem logjik.

Shumica e sistemeve të mesazheve lexojnë të dhëna nga destinacioni duke përdorur shembuj dhe fije të shumta për të përpunuar mesazhet paralelisht. Kështu, zakonisht do të ketë shumë raste të konsumatorëve që ndajnë të njëjtin grup konsumatorësh.

Problemi i leximit mund të përfaqësohet si më poshtë:

  • Tema ka ndarje të shumta
  • Grupe të shumta të konsumatorëve mund të përdorin një temë në të njëjtën kohë
  • Një grup konsumatorësh mund të ketë shumë raste të veçanta

Ky është një problem jo i parëndësishëm shumë-për-shumë. Për të kuptuar se si i trajton Kafka marrëdhëniet midis grupeve të konsumatorëve, shembujve të konsumatorëve dhe ndarjeve, le të shohim një sërë skenarësh leximi në mënyrë progresive më komplekse.

Konsumatorët dhe grupet e konsumatorëve

Le të marrim si pikënisje një temë me një ndarje (Figura 3 2-).

Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka
Figura 3-2. Konsumatori lexon nga ndarja

Kur një shembull konsumatori lidhet me grupin_id të tij me këtë temë, atij i caktohet një ndarje leximi dhe një kompensim në atë ndarje. Pozicioni i këtij kompensimi është konfiguruar në klient si një tregues për pozicionin më të fundit (mesazhi më i ri) ose pozicionin më të hershëm (mesazhi më i vjetër). Konsumatori kërkon (sondazhe) mesazhe nga tema, gjë që bën që ato të lexohen në mënyrë sekuenciale nga regjistri.
Pozicioni i kompensimit i është dhënë rregullisht Kafkës dhe ruhet si mesazhe në një temë të brendshme Kompensimet e _konsumatorit. Mesazhet e lexuara ende nuk fshihen, ndryshe nga një ndërmjetës i zakonshëm, dhe klienti mund ta kthejë kompensimin për të ripërpunuar mesazhet e shikuara tashmë.

Kur një konsumator i dytë logjik lidhet duke përdorur një grup_id të ndryshëm, ai menaxhon një tregues të dytë që është i pavarur nga i pari (Figura 3 3-). Kështu, një temë Kafka vepron si një radhë ku ka një konsumator dhe si një temë normale publikim-subscribe (pub-sub) në të cilën abonohen shumë konsumatorë, me përfitimin e shtuar që të gjitha mesazhet ruhen dhe mund të përpunohen disa herë.

Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka
Figura 3-3. Dy konsumatorë në grupe të ndryshme të konsumatorëve lexojnë nga e njëjta ndarje

Konsumatorët në një grup konsumatorësh

Kur një shembull i konsumatorit lexon të dhëna nga një ndarje, ai ka kontroll të plotë të treguesit dhe përpunon mesazhet siç përshkruhet në seksionin e mëparshëm.
Nëse disa raste të konsumatorëve janë lidhur me të njëjtin grup_id me një temë me një ndarje, atëherë shembullit që u lidh i fundit do t'i jepet kontrolli mbi treguesin dhe që nga ai moment ai do të marrë të gjitha mesazhet (Figura 3 4-).

Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka
Figura 3-4. Dy konsumatorë në të njëjtin grup konsumatorësh lexojnë nga e njëjta ndarje

Kjo mënyrë përpunimi, në të cilën numri i rasteve të konsumatorit tejkalon numrin e ndarjeve, mund të konsiderohet si një lloj konsumatori ekskluziv. Kjo mund të jetë e dobishme nëse keni nevojë për grupim "aktiv-pasiv" (ose "hot-ngrohtë") të rasteve tuaja të konsumatorit, megjithëse drejtimi i disa konsumatorëve paralelisht ("aktiv-aktiv" ose "hot-hot") është shumë më tipik sesa konsumatorët.Në gatishmëri.

Kjo sjellje e shpërndarjes së mesazheve e përshkruar më sipër mund të jetë befasuese në krahasim me mënyrën se si sillet një radhë normale JMS. Në këtë model, mesazhet e dërguara në radhë do të shpërndahen në mënyrë të barabartë midis dy konsumatorëve.

Më shpesh, kur krijojmë raste të shumta të konsumatorëve, ne e bëjmë këtë ose për të përpunuar mesazhet paralelisht, ose për të rritur shpejtësinë e leximit, ose për të rritur stabilitetin e procesit të leximit. Meqenëse vetëm një shembull i konsumatorit mund të lexojë të dhëna nga një ndarje në të njëjtën kohë, si arrihet kjo në Kafka?

Një mënyrë për ta bërë këtë është të përdorni një shembull të vetëm konsumator për të lexuar të gjitha mesazhet dhe për t'i kaluar ato në grupin e temave. Ndërsa kjo qasje rrit xhiron e përpunimit, ajo rrit kompleksitetin e logjikës së konsumatorit dhe nuk bën asgjë për të rritur qëndrueshmërinë e sistemit të leximit. Nëse një kopje e konsumatorit shkon poshtë për shkak të një ndërprerjeje të energjisë ose ngjarje të ngjashme, atëherë zbritja ndalon.

Mënyra kanonike për të zgjidhur këtë problem te Kafka është përdorimi i bОmë shumë ndarje.

Ndarje

Ndarjet janë mekanizmi kryesor për paralelizimin e leximit dhe shkallëzimin e një teme përtej gjerësisë së brezit të një shembulli të vetëm ndërmjetësi. Për ta kuptuar më mirë këtë, le të shqyrtojmë një situatë ku ekziston një temë me dy ndarje dhe një konsumator pajtohet në këtë temë (Figura 3 5-).

Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka
Figura 3-5. Një konsumator lexon nga ndarje të shumta

Në këtë skenar, konsumatorit i jepet kontrolli mbi treguesit që korrespondojnë me grupin_id të tij në të dy ndarjet dhe fillon të lexojë mesazhe nga të dy ndarjet.
Kur kësaj teme i shtohet një konsumator shtesë për të njëjtin grup_id, Kafka rialokon njërën nga ndarjet nga konsumatori i parë te konsumatori i dytë. Pas kësaj, çdo shembull i konsumatorit do të lexojë nga një ndarje e temës (Figura 3 6-).

Për të siguruar që mesazhet të përpunohen paralelisht në 20 tema, ju nevojiten të paktën 20 ndarje. Nëse ka më pak ndarje, do të mbeteni me konsumatorë që nuk kanë asgjë për të punuar, siç përshkruhet më parë në diskutimin e konsumatorëve ekskluzivë.

Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 3. Kafka
Figura 3-6. Dy konsumatorë në të njëjtin grup konsumatorësh lexojnë nga ndarje të ndryshme

Kjo skemë redukton shumë kompleksitetin e ndërmjetësit Kafka në krahasim me shpërndarjen e mesazheve që kërkohet për të mbajtur radhën JMS. Këtu nuk keni nevojë të shqetësoheni për pikat e mëposhtme:

  • Cili konsumator duhet të marrë mesazhin e radhës, bazuar në shpërndarjen e rrumbullakët, kapacitetin aktual të buferave të para-marrjes ose mesazhet e mëparshme (si për grupet e mesazheve JMS).
  • Cilat mesazhe u dërgohen kujt konsumatorëve dhe nëse ato duhet të ridërgohen në rast të dështimit.

Gjithçka që duhet të bëjë ndërmjetësi Kafka është t'i kalojë mesazhet konsumatorit në mënyrë sekuenciale kur ky i fundit i kërkon ato.

Sidoqoftë, kërkesat për paralelizimin e korrigjimit dhe ridërgimin e mesazheve të dështuara nuk zhduken - përgjegjësia për to thjesht kalon nga ndërmjetësi te klienti. Kjo do të thotë që ato duhet të merren parasysh në kodin tuaj.

Dërgimi i mesazheve

Është përgjegjësi e prodhuesit të atij mesazhi të vendosë se cilës ndarje të dërgojë një mesazh. Për të kuptuar mekanizmin me të cilin bëhet kjo, së pari duhet të shqyrtojmë se çfarë saktësisht po dërgojmë.

Ndërsa në JMS ne përdorim një strukturë mesazhi me metadata (titujt dhe vetitë) dhe një trup që përmban ngarkesën (payload), në Kafka mesazhi është çift ​​"çelës-vlerë". Ngarkesa e mesazhit dërgohet si vlerë. Çelësi, nga ana tjetër, përdoret kryesisht për ndarje dhe duhet të përmbajë çelësi specifik i logjikës së biznesitpër të vendosur mesazhe të lidhura në të njëjtën ndarje.

Në kapitullin 2, ne diskutuam skenarin e basteve në internet ku ngjarjet e lidhura duhet të përpunohen sipas rendit nga një konsumator i vetëm:

  1. Llogaria e përdoruesit është konfiguruar.
  2. Paratë kreditohen në llogari.
  3. Bëhet një bast që tërheq para nga llogaria.

Nëse çdo ngjarje është një mesazh i postuar në një temë, atëherë çelësi natyror do të ishte ID-ja e llogarisë.
Kur një mesazh dërgohet duke përdorur API-në e Prodhuesit të Kafkës, ai kalon në një funksion ndarjeje i cili, duke pasur parasysh mesazhin dhe gjendjen aktuale të grupit Kafka, kthen ID-në e ndarjes në të cilën duhet të dërgohet mesazhi. Ky funksion zbatohet në Java përmes ndërfaqes Partitioner.

Kjo ndërfaqe duket si kjo:

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

Zbatimi i Partitioner përdor algoritmin e paracaktuar të hashimit për qëllime të përgjithshme mbi çelësin për të përcaktuar ndarjen, ose raunde nëse nuk specifikohet asnjë çelës. Kjo vlerë e paracaktuar funksionon mirë në shumicën e rasteve. Megjithatë, në të ardhmen do të dëshironi të shkruani tuajën.

Shkrimi i strategjisë tuaj të ndarjes

Le të shohim një shembull ku dëshironi të dërgoni meta të dhëna së bashku me ngarkesën e mesazhit. Ngarkesa në shembullin tonë është një udhëzim për të bërë një depozitë në llogarinë e lojës. Një udhëzim është diçka që ne do të dëshironim të garantohej se nuk do të modifikohej gjatë transmetimit dhe duam të jemi të sigurt se vetëm një sistem i besuar në rrjedhën e sipërme mund ta inicojë atë udhëzim. Në këtë rast, sistemet dërguese dhe marrëse bien dakord për përdorimin e një nënshkrimi për të vërtetuar mesazhin.
Në JMS normale, ne thjesht përcaktojmë një veçori "nënshkrimi i mesazhit" dhe e shtojmë atë në mesazh. Megjithatë, Kafka nuk na ofron një mekanizëm për kalimin e meta të dhënave, vetëm një çelës dhe një vlerë.

Meqenëse vlera është një ngarkesë e transfertave bankare, integritetin e së cilës duam ta ruajmë, nuk na mbetet gjë tjetër veçse të përcaktojmë strukturën e të dhënave për t'u përdorur në çelës. Duke supozuar se na duhet një ID llogarie për ndarje, pasi të gjitha mesazhet që lidhen me një llogari duhet të përpunohen në rregull, ne do të dalim me strukturën e mëposhtme JSON:

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

Për shkak se vlera e nënshkrimit do të ndryshojë në varësi të ngarkesës, strategjia e paracaktuar e hashimit të ndërfaqes së Partitioner nuk do të grupojë në mënyrë të besueshme mesazhet e lidhura. Prandaj, do të na duhet të shkruajmë strategjinë tonë që do të analizojë këtë çelës dhe do të ndajë vlerën e llogarisë ID.

Kafka përfshin kontrolle për të zbuluar korrupsionin e mesazheve në dyqan dhe ka një grup të plotë karakteristikash sigurie. Megjithatë, ndonjëherë shfaqen kërkesa specifike për industrinë, si ajo e mësipërme.

Strategjia e ndarjes së përdoruesit duhet të sigurojë që të gjitha mesazhet e lidhura të përfundojnë në të njëjtën ndarje. Ndërsa kjo duket e thjeshtë, kërkesa mund të komplikohet nga rëndësia e porositjes së mesazheve të lidhura dhe sa fiks është numri i ndarjeve në një temë.

Numri i ndarjeve në një temë mund të ndryshojë me kalimin e kohës, pasi ato mund të shtohen nëse trafiku shkon përtej pritjeve fillestare. Kështu, çelësat e mesazheve mund të shoqërohen me ndarjen në të cilën u dërguan fillimisht, duke nënkuptuar një pjesë të gjendjes që do të ndahet midis instancave të prodhuesve.

Një faktor tjetër që duhet marrë parasysh është shpërndarja e barabartë e mesazheve nëpër ndarje. Në mënyrë tipike, çelësat nuk shpërndahen në mënyrë të barabartë nëpër mesazhe dhe funksionet hash nuk garantojnë një shpërndarje të drejtë të mesazheve për një grup të vogël çelësash.
Është e rëndësishme të theksohet se sido që të zgjidhni të ndani mesazhet, vetë ndarësi mund të duhet të ripërdoret.

Merrni parasysh kërkesën për të përsëritur të dhënat midis grupimeve të Kafkës në vende të ndryshme gjeografike. Për këtë qëllim, Kafka vjen me një mjet të linjës komanduese të quajtur MirrorMaker, i cili përdoret për të lexuar mesazhe nga një grup dhe për t'i transferuar ato në një tjetër.

MirrorMaker duhet të kuptojë çelësat e temës së përsëritur në mënyrë që të ruajë rendin relativ midis mesazheve kur replikohet midis grupimeve, pasi numri i ndarjeve për atë temë mund të mos jetë i njëjtë në dy grupime.

Strategjitë e personalizimit të ndarjes janë relativisht të rralla, pasi hashimi i paracaktuar ose rrumbullakët funksionojnë mirë në shumicën e skenarëve. Sidoqoftë, nëse keni nevojë për garanci të forta porositjeje ose keni nevojë të nxjerrni meta të dhëna nga ngarkesat, atëherë ndarja është diçka që duhet ta shikoni më nga afër.

Përfitimet e shkallëzueshmërisë dhe performancës së Kafkës vijnë nga zhvendosja e disa prej përgjegjësive të ndërmjetësit tradicional te klienti. Në këtë rast, merret një vendim për të shpërndarë mesazhe potencialisht të lidhura midis disa konsumatorëve që punojnë paralelisht.

Agjentët JMS gjithashtu duhet të merren me kërkesa të tilla. Është interesante se mekanizmi për dërgimin e mesazheve të lidhura me të njëjtin konsumator, i zbatuar përmes Grupeve të Mesazheve JMS (një ndryshim në strategjinë e balancimit të ngarkesës ngjitëse (SLB)), gjithashtu kërkon që dërguesi të shënojë mesazhet si të lidhura. Në rastin e JMS, ndërmjetësi është përgjegjës për dërgimin e këtij grupi mesazhesh të lidhura te një konsumator nga shumë, dhe transferimin e pronësisë së grupit nëse konsumatori bie.

Marrëveshjet e Prodhuesit

Ndarja nuk është e vetmja gjë që duhet marrë parasysh kur dërgoni mesazhe. Le të hedhim një vështrim në metodat send() të klasës Producer në Java API:

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

Duhet të theksohet menjëherë se të dyja metodat kthejnë Future, gjë që tregon se operacioni i dërgimit nuk kryhet menjëherë. Rezultati është se një mesazh (ProducerRecord) shkruhet në bufferin e dërgimit për çdo ndarje aktive dhe dërgohet te ndërmjetësi si një fill në sfond në bibliotekën e klientit Kafka. Ndërsa kjo i bën gjërat tepër të shpejta, kjo do të thotë që një aplikacion pa përvojë mund të humbasë mesazhe nëse procesi i tij ndalet.

Si gjithmonë, ekziston një mënyrë për ta bërë operacionin e dërgimit më të besueshëm në kurriz të performancës. Madhësia e këtij buferi mund të vendoset në 0, dhe filli i aplikacionit dërgues do të detyrohet të presë derisa të përfundojë transferimi i mesazhit te ndërmjetësi, si më poshtë:

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

Më shumë rreth leximit të mesazheve

Leximi i mesazheve ka kompleksitete shtesë për të cilat duhen spekuluar. Ndryshe nga JMS API, i cili mund të ekzekutojë një dëgjues mesazhi në përgjigje të një mesazhi, Konsumator Kafka vetëm sondazhe. Le të hedhim një vështrim më të afërt në metodën sondazh ()përdoret për këtë qëllim:

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

Vlera e kthyer e metodës është një strukturë kontejneri që përmban shumë objekte të dhënat e konsumatorit nga potencialisht disa ndarje. të dhënat e konsumatorit është në vetvete një objekt mbajtës për një çift çelës-vlerë me meta të dhëna të lidhura, siç është ndarja nga e cila rrjedh.

Siç u diskutua në Kapitullin 2, duhet të kemi parasysh se çfarë ndodh me mesazhet pasi ato të jenë përpunuar me sukses ose pa sukses, për shembull, nëse klienti nuk është në gjendje të përpunojë mesazhin ose nëse ai anulon. Në JMS, kjo u trajtua përmes një modaliteti njohjeje. Ndërmjetësi ose do të fshijë mesazhin e përpunuar me sukses, ose do të ri-dorëzojë mesazhin e papërpunuar ose të rremë (duke supozuar se janë përdorur transaksione).
Kafka punon shumë ndryshe. Mesazhet nuk fshihen në ndërmjetës pas korrigjimit, dhe ajo që ndodh në rast dështimi është përgjegjësi e vetë kodit të korrigjimit.

Siç kemi thënë, grupi i konsumatorëve shoqërohet me kompensimin në regjistër. Pozicioni i regjistrit i lidhur me këtë kompensim korrespondon me mesazhin tjetër që do të lëshohet si përgjigje sondazh (). Pika kohore kur kjo kompensim rritet është vendimtare për leximin.

Duke iu rikthyer modelit të leximit të diskutuar më parë, përpunimi i mesazhit përbëhet nga tre faza:

  1. Merr një mesazh për lexim.
  2. Përpunoni mesazhin.
  3. Konfirmo mesazhin.

Konsumatori Kafka vjen me një opsion konfigurimi enable.auto.commit. Ky është një cilësim i paracaktuar i përdorur shpesh, siç është e zakonshme me cilësimet që përmbajnë fjalën "auto".

Përpara Kafka 0.10, një klient që përdor këtë opsion do të dërgonte kompensimin e mesazhit të fundit të lexuar në thirrjen tjetër sondazh () pas përpunimit. Kjo do të thoshte se çdo mesazh që ishte marrë tashmë mund të ripërpunohej nëse klienti i kishte përpunuar tashmë, por ishte shkatërruar papritur përpara se të telefononte sondazh (). Për shkak se ndërmjetësi nuk mban asnjë gjendje se sa herë është lexuar një mesazh, konsumatori tjetër që e merr atë mesazh nuk do të dijë se ka ndodhur ndonjë gjë e keqe. Kjo sjellje ishte pseudo-transaksionale. Kompensimi kryhej vetëm nëse mesazhi përpunohej me sukses, por nëse klienti ndërpritet, ndërmjetësi do t'i dërgonte përsëri të njëjtin mesazh një klienti tjetër. Kjo sjellje ishte në përputhje me garancinë e dërgimit të mesazhit "te pakten nje here".

Në Kafka 0.10, kodi i klientit është ndryshuar në mënyrë që kryerja të aktivizohet periodikisht nga biblioteka e klientit, siç është konfiguruar auto.commit.interval.ms. Kjo sjellje është diku midis modaliteteve JMS AUTO_ACKNOWLEDGE dhe DUPS_OK_ACKNOWLEDGE. Kur përdorni autocommit, mesazhet mund të kryhen pavarësisht nëse ato janë përpunuar në të vërtetë - kjo mund të ndodhë në rastin e një konsumatori të ngadaltë. Nëse një konsumator ndërpritet, mesazhet do të merren nga konsumatori tjetër, duke filluar nga pozicioni i kryer, gjë që mund të rezultojë në humbjen e mesazhit. Në këtë rast, Kafka nuk i humbi mesazhet, kodi i leximit thjesht nuk i përpunoi ato.

Kjo mënyrë ka të njëjtin premtim si në versionin 0.9: mesazhet mund të përpunohen, por nëse dështon, kompensimi mund të mos kryhet, duke shkaktuar potencialisht dyfishimin e dërgimit. Sa më shumë mesazhe të merrni gjatë ekzekutimit sondazh (), aq më shumë ky problem.

Siç u diskutua në "Leximi i mesazheve nga një radhë" në faqen 21, nuk ekziston diçka e tillë si dërgimi një herë i një mesazhi në një sistem mesazhesh kur merren parasysh mënyrat e dështimit.

Në Kafka, ka dy mënyra për të kryer (kryer) një kompensim (offset): automatikisht dhe manualisht. Në të dyja rastet, mesazhet mund të përpunohen disa herë nëse mesazhi është përpunuar por dështoi përpara kryerjes. Ju gjithashtu mund të zgjidhni të mos e përpunoni fare mesazhin nëse kryerja ka ndodhur në sfond dhe kodi juaj është përfunduar përpara se të mund të përpunohej (ndoshta në Kafka 0.9 dhe më herët).

Ju mund të kontrolloni procesin e kryerjes së kompensimit manual në API-në e konsumatorit Kafka duke vendosur parametrin enable.auto.commit për false dhe thirrje në mënyrë eksplicite një nga metodat e mëposhtme:

void commitSync();
void commitAsync();

Nëse dëshironi të përpunoni mesazhin "të paktën një herë", duhet të kryeni kompensimin manualisht me commitSync()duke e ekzekutuar këtë komandë menjëherë pas përpunimit të mesazheve.

Këto metoda nuk lejojnë që mesazhet të pranohen përpara se të përpunohen, por ato nuk bëjnë asgjë për të eliminuar vonesat e mundshme të përpunimit duke dhënë pamjen e transaksionit. Nuk ka transaksione në Kafka. Klienti nuk ka aftësinë të bëjë sa vijon:

  • Rikthe automatikisht një mesazh të falsifikuar. Vetë konsumatorët duhet të trajtojnë përjashtimet që lindin nga ngarkesat problematike dhe ndërprerjet në fund, pasi ata nuk mund të mbështeten te ndërmjetësi për të ridërguar mesazhet.
  • Dërgoni mesazhe në tema të shumta në një operacion atomik. Siç do të shohim së shpejti, kontrolli mbi tema dhe ndarje të ndryshme mund të qëndrojë në makina të ndryshme në grupin Kafka që nuk koordinojnë transaksionet kur dërgohen. Në kohën e këtij shkrimi, është bërë disa punë për ta bërë të mundur këtë me KIP-98.
  • Lidhni leximin e një mesazhi nga një temë me dërgimin e një mesazhi tjetër në një temë tjetër. Përsëri, arkitektura e Kafkës varet nga shumë makina të pavarura që funksionojnë si një autobus dhe nuk bëhet asnjë përpjekje për ta fshehur këtë. Për shembull, nuk ka komponentë API që do t'ju lejojnë të lidhni konsumatori и prodhues në një transaksion. Në JMS, kjo sigurohet nga objekti seancënga të cilat krijohen Prodhuesit e mesazheve и Mesazh Konsumatorët.

Nëse nuk mund të mbështetemi te transaksionet, si mund të ofrojmë semantikë më afër atyre të ofruara nga sistemet tradicionale të mesazheve?

Nëse ekziston mundësia që kompensimi i konsumatorit të rritet përpara se mesazhi të përpunohet, si për shembull gjatë një përplasjeje konsumatori, atëherë konsumatori nuk ka asnjë mënyrë për të ditur nëse grupi i tij i konsumatorëve e ka humbur mesazhin kur i është caktuar një ndarje. Pra, një strategji është të ktheni kompensimin në pozicionin e mëparshëm. API-ja e konsumatorit Kafka ofron metodat e mëposhtme për këtë:

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

Метод kërkoj () mund të përdoret me metodë
offsetsForTimes (Harta vulat kohoreToSearch) për t'u kthyer në një gjendje në një pikë specifike në të kaluarën.

Në mënyrë implicite, përdorimi i kësaj qasjeje do të thotë se ka shumë të ngjarë që disa mesazhe të përpunuara më parë të lexohen dhe përpunohen përsëri. Për të shmangur këtë, ne mund të përdorim leximin idempotent, siç përshkruhet në Kapitullin 4, për të mbajtur gjurmët e mesazheve të shikuara më parë dhe për të eliminuar dublikatat.

Përndryshe, kodi juaj i konsumatorit mund të mbahet i thjeshtë, për sa kohë që humbja ose dyfishimi i mesazhit është i pranueshëm. Kur marrim parasysh rastet e përdorimit për të cilat përdoret zakonisht Kafka, të tilla si trajtimi i ngjarjeve të regjistrit, metrikat, gjurmimi i klikimeve, etj., kuptojmë se humbja e mesazheve individuale nuk ka gjasa të ketë një ndikim të rëndësishëm në aplikacionet përreth. Në raste të tilla, vlerat e paracaktuara janë krejtësisht të pranueshme. Nga ana tjetër, nëse aplikacioni juaj duhet të dërgojë pagesa, duhet të kujdeseni me kujdes për çdo mesazh individual. Gjithçka varet nga konteksti.

Vëzhgimet personale tregojnë se me rritjen e intensitetit të mesazheve, vlera e çdo mesazhi individual zvogëlohet. Mesazhet e mëdha priren të jenë të vlefshme kur shikohen në formë të përmbledhur.

Disponueshmëri e lartë

Qasja e Kafkës ndaj disponueshmërisë së lartë është shumë e ndryshme nga qasja e ActiveMQ. Kafka është projektuar rreth grupimeve të shkallëzuara ku të gjitha rastet e ndërmjetësit marrin dhe shpërndajnë mesazhe në të njëjtën kohë.

Një grup Kafka përbëhet nga instanca të shumta ndërmjetësi që funksionojnë në serverë të ndryshëm. Kafka u krijua për të funksionuar në pajisje të zakonshme të pavarura, ku çdo nyje ka ruajtjen e saj të dedikuar. Përdorimi i ruajtjes së bashkangjitur në rrjet (SAN) nuk rekomandohet sepse shumë nyje llogaritëse mund të konkurrojnë për kohën.Ыe intervalet e ruajtjes dhe krijojnë konflikte.

Kafka është gjithmonë ndezur sistemi. Shumë përdorues të mëdhenj të Kafka-s nuk i mbyllin asnjëherë grupet e tyre dhe softueri përditësohet gjithmonë me një rinisje vijuese. Kjo arrihet duke garantuar përputhshmëri me versionin e mëparshëm për mesazhet dhe ndërveprimet ndërmjet ndërmjetësve.

Brokerat e lidhur me një grup serverësh Zookeeper, i cili vepron si një regjistër i të dhënave të konfigurimit dhe përdoret për të koordinuar rolet e çdo ndërmjetësi. Vetë ZooKeeper është një sistem i shpërndarë që ofron disponueshmëri të lartë përmes riprodhimit të informacionit duke vendosur kuorum.

Në rastin bazë, një temë krijohet në një grup Kafka me vetitë e mëposhtme:

  • Numri i ndarjeve. Siç u diskutua më herët, vlera e saktë e përdorur këtu varet nga niveli i dëshiruar i leximit paralel.
  • Faktori i replikimit (faktori) përcakton se sa instanca ndërmjetësi në grup duhet të përmbajnë regjistrat për këtë ndarje.

Duke përdorur ZooKeepers për koordinim, Kafka përpiqet të shpërndajë në mënyrë të drejtë ndarjet e reja midis ndërmjetësve në grup. Kjo bëhet nga një shembull i vetëm që vepron si kontrollues.

Në kohën e ekzekutimit për çdo ndarje teme Kontrollues caktoni role për një ndërmjetës udhëheqës (udhëheqës, mjeshtër, prezantues) dhe ndjekësit (pasuesit, skllevër, vartës). Ndërmjetësi, duke vepruar si lider për këtë ndarje, është përgjegjës për marrjen e të gjitha mesazheve që i dërgohen nga prodhuesit dhe shpërndarjen e mesazheve tek konsumatorët. Kur mesazhet dërgohen në një ndarje teme, ato përsëriten në të gjitha nyjet e ndërmjetësit që veprojnë si ndjekës për atë ndarje. Çdo nyje që përmban regjistrat për një ndarje quhet kopje. Një ndërmjetës mund të veprojë si udhëheqës për disa ndarje dhe si ndjekës për të tjerët.

Një ndjekës që përmban të gjitha mesazhet e mbajtura nga udhëheqësi quhet kopje e sinkronizuar (një kopje që është në gjendje të sinkronizuar, kopje e sinkronizuar). Nëse një ndërmjetës që vepron si udhëheqës për një ndarje shkon poshtë, çdo ndërmjetës që është i përditësuar ose i sinkronizuar për atë ndarje mund të marrë rolin e udhëheqësit. Është një dizajn tepër i qëndrueshëm.

Një pjesë e konfigurimit të prodhuesit është parametri qafat, i cili përcakton se sa kopje duhet të konfirmojnë (pranojnë) marrjen e një mesazhi përpara se filli i aplikacionit të vazhdojë të dërgojë: 0, 1 ose të gjitha. Nëse vendoset në të gjithë, atëherë kur të merret një mesazh, drejtuesi do t'i dërgojë një konfirmim prodhuesit sapo të marrë konfirmimet (mirënjohjet) të regjistrimit nga disa sinjale (përfshirë veten) të përcaktuara nga konfigurimi i temës min.insync.kopje (parazgjedhja 1). Nëse mesazhi nuk mund të përsëritet me sukses, atëherë prodhuesi do të hedhë një përjashtim të aplikacionit (NotEnoughReplicas ose NotEnoughReplicasAfterAppend).

Një konfigurim tipik krijon një temë me një faktor replikimi prej 3 (1 lider, 2 ndjekës për ndarje) dhe parametri min.insync.kopje është vendosur në 2. Në këtë rast, grupi do të lejojë që një nga ndërmjetësit që menaxhon ndarjen e temës të zbresë pa ndikuar në aplikacionet e klientit.

Kjo na kthen te shkëmbimi tashmë i njohur midis performancës dhe besueshmërisë. Replikimi ndodh në kurriz të kohës shtesë të pritjes për konfirmimet (mirënjohjet) nga ndjekësit. Megjithëse, për shkak se funksionon paralelisht, përsëritja në të paktën tre nyje ka të njëjtën performancë si dy (duke injoruar rritjen e përdorimit të gjerësisë së brezit të rrjetit).

Duke përdorur këtë skemë riprodhimi, Kafka shmang me zgjuarsi nevojën për të shkruar fizikisht çdo mesazh në disk me operacionin sinkronizimi (). Çdo mesazh i dërguar nga prodhuesi do të shkruhet në regjistrin e ndarjes, por siç u diskutua në Kapitullin 2, shkrimi në një skedar fillimisht bëhet në buferin e sistemit operativ. Nëse ky mesazh përsëritet në një shembull tjetër të Kafkës dhe është në kujtesën e tij, humbja e udhëheqësit nuk do të thotë se vetë mesazhi ka humbur - ai mund të merret përsipër nga një kopje e sinkronizuar.
Refuzimi për të kryer operacionin sinkronizimi () do të thotë që Kafka mund të marrë mesazhe aq shpejt sa mund t'i shkruajë ato në kujtesë. Anasjelltas, sa më gjatë të shmangni shpëlarjen e memories në disk, aq më mirë. Për këtë arsye, nuk është e pazakontë që ndërmjetësve të Kafkës t'u ndahen 64 GB ose më shumë memorie. Ky përdorim i kujtesës do të thotë që një shembull i vetëm i Kafkës mund të funksionojë lehtësisht me shpejtësi mijëra herë më të shpejta se një ndërmjetës tradicional i mesazheve.

Kafka gjithashtu mund të konfigurohet për të aplikuar operacionin sinkronizimi () për të mesazhuar paketat. Meqenëse gjithçka në Kafka është e orientuar nga paketa, në fakt funksionon mjaft mirë për shumë raste përdorimi dhe është një mjet i dobishëm për përdoruesit që kërkojnë garanci shumë të forta. Pjesa më e madhe e performancës së pastër të Kafkës vjen nga mesazhet që i dërgohen ndërmjetësit si pako dhe që këto mesazhe lexohen nga ndërmjetësi në blloqe të njëpasnjëshme duke përdorur kopje zero operacione (operacione gjatë të cilave nuk kryhet detyra e kopjimit të të dhënave nga një zonë memorie në tjetrën). Ky i fundit është një përfitim i madh i performancës dhe burimeve dhe është i mundur vetëm nëpërmjet përdorimit të një strukture të të dhënave bazë të regjistrit që përcakton skemën e ndarjes.

Performanca shumë më e mirë është e mundur në një grup Kafka sesa me një ndërmjetës të vetëm Kafka, sepse ndarjet e temave mund të shpërndahen në shumë makina të veçanta.

Rezultatet e

Në këtë kapitull, ne shikuam se si arkitektura Kafka riimagjinon marrëdhënien midis klientëve dhe ndërmjetësve për të siguruar një linjë mesazhesh tepër të fuqishme, me xhiro shumë herë më të madhe se ajo e një ndërmjetësi mesazhesh konvencionale. Ne kemi diskutuar funksionalitetin që përdor për ta arritur këtë dhe kemi parë shkurtimisht arkitekturën e aplikacioneve që ofrojnë këtë funksionalitet. Në kapitullin tjetër, ne do të shikojmë problemet e zakonshme që aplikacionet e bazuara në mesazhe duhet të zgjidhin dhe diskutojnë strategjitë për trajtimin e tyre. Ne do ta mbyllim kapitullin duke përshkruar se si të flasim për teknologjitë e mesazheve në përgjithësi, në mënyrë që të vlerësoni përshtatshmërinë e tyre për rastet tuaja të përdorimit.

Pjesa e mëparshme e përkthyer: Kuptimi i ndërmjetësve të mesazheve. Mësimi i mekanikës së mesazheve me ActiveMQ dhe Kafka. Kapitulli 1

Përkthimi u krye: tele.gg/middle_java

Vazhdon…

Vetëm përdoruesit e regjistruar mund të marrin pjesë në anketë. Hyni, te lutem

A përdoret Kafka në organizatën tuaj?

  • Po

  • Jo

  • Përdorur më parë, tani jo

  • Ne planifikojmë të përdorim

38 përdorues votuan. 8 përdorues abstenuan.

Burimi: www.habr.com

Shto një koment