Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka

Ferfolch fan de oersetting fan in lyts boekje:
Berjochtmakelaars begripe
skriuwer: Jakub Korab, útjouwer: O'Reilly Media, Inc., datum fan publikaasje: juny 2017, ISBN: 9781492049296.

Foarige oerset diel: Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 1 Yntroduksje

HAADSTIK 3

Kafka

Kafka is ûntwikkele by LinkedIn om guon fan 'e beheiningen fan tradisjonele berjochtmakelaars om te kommen en foar te kommen dat jo meardere berjochtmakelaars moatte ynstelle foar ferskate punt-tot-punt ynteraksjes, wat wurdt beskreaun yn dit boek ûnder "Op- en útskaaljen" op side 28 Gebrûksgefallen LinkedIn hat foar it grutste part fertroud op ien-rjochte ynname fan heul grutte hoemannichten gegevens, lykas sideklikken en tagongslogboeken, wylst dizze gegevens noch altyd brûkt wurde kinne troch meardere systemen sûnder ynfloed op de produktiviteit fan produsinten of oare konsuminten. Yn feite is de reden dat Kafka bestiet om it soarte messaging-arsjitektuer te krijen dat de Universal Data Pipeline beskriuwt.

Sjoen dit eindoel ûntstiene fansels oare easken. Kafka moat:

  • Wês ekstreem rap
  • Biede mear bânbreedte by it wurkjen mei berjochten
  • Stypje Publisher-Abonnee en Point-to-Point modellen
  • Fertrage net mei it tafoegjen fan konsuminten. Bygelyks, de prestaasjes fan sawol de wachtrige as it ûnderwerp yn ActiveMQ degradearret as it oantal konsuminten op 'e bestimming groeit.
  • Wês horizontaal skalberber; as ien broker dy't berjochten oanhâldt, dit allinich kin dwaan op maksimale skiifsnelheid, dan makket it sin om fierder te gean as in inkele broker-eksimplaar om prestaasjes te ferheegjen
  • Beheine tagong ta it opslaan en opnij opheljen fan berjochten

Om dit alles te berikken, naam Kafka in arsjitektuer oan dy't de rollen en ferantwurdlikheden fan kliïnten en messagingbrokers opnij definieare. It JMS-model is heul broker-oriïntearre, wêr't de brokker ferantwurdlik is foar it fersprieden fan berjochten en kliïnten moatte allinich soargen hawwe oer it ferstjoeren en ûntfangen fan berjochten. Kafka, oan 'e oare kant, is klant-sintraal, mei't de kliïnt in protte fan 'e funksjes fan in tradysjonele makelder nimt, lykas earlike ferdieling fan relevante berjochten oan konsuminten, yn ruil foar in ekstreem rappe en skalberbere broker. Foar minsken dy't hawwe wurke mei tradisjonele messaging systemen, wurkje mei Kafka fereasket in fûnemintele feroaring fan geast.
Dizze yngenieursrjochting hat laat ta it oanmeitsjen fan in berjochtynfrastruktuer dy't by steat is om trochput te fergrutsjen mei in protte oarders fan grutte yn ferliking mei in konvinsjonele makelder. As wy sille sjen, komt dizze oanpak mei trade-offs, wat betsjut dat Kafka net geskikt is foar bepaalde soarten workloads en ynstalleare software.

Unified Destination Model

Om de hjirboppe beskreaune easken te foldwaan, hat Kafka publisearje-abonnearje en punt-oan-punt berjochten kombineare ûnder ien soarte bestimming - ûnderwerp. Dit is betiizjend foar minsken dy't wurke hawwe mei berjochtsystemen, wêr't it wurd "ûnderwerp" ferwiist nei in útstjoermeganisme wêrfan (fan it ûnderwerp) lêzen net duorsum is. Kafka-ûnderwerpen moatte wurde beskôge as in hybride bestimmingstype, lykas definiearre yn 'e ynlieding fan dit boek.

Foar de rest fan dit haadstik sil, útsein as wy eksplisyt oars oanjaan, de term "ûnderwerp" ferwize nei in Kafka-ûnderwerp.

Om folslein te begripen hoe't ûnderwerpen har gedrage en hokker garânsjes se leverje, moatte wy earst sjen hoe't se yn Kafka wurde ymplementearre.
Elk ûnderwerp yn Kafka hat syn eigen log.
Produsinten dy't berjochten stjoere nei Kafka skriuwe nei dit log, en konsuminten lêze út it log mei help fan oanwizers dy't hieltyd foarút geane. Periodyk wisket Kafka de âldste dielen fan it log, of de berjochten yn dy dielen binne lêzen of net. In sintraal diel fan Kafka's ûntwerp is dat de makelder net skele as berjochten wurde lêzen of net - dat is de ferantwurdlikens fan 'e kliïnt.

De termen "log" en "pointer" komme net yn Kafka dokumintaasje. Dizze bekende termen wurde hjir brûkt om begryp te helpen.

Dit model is folslein oars fan ActiveMQ, dêr't berjochten fan alle wachtrijen wurde opslein yn deselde log, en de makelder markearret de berjochten as wiske neidat se binne lêzen.
Litte wy no in bytsje djipper grave en it ûnderwerplog yn mear detail besjen.
It Kafka-logboek bestiet út ferskate partysjes (Ofbylding 3-1). Kafka garandearret strikte oardering yn elke partysje. Dit betsjut dat berjochten skreaun nei de partysje yn in bepaalde folchoarder sille wurde lêzen yn deselde folchoarder. Elke partysje wurdt ymplementearre as in rôljend logbestân dat befettet in subset (subset) fan alle berjochten stjoerd nei it ûnderwerp troch syn produsinten. It oanmakke ûnderwerp befettet, standert, ien partition. It idee fan partysjes is it sintrale idee fan Kafka foar horizontale skaalfergrutting.

Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka
figuer 3-1. Kafka Partitionen

As in produsint in berjocht stjoert nei in Kafka-ûnderwerp, beslút hy nei hokker partysje it berjocht stjoere sil. Dit sille wy letter yn mear detail besjen.

Berjochten lêze

De kliïnt dy't de berjochten lêze wol, beheart in neamde oanwizer neamd konsumint groep, dy't wiist op offset berjochten yn 'e partition. In offset is in ynkrementele posysje dy't begjint by 0 oan it begjin fan in partition. Dizze konsumintgroep, ferwiisd yn 'e API fia de troch de brûker definieare group_id, komt oerien mei ien logyske konsumint of systeem.

De measte messagingsystemen lêze gegevens fan 'e bestimming mei meardere eksimplaren en diskusjes om berjochten parallel te ferwurkjen. Sa sille d'r meastentiids in protte konsuminteeksimplaren wêze dy't deselde konsumintegroep diele.

It probleem fan it lêzen kin wurde fertsjintwurdige as folget:

  • Underwerp hat meardere partysjes
  • Meardere groepen konsuminten kinne in ûnderwerp tagelyk brûke
  • In groep konsuminten kin meardere aparte eksimplaren hawwe

Dit is in net-triviale in protte-to-in protte probleem. Om te begripen hoe't Kafka relaasjes omgiet tusken konsumintegroepen, konsuminteksimplaren en partysjes, litte wy nei in searje fan stadichoan kompleksere lêsscenario's sjen.

Konsuminten en konsumintegroepen

Litte wy as útgongspunt in ûnderwerp nimme mei ien partition (Ofbylding 3-2).

Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka
figuer 3-2. Konsumint lêst fan partition

As in konsuminteksimplaar ferbynt mei syn eigen group_id oan dit ûnderwerp, wurdt it in lêspartysje en in offset tawiisd yn dy partysje. De posysje fan dizze offset is konfigurearber yn 'e kliïnt as in oanwizer nei de meast resinte posysje (nijste berjocht) of ierste posysje (âldste berjocht). De konsumint freget (polls) berjochten út it ûnderwerp, wêrtroch't se opfolgjend lêzen wurde út it log.
De offset posysje wurdt regelmjittich ynsette werom nei Kafka en opslein as berjochten yn in ynterne ûnderwerp _konsumint_offsets. Lêzen berjochten wurde noch altyd net wiske, yn tsjinstelling ta in gewoane broker, en de kliïnt kin de offset weromdraaie om al besjoen berjochten opnij te ferwurkjen.

As in twadde logyske konsumint ferbynt mei in oare group_id, beheart it in twadde oanwizer dy't ûnôfhinklik is fan 'e earste (Ofbylding 3-3). Sa wurket in Kafka-ûnderwerp as in wachtrige dêr't ien konsumint is en as in normaal publisearje-abonnearje (pub-sub) ûnderwerp dêr't meardere konsuminten har op abonnearje, mei it ekstra foardiel dat alle berjochten opslein wurde en meardere kearen ferwurke wurde kinne.

Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka
figuer 3-3. Twa konsuminten yn ferskate konsumintegroepen lêze fan deselde partysje

Konsuminten yn in konsumintegroep

As ien konsumint eksimplaar lêst gegevens fan in partition, it hat folsleine kontrôle fan de oanwizer en ferwurket berjochten lykas beskreaun yn de foarige paragraaf.
As ferskate eksimplaren fan konsuminten ferbûn binne mei deselde group_id oan in ûnderwerp mei ien partition, dan sil de eksimplaar dy't it lêste ferbûn hawwe kontrôle krije oer de oanwizer en fan dat momint ôf sil it alle berjochten ûntfange (Ofbylding 3-4).

Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka
figuer 3-4. Twa konsuminten yn deselde konsumintegroep lêze fan deselde partysje

Dizze wize fan ferwurkjen, wêrby't it oantal konsuminteksimplaren it oantal partysjes grutter makket, kin tocht wurde as in soarte fan eksklusive konsumint. Dit kin nuttich wêze as jo "aktyf-passyf" (of "waarm-waarm") klustering fan jo konsuminteksimplaren nedich binne, hoewol it útfieren fan meardere konsuminten parallel ("aktyf-aktyf" of "hyt-waar") folle typiger is as konsuminten Yn standby.

Dit hjirboppe beskreaune berjochtferdielingsgedrach kin ferrassend wêze yn ferliking mei hoe't in normale JMS-wachtrige gedraacht. Yn dit model sille berjochten dy't nei de wachtrige stjoerd wurde evenredich ferdield wurde tusken de twa konsuminten.

Meastentiids, as wy meardere eksimplaren fan konsuminten meitsje, dogge wy dit of om berjochten parallel te ferwurkjen, of om de snelheid fan it lêzen te ferheegjen, of om de stabiliteit fan it lêsproses te fergrutsjen. Om't mar ien konsuminteksimplaar tagelyk gegevens fan in partysje kin lêze, hoe wurdt dit berikt yn Kafka?

Ien manier om dit te dwaan is in inkele konsuminteksimplaar te brûken om alle berjochten te lêzen en troch te jaan oan 'e threadpool. Hoewol dizze oanpak fergruttet de ferwurking trochfier, fergruttet it de kompleksiteit fan 'e konsumintlogika en docht neat om de robúste fan it lêssysteem te fergrutsjen. As ien eksimplaar fan 'e konsumint delkomt fanwege in stroomûnderbrekking of ferlykber barren, dan stopet de subtraksje.

De kanonike manier om dit probleem yn Kafka op te lossen is bОmear partysjes.

Partitioning

Partitionen binne it haadmeganisme foar it parallelisearjen fan lêzen en skaalfergrutting fan in ûnderwerp bûten de bânbreedte fan in inkele broker-eksimplaar. Om dit better te begripen, litte wy in situaasje beskôgje wêr't d'r in ûnderwerp is mei twa partysjes en ien konsumint abonnearret op dit ûnderwerp (Ofbylding 3-5).

Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka
figuer 3-5. Ien konsumint lêst fan meardere partysjes

Yn dit senario wurdt de konsumint kontrôle jûn oer de oanwizers dy't oerienkomme mei syn group_id yn beide partysjes en begjint berjochten fan beide partysjes te lêzen.
As in ekstra konsumint foar deselde group_id wurdt tafoege oan dit ûnderwerp, ferwiist Kafka ien fan 'e partysjes fan' e earste nei de twadde konsumint. Dêrnei sil elke eksimplaar fan 'e konsumint lêze fan ien dieling fan it ûnderwerp (Ofbylding 3-6).

Om te soargjen dat berjochten parallel wurde ferwurke yn 20 threads, hawwe jo op syn minst 20 partysjes nedich. As der minder partysjes binne, sille jo bliuwe mei konsuminten dy't neat hawwe om oan te wurkjen, lykas earder beskreaun yn 'e diskusje fan eksklusive konsuminten.

Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 3. Kafka
figuer 3-6. Twa konsuminten yn deselde konsumintegroep lêze fan ferskate partysjes

Dit skema ferminderet de kompleksiteit fan 'e Kafka-broker sterk yn ferliking mei de berjochtferdieling dy't nedich is om de JMS-wachtrige te behâlden. Hjir hoege jo gjin soargen te meitsjen oer de folgjende punten:

  • Hokker konsumint moat it folgjende berjocht ûntfange, basearre op round-robin-allokaasje, hjoeddeistige kapasiteit fan prefetch-buffers, of eardere berjochten (lykas foar JMS-berjochtgroepen).
  • Hokker berjochten wurde stjoerd nei hokker konsuminten en oft se opnij besoarge wurde moatte yn gefal fan mislearring.

Alles wat de Kafka-makelaar moat dwaan is berjochten opfolgjend trochjaan oan de konsumint as de lêste se freget.

De easken foar it parallelisearjen fan it korrektyflêzen en it opnij ferstjoeren fan mislearre berjochten geane lykwols net fuort - de ferantwurdlikens foar har giet gewoan oer fan 'e makelder nei de klant. Dit betsjut dat se moatte wurde rekken holden yn jo koade.

Berjochten ferstjoere

It is de ferantwurdlikens fan de produsint fan dat berjocht om te besluten nei hokker partysje in berjocht stjoere moat. Om it meganisme te begripen wêrmei dit wurdt dien, moatte wy earst beskôgje wat wy eins stjoere.

Wylst wy yn JMS in berjochtstruktuer brûke mei metadata (kopteksten en eigenskippen) en in lichem dat de loadload befettet, yn Kafka is it berjocht pear "kaai-wearde". De berjochtlading wurdt stjoerd as in wearde. De kaai, oan 'e oare kant, wurdt benammen brûkt foar partitioning en moat befetsje saaklike logika spesifike kaaiom relatearre berjochten yn deselde partysje te pleatsen.

Yn haadstik 2 hawwe wy it senario foar online weddenskip besprutsen wêrby't relatearre eveneminten yn oarder moatte wurde ferwurke troch ien konsumint:

  1. It brûkersaccount is konfigurearre.
  2. Jild wurdt byskreaun op it akkount.
  3. In weddenskip wurdt makke dy't lûkt jild út it akkount.

As elk barren in berjocht is pleatst nei in ûnderwerp, dan soe de natuerlike kaai de akkount-ID wêze.
As in berjocht ferstjoerd wurdt mei de Kafka Producer API, wurdt it trochjûn oan in partysjefunksje dy't, sjoen it berjocht en de aktuele tastân fan it Kafka-kluster, de ID weromjout fan 'e partysje dêr't it berjocht nei ferstjoerd wurde moat. Dizze funksje wurdt ymplementearre yn Java fia de Partitioner-ynterface.

Dizze ynterface sjocht der sa út:

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

De ymplemintaasje fan Partitioner brûkt it standert hashing-algoritme foar algemien doel oer de kaai om de partition te bepalen, of round-robin as gjin kaai is oantsjutte. Dizze standertwearde wurket yn 'e measte gefallen goed. Yn 'e takomst sille jo lykwols jo eigen skriuwe wolle.

It skriuwen fan jo eigen partitioneringsstrategy

Litte wy nei in foarbyld sjen wêr't jo metadata wolle ferstjoere tegearre mei de berjochtlading. De lading yn ús foarbyld is in ynstruksje om in boarch te meitsjen op it spulkonto. In ynstruksje is iets dat wy wolle wurde garandearre om net te wizigjen by oerdracht en wolle der wis fan wêze dat allinich in fertroud streamop-systeem dy ynstruksje kin inisjearje. Yn dit gefal binne de ferstjoerende en ûntfangende systemen it iens oer it brûken fan in hantekening om it berjocht te autentisearjen.
Yn normale JMS definiearje wy gewoan in eigenskip "berjochtûndertekening" en foegje it ta oan it berjocht. Kafka jout ús lykwols gjin meganisme foar it trochjaan fan metadata, allinich in kaai en in wearde.

Sûnt de wearde is in bankoerdracht loadload waans yntegriteit wy wolle behâlde, wy hawwe gjin oare kar, mar te definiearjen de gegevens struktuer te brûken yn de kaai. Oannommen dat wy in akkount-ID nedich binne foar partitionearjen, om't alle berjochten yn ferbân mei in akkount yn oarder moatte wurde ferwurke, sille wy de folgjende JSON-struktuer komme:

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

Om't de wearde fan 'e hantekening sil fariearje ôfhinklik fan' e lading, sil de standert hashingstrategy fan 'e Partitioner-ynterface net betrouber groepearje relatearre berjochten. Dêrom moatte wy ús eigen strategy skriuwe dy't dizze kaai parse sil en de accountId-wearde partitionearje.

Kafka omfettet kontrôlesummen om korrupsje fan berjochten yn 'e winkel te detectearjen en hat in folsleine set fan feiligensfunksjes. Sels dan ferskine yndustryspesifike easken, lykas de hjirboppe, soms.

De partitioneringsstrategy fan de brûker moat derfoar soargje dat alle relatearre berjochten yn deselde partysje einigje. Hoewol dit ienfâldich liket, kin de eask komplisearre wurde troch it belang fan it bestellen fan relatearre berjochten en hoe fêst it oantal partysjes yn in ûnderwerp is.

It oantal partysjes yn in ûnderwerp kin yn 'e rin fan' e tiid feroarje, om't se kinne wurde tafoege as ferkear boppe de earste ferwachtingen giet. Sa kinne berjochtkaaien wurde assosjearre mei de partysje wêr't se oarspronklik nei waarden stjoerd, wat betsjuttet dat in diel fan steat wurdt dield tusken produsinteksimplaren.

In oare faktor om te beskôgjen is de even ferdieling fan berjochten oer partysjes. Typysk wurde toetsen net lykwichtich ferdield oer berjochten, en hashfunksjes garandearje net in earlike ferdieling fan berjochten foar in lytse set toetsen.
It is wichtich om te notearjen dat jo lykwols kieze om berjochten te splitsen, it skiedingsteken sels moat miskien opnij brûkt wurde.

Beskôgje de eask om gegevens te replikearjen tusken Kafka-klusters op ferskate geografyske lokaasjes. Foar dit doel komt Kafka mei in kommandorigelark neamd MirrorMaker, dat brûkt wurdt om berjochten fan ien kluster te lêzen en oer te bringen nei in oar.

MirrorMaker moat de kaaien fan it replikearre ûnderwerp begripe om relatyf folchoarder tusken berjochten te behâlden by it replikearjen tusken klusters, om't it oantal partysjes foar dat ûnderwerp miskien net itselde is yn twa klusters.

Oanpaste partitioneringsstrategyen binne relatyf seldsum, om't standert hashing of round robin goed wurket yn 'e measte senario's. As jo ​​​​lykwols sterke bestelgarânsjes nedich binne of metadata moatte ekstrahearje fan payloads, dan is partitionearjen iets dat jo in tichterby moatte besjen.

De skaalberens en prestaasjesfoardielen fan Kafka komme út it ferpleatsen fan guon fan 'e ferantwurdlikheden fan' e tradisjonele broker nei de klant. Yn dit gefal wurdt in beslút makke om potinsjeel relatearre berjochten te fersprieden ûnder ferskate konsuminten dy't parallel wurkje.

JMS-brokers moatte ek omgean mei sokke easken. Nijsgjirrich is dat it meganisme foar it ferstjoeren fan besibbe berjochten nei deselde konsumint, ymplementearre fia JMS Message Groups (in fariaasje op 'e kleverige load balancing (SLB) strategy), ek fereasket dat de stjoerder berjochten markearret as besibbe. Yn it gefal fan JMS is de brokker ferantwurdlik foar it ferstjoeren fan dizze groep relatearre berjochten nei ien konsumint út in protte, en it oerdragen fan eigendom fan 'e groep as de konsumint falt.

Produsint oerienkomsten

Partitioning is net it ienige ding om te beskôgjen by it ferstjoeren fan berjochten. Litte wy sjen nei de send() metoaden fan 'e Producer-klasse yn' e Java API:

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

It moat fuortendaliks opmurken wurde dat beide metoaden Future weromkomme, wat oanjout dat de ferstjoeroperaasje net fuortendaliks útfierd wurdt. It resultaat is dat in berjocht (ProducerRecord) skreaun wurdt nei de ferstjoerbuffer foar elke aktive partysje en stjoerd nei de brokker as eftergrûntried yn 'e Kafka-kliïntbibleteek. Hoewol dit dingen ongelooflijk rap makket, betsjut it dat in sûnder ûnderfining applikaasje berjochten kin ferlieze as it proses wurdt stoppe.

Lykas altyd is d'r in manier om de ferstjoeroperaasje betrouberer te meitsjen op kosten fan prestaasjes. De grutte fan dizze buffer kin ynsteld wurde op 0, en de ferstjoerende applikaasje thread sil wurde twongen om te wachtsjen oant de berjochtoerdracht nei de makelder is foltôge, as folget:

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

Mear oer it lêzen fan berjochten

It lêzen fan berjochten hat ekstra kompleksiteiten dêr't oer spekulearre wurde moat. Oars as de JMS API, dat kin rinne in berjocht harker yn reaksje op in berjocht, de Konsumint Kafka allinnich polls. Litte wy de metoade in tichterby besjen poll ()brûkt foar dit doel:

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

De weromwearde fan 'e metoade is in kontenerstruktuer mei meardere objekten konsumint rekord út mooglik ferskate partysjes. konsumint rekord is sels in holder-objekt foar in kaai-wearde-pear mei byhearrende metadata, lykas de partysje wêrfan it is ôflaat.

Lykas besprutsen yn haadstik 2, moatte wy yn gedachten hâlde wat der bart mei berjochten neidat se mei sukses of net slagge binne ferwurke, bygelyks as de kliïnt it berjocht net kin ferwurkje of as it ôfbrekke. Yn JMS waard dit behannele fia in erkenningsmodus. De makelder sil it mei súkses ferwurke berjocht wiskje, of it rau of falske berjocht opnij leverje (oannommen dat transaksjes waarden brûkt).
Kafka wurket hiel oars. Berjochten wurde net wiske yn 'e makelder nei proofreading, en wat bart op mislearring is de ferantwurdlikens fan de proofreading koade sels.

As wy hawwe sein, de konsumint groep is ferbûn mei de offset yn it log. De logposysje dy't ferbûn is mei dizze offset komt oerien mei it folgjende berjocht dat wurdt útjûn as antwurd op poll (). It punt yn 'e tiid dat dizze offset ferheget, is beslissend foar it lêzen.

Werom nei it earder besprutsen lêsmodel, berjochtferwurking bestiet út trije stadia:

  1. Sykje in berjocht foar it lêzen.
  2. Ferwurkje it berjocht.
  3. Befêstigje berjocht.

De Kafka-konsumint komt mei in konfiguraasjeopsje enable.auto.commit. Dit is in faak brûkte standertynstelling, lykas gewoanlik is mei ynstellings dy't it wurd "auto" befetsje.

Foarôfgeand oan Kafka 0.10 soe in kliïnt dy't dizze opsje brûkt de offset stjoere fan it lêste berjocht lêzen op de folgjende oprop poll () nei ferwurking. Dit betsjutte dat alle berjochten dy't al ophelle wiene, koene wurde opnij ferwurke as de kliïnt se al ferwurke hie, mar ûnferwachts ferneatige waarden foardat hy belle poll (). Om't de makelder gjin steat hâldt oer hoefolle kearen in berjocht is lêzen, sil de folgjende konsumint dy't dat berjocht ophelje sil net witte dat der wat slims bard is. Dit gedrach wie pseudo-transaksjoneel. De offset waard allinich ynset as it berjocht mei súkses ferwurke waard, mar as de kliïnt ôfbrutsen, soe de brokker itselde berjocht wer nei in oare kliïnt stjoere. Dit gedrach wie yn oerienstimming mei de garânsje foar berjochtlevering "op syn minst ien kear".

Yn Kafka 0.10 is de kliïntkoade feroare sadat de commit periodyk wurdt trigger troch de kliïntbibleteek, lykas ynsteld auto.commit.interval.ms. Dit gedrach is earne tusken de JMS AUTO_ACKNOWLEDGE en DUPS_OK_ACKNOWLEDGE modus. By it brûken fan autocommit kinne berjochten wurde ynset, nettsjinsteande oft se werklik binne ferwurke - dit kin barre yn it gefal fan in trage konsumint. As in konsumint ôfbrekke, soene berjochten wurde ophelle troch de folgjende konsumint, begjinnend by de tawijde posysje, wat kin resultearje yn in miste berjocht. Yn dit gefal ferlear Kafka de berjochten net, de lêskoade ferwurke se gewoan net.

Dizze modus hat deselde belofte as yn ferzje 0.9: berjochten kinne wurde ferwurke, mar as it mislearret, kin de offset net ynset wurde, wêrtroch't mooglik levering ferdûbele wurdt. Hoe mear berjochten jo ophelje by it útfieren poll (), hoe mear dit probleem.

Lykas besprutsen yn "Berjochten lêze fan in wachtrige" op side 21, is d'r net sa'n ding as in ienmalige levering fan in berjocht yn in berjochtensysteem as mislearringsmodi wurde rekken holden.

Yn Kafka binne d'r twa manieren om in offset (offset) yn te setten: automatysk en mei de hân. Yn beide gefallen kinne berjochten meardere kearen wurde ferwurke as it berjocht ferwurke is, mar mislearre foar de commit. Jo kinne ek kieze om it berjocht hielendal net te ferwurkjen as de commit op 'e eftergrûn barde en jo koade is foltôge foardat it koe wurde ferwurke (miskien yn Kafka 0.9 en earder).

Jo kinne it manuelle offset-commitproses kontrolearje yn 'e Kafka-konsumint-API troch de parameter yn te stellen enable.auto.commit om falsk en eksplisyt ien fan 'e folgjende metoaden te neamen:

void commitSync();
void commitAsync();

As jo ​​​​it berjocht "op syn minst ien kear" wolle ferwurkje, moatte jo de offset manuell dwaan mei commitSync()troch dit kommando fuort út te fieren nei it ferwurkjen fan de berjochten.

Dizze metoaden steane net ta dat berjochten wurde erkend foardat se wurde ferwurke, mar se dogge neat om potinsjele ferwurkingsfertragingen te eliminearjen, wylst se it uterlik jouwe fan transaksje. D'r binne gjin transaksjes yn Kafka. De klant hat net de mooglikheid om it folgjende te dwaan:

  • Rôlje automatysk in falsk berjocht werom. Konsuminten sels moatte omgean mei útsûnderingen dy't ûntsteane út problematyske loadloads en backend-útfallen, om't se net kinne fertrouwe op 'e makelder om berjochten opnij te leverjen.
  • Stjoer berjochten nei meardere ûnderwerpen yn ien atoomoperaasje. As wy koart sille sjen, kin kontrôle oer ferskate ûnderwerpen en partysjes wenje op ferskate masines yn it Kafka-kluster dy't transaksjes net koördinearje as se ferstjoerd wurde. Op it momint fan dit skriuwen is wat wurk dien om dit mooglik te meitsjen mei de KIP-98.
  • Assosiearje it lêzen fan ien berjocht fan ien ûnderwerp mei it ferstjoeren fan in oar berjocht nei in oar ûnderwerp. Nochris is de Kafka-arsjitektuer ôfhinklik fan in protte ûnôfhinklike masines dy't as ien bus rinne en gjin besykjen wurdt dien om dit te ferbergjen. D'r binne bygelyks gjin API-komponinten dy't jo kinne keppelje konsumint и Produsint yn in transaksje. Yn JMS wurdt dit levere troch it objekt Sittingdêr't wurde makke MessageProducers и Berjocht Consumers.

As wy net kinne fertrouwe op transaksjes, hoe kinne wy ​​dan semantyk leverje oan dy fan tradisjonele messagingsystemen?

As der in mooglikheid is dat de offset fan de konsumint tanimme kin foardat it berjocht ferwurke is, lykas by in konsumintûngelok, dan hat de konsumint gjin manier om te witten oft syn konsumintegroep it berjocht mist hat doe't it in ôfskieding krige. Dus ien strategy is om de offset werom te draaien nei de foarige posysje. De Kafka konsumint API biedt de folgjende metoaden foar dit:

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

Metoade sykje() kin brûkt wurde mei metoade
offsetsForTimes(Map timestampsToSearch) om werom te spoelen nei in steat op in spesifyk punt yn it ferline.

Implisyt betsjut it brûken fan dizze oanpak dat it heul wierskynlik is dat guon berjochten dy't earder ferwurke binne lêzen en opnij ferwurke wurde. Om dit foar te kommen, kinne wy ​​idempotent lêzen brûke, lykas beskreaun yn haadstik 4, om earder besjoen berjochten by te hâlden en duplikaten te eliminearjen.

As alternatyf kin jo konsumintkoade ienfâldich wurde hâlden, salang't berjochtferlies of duplikaasje akseptabel is. As wy gebrûksgefallen beskôgje wêrfoar Kafka gewoanlik brûkt wurdt, lykas it behanneljen fan log-eveneminten, metriken, klik folgjen, ensfh., Wy begripe dat it ferlies fan yndividuele berjochten net wierskynlik in signifikante ynfloed hat op omlizzende applikaasjes. Yn sokke gefallen binne de standertwearden perfoarst akseptabel. Oan 'e oare kant, as jo applikaasje betellingen moat ferstjoere, moatte jo foarsichtich soargje foar elk yndividueel berjocht. It komt allegear del op kontekst.

Persoanlike waarnimmings litte sjen dat as de yntinsiteit fan berjochten ferheget, de wearde fan elk yndividueel berjocht ôfnimt. Grutte berjochten binne meast weardefol as se wurde besjoen yn in aggregearre foarm.

Hege Beskikberens

Kafka's oanpak foar hege beskikberens is heul oars as de oanpak fan ActiveMQ. Kafka is ûntworpen om skaalfergruttingsklusters dêr't alle broker-eksimplaren tagelyk berjochten ûntfange en fersprieden.

In Kafka-kluster bestiet út meardere broker-ynstânsjes dy't rinne op ferskate servers. Kafka is ûntworpen om te rinnen op gewoane standalone hardware, wêrby't elk knooppunt in eigen tawijd opslach hat. It gebrûk fan netwurk taheakke opslach (SAN) wurdt net oanrikkemandearre om't meardere komputerknooppunten kinne konkurrearje foar tiid.Ыe opslach yntervallen en meitsje konflikten.

Kafka is altyd op systeem. In protte grutte Kafka-brûkers slute har klusters noait ôf en de software fernijt altyd mei in sekwinsjele werstart. Dit wurdt berikt troch kompatibiliteit te garandearjen mei de foarige ferzje foar berjochten en ynteraksjes tusken brokers.

Brokers ferbûn mei in tsjinner kluster ZooKeeper, dy't fungearret as konfiguraasjegegevensregister en wurdt brûkt om de rollen fan elke broker te koördinearjen. ZooKeeper sels is in ferspraat systeem dat soarget foar hege beskikberens troch de replikaasje fan ynformaasje troch fêst te stellen quorum.

Yn it basisgefal wurdt in ûnderwerp makke yn in Kafka-kluster mei de folgjende eigenskippen:

  • It oantal partysjes. Lykas earder besprutsen, hinget de krekte wearde dy't hjir brûkt wurdt ôf fan it winske nivo fan parallellêzen.
  • De replikaasjefaktor (faktor) bepaalt hoefolle broker-eksimplaren yn it kluster logs moatte befetsje foar dizze dieling.

Mei it brûken fan ZooKeepers foar koördinaasje besiket Kafka nije partysjes frij te fersprieden ûnder de makelders yn it kluster. Dit wurdt dien troch ien eksimplaar dy't fungearret as in Controller.

By runtime foar elk ûnderwerp partition Controller tawize rollen oan in makelder lieder (lieder, master, presintator) en folgers (folgers, slaven, ûndergeskikten). De makelder, fungearret as de lieder foar dizze dieling, is ferantwurdlik foar it ûntfangen fan alle berjochten dy't troch de produsinten nei him stjoerd binne en de berjochten oan 'e konsuminten te fersprieden. As berjochten nei in ûnderwerpdieling stjoerd wurde, wurde se replikearre nei alle brokerknooppunten dy't fungearje as folgers foar dy dieling. Elke knooppunt mei logs foar in partition wurdt neamd replika. In makelder kin fungearje as lieder foar guon partysjes en as folger foar oaren.

In folger dy't alle berjochten befettet dy't troch de lieder bewarre wurdt, wurdt oproppen syngronisearre replika (in replika dy't yn in syngronisearre steat is, yn syngronisearre replika). As in makelder dy't fungearret as lieder foar in partition giet omleech, eltse makelder dy't bywurke of syngronisearre foar dy dieling kin oernimme de lieder rol. It is in ongelooflijk duorsum ûntwerp.

In part fan de produsint konfiguraasje is de parameter acks, dy't bepaalt hoefolle replika's de ûntfangst (befêstigje) fan in berjocht moatte erkenne foardat de applikaasjetried trochgiet mei ferstjoeren: 0, 1, of allegear. As ynsteld op allegearre, as in berjocht wurdt ûntfongen, sil de lieder in befêstiging werom stjoere nei de produsint sa gau as hy befêstigings (befêstigingen) fan it rekord ûntfangt fan ferskate oanwizings (ynklusyf himsels) definieare troch de ûnderwerpynstelling min.insync.replicas (standert 1). As it berjocht net mei sukses replikearre wurde kin, sil de produsint in applikaasje útsûndering smyt (NotEnoughReplicas of NotEnoughReplicasAfterAppend).

In typyske konfiguraasje makket in ûnderwerp mei in replikaasjefaktor fan 3 (1 lieder, 2 folgers per partysje) en de parameter min.insync.replicas is ynsteld op 2. Yn dit gefal sil it kluster ien fan 'e makelders dy't de ûnderwerpdieling beheare kinne omleech gean sûnder ynfloed op kliïntapplikaasjes.

Dit bringt ús werom nei de al bekende trade-off tusken prestaasjes en betrouberens. Replikaasje bart op kosten fan ekstra wachttiid foar befêstigingen (befêstigingen) fan folgers. Hoewol, om't it parallel rint, replikaasje nei op syn minst trije knooppunten hat deselde prestaasjes as twa (negearje de ferheging fan gebrûk fan netwurkbânbreedte).

Troch dit replikaasjeskema te brûken, foarkomt Kafka tûk de needsaak om elk berjocht fysyk op skiif te skriuwen mei de operaasje syngronisearje(). Elk berjocht dat troch de produsint stjoerd wurdt, wurdt skreaun nei it partition log, mar lykas besprutsen yn haadstik 2, wurdt it skriuwen nei in bestân yn earste ynstânsje dien yn de buffer fan it bestjoeringssysteem. As dit berjocht wurdt replikearre nei in oare Kafka-eksimplaar en yn har ûnthâld is, betsjut it ferlies fan 'e lieder net dat it berjocht sels ferlern gien is - it kin oernommen wurde troch in syngronisearre replika.
Wegering om de operaasje út te fieren syngronisearje() betsjut dat Kafka berjochten sa fluch kin ûntfange as it se yn it ûnthâld kin skriuwe. Oarsom, hoe langer jo kinne foarkomme dat jo ûnthâld op skiif spoelen, hoe better. Om dizze reden is it net ûngewoan dat Kafka-makelaars 64 GB of mear ûnthâld wurde tawiisd. Dit ûnthâldgebrûk betsjut dat in inkele Kafka-eksimplaar maklik kin rinne mei snelheden in protte tûzenen kearen rapper dan in tradisjonele berjochtmakelaar.

Kafka kin ek ynsteld wurde om de operaasje oan te passen syngronisearje() oan berjochtpakketten. Sûnt alles yn Kafka pakket-rjochte is, wurket it eins frij goed foar in protte gebrûksgefallen en is in nuttich ark foar brûkers dy't heul sterke garânsjes nedich binne. In protte fan 'e suvere prestaasjes fan Kafka komt fan' e berjochten dy't as pakketten nei de makelder stjoerd wurde en dat dizze berjochten wurde lêzen fan 'e brokker yn opfolgjende blokken mei nul kopy operaasjes (operaasjes wêryn de taak fan it kopiearjen fan gegevens fan it iene ûnthâldgebiet nei it oare net útfierd wurdt). Dat lêste is in grutte prestaasjes en boarnewinst en is allinich mooglik troch it brûken fan in ûnderlizzende loggegevensstruktuer dy't it partitionskema definiearret.

Folle bettere prestaasjes binne mooglik yn in Kafka-kluster dan mei in inkele Kafka-makelaar, om't ûnderwerppartysjes oer in protte aparte masines útskaalje kinne.

Resultaten

Yn dit haadstik hawwe wy sjoen nei hoe't de Kafka-arsjitektuer de relaasje tusken kliïnten en makelders opnij foarstelle om in ongelooflijk robúste berjochtenpipeline te leverjen, mei trochset in protte kearen grutter dan dy fan in konvinsjonele berjochtmakelaar. Wy hawwe de funksjonaliteit besprutsen dy't it brûkt om dit te berikken en koart sjoen nei de arsjitektuer fan 'e applikaasjes dy't dizze funksjonaliteit leverje. Yn it folgjende haadstik sille wy sjen nei mienskiplike problemen dy't messaging-basearre applikaasjes moatte oplosse en beprate strategyen foar it omgean mei harren. Wy sille it haadstik einigje troch út te lizzen hoe't jo oer berjochttechnologyen yn 't algemien prate kinne, sadat jo de geskiktheid foar jo gebrûksgefallen kinne evaluearje.

Foarige oerset diel: Begryp fan berjochtmakkers. Learje de meganika fan messaging mei ActiveMQ en Kafka. Haadstik 1

Dien oersetting: tele.gg/midden_java

Oanhâlde wurde ...

Allinnich registrearre brûkers kinne meidwaan oan 'e enkête. Ynlogge, asjebleaft.

Wurdt Kafka brûkt yn jo organisaasje?

  • dat

  • gjin

  • Earder brûkt, no net

  • Wy planje te brûken

38 brûkers stimden. 8 brûkers ûntholden har.

Boarne: www.habr.com

Add a comment