Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka

Daŭrigo de la traduko de malgranda libro:
Kompreni Mesaĝajn Makleristojn
aŭtoro: Jakub Korab, eldonejo: O'Reilly Media, Inc., eldondato: junio 2017, ISBN: 9781492049296.

Antaŭa tradukita parto: Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 1 Enkonduko

ĈAPITRO 3

Kafka

Kafka estis evoluigita de LinkedIn por ĉirkaŭiri kelkajn el la limigoj de tradiciaj mesaĝmakleristoj kaj eviti devi starigi multoblajn mesaĝmakleristojn por malsamaj punkto-al-punktaj interagoj, kiu estas priskribita en ĉi tiu libro sub "Skalado supren kaj eksteren" sur paĝo 28. Uzokazoj LinkedIn plejparte dependis de unudirekta konsumado de tre grandaj kvantoj da datumoj, kiel paĝklakoj kaj alirprogramoj, dum daŭre permesante ke tiuj datumoj estu uzataj de multoblaj sistemoj sen influi la produktivecon de produktantoj aŭ aliaj konsumantoj. Fakte, la kialo, ke Kafka ekzistas, estas akiri la specon de mesaĝa arkitekturo, kiun la Universala Datuma Dukto priskribas.

Konsiderante ĉi tiun finfinan celon, aliaj postuloj nature aperis. Kafka devus:

  • Estu ekstreme rapida
  • Provizu pli da bendolarĝo kiam vi laboras kun mesaĝoj
  • Subteno Eldonisto-Abonanto kaj Punkto-al-Punkto modeloj
  • Ne malrapidu aldonante konsumantojn. Ekzemple, la agado de kaj la atendovico kaj la temo en ActiveMQ degradas kiam la nombro da konsumantoj sur la celloko kreskas.
  • Estu horizontale skalebla; se unu makleristo, kiu persistas mesaĝojn, povas fari tion nur kun maksimuma diskrapideco, tiam estas senco iri preter ununura makleristo por pliigi rendimenton.
  • Limigu aliron al stokado kaj reakiro de mesaĝoj

Por atingi ĉion ĉi, Kafka adoptis arkitekturon kiu redifinis la rolojn kaj respondecojn de klientoj kaj mesaĝaj makleristoj. La JMS-modelo estas tre orientita al makleristo, kie la makleristo respondecas pri distribuado de mesaĝoj kaj klientoj nur devas zorgi pri sendado kaj ricevado de mesaĝoj. Kafka, aliflanke, estas klientcentra, kun la kliento akceptas multajn el la trajtoj de tradicia makleristo, kiel justa distribuado de rilataj mesaĝoj al konsumantoj, kontraŭ ekstreme rapida kaj skalebla makleristo. Por homoj, kiuj laboris kun tradiciaj mesaĝaj sistemoj, labori kun Kafka postulas fundamentan mensoŝanĝon.
Ĉi tiu inĝenieristikdirekto kaŭzis la kreadon de mesaĝa infrastrukturo kapabla pliigi trairon je multaj grandordoj kompare kun konvencia makleristo. Kiel ni vidos, ĉi tiu aliro venas kun kompromisoj, kio signifas, ke Kafka ne taŭgas por certaj specoj de laborŝarĝoj kaj instalita programaro.

Unuigita Destina modelo

Por plenumi la postulojn priskribitajn supre, Kafka kombinis publikigi-aboni kaj punkto-al-punktan mesaĝadon sub unu speco de celloko − temo. Ĉi tio konfuzas al homoj, kiuj laboris kun mesaĝsistemoj, kie la vorto "temo" rilatas al elsenda mekanismo de kiu (de la temo) legado estas nedaŭra. Kafkaj temoj devus esti konsiderataj hibrida celspeco, kiel difinite en la enkonduko al ĉi tiu libro.

Por la cetero de ĉi tiu ĉapitro, krom se ni eksplicite diras alie, la termino "temo" referencos al Kafka temo.

Por plene kompreni kiel temoj kondutas kaj kiajn garantiojn ili donas, ni unue devas rigardi kiel ili estas efektivigitaj en Kafka.
Ĉiu temo en Kafka havas sian propran protokolon.
Produktantoj sendantaj mesaĝojn al Kafka skribas al ĉi tiu protokolo, kaj konsumantoj legas el la protokolo uzante montrilojn, kiuj konstante antaŭeniras. Periode, Kafka forigas la plej malnovajn partojn de la protokolo, ĉu la mesaĝoj en tiuj partoj estis legitaj aŭ ne. Centra parto de la dezajno de Kafka estas ke la makleristo ne zorgas ĉu mesaĝoj estas legitaj aŭ ne - tio estas la respondeco de la kliento.

La terminoj "log" kaj "montrilo" ne aperas en Kafka dokumentado. Ĉi tiuj konataj terminoj estas uzataj ĉi tie por helpi komprenon.

Ĉi tiu modelo estas tute diferenca de ActiveMQ, kie mesaĝoj de ĉiuj vostoj estas konservitaj en la sama protokolo, kaj la makleristo markas la mesaĝojn kiel forigitaj post kiam ili estis legitaj.
Ni nun fosu iom pli profunde kaj rigardu la teman protokolon pli detale.
La Kafka protokolo konsistas el pluraj sekcioj (Figuro 3-1). Kafka garantias striktan ordigon en ĉiu sekcio. Ĉi tio signifas, ke mesaĝoj skribitaj al la sekcio en certa ordo estos legitaj en la sama ordo. Ĉiu sekcio estas efektivigita kiel ruliĝanta protokolo-dosiero kiu enhavas subaro (subaro) de ĉiuj mesaĝoj senditaj al la temo de ĝiaj produktantoj. La kreita temo enhavas, defaŭlte, unu sekcion. La ideo de sekcioj estas la centra ideo de Kafka por horizontala skalado.

Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka
Figuro 3-1. Kafka Dispartigoj

Kiam produktanto sendas mesaĝon al Kafka temo, ĝi decidas al kiu sekcio sendi la mesaĝon. Ni rigardos ĉi tion pli detale poste.

Legante mesaĝojn

La kliento kiu volas legi la mesaĝojn administras nomitan montrilon nomitan konsumanta grupo, kiu montras al ofseto mesaĝoj en la sekcio. Ofseto estas pliiga pozicio, kiu komenciĝas ĉe 0 ĉe la komenco de sekcio. Ĉi tiu konsumanta grupo, referencita en la API per la uzant-difinita group_id, respondas unu logika konsumanto aŭ sistemo.

La plej multaj mesaĝsistemoj legas datumojn de la celloko uzante plurajn kazojn kaj fadenojn por procesi mesaĝojn paralele. Tiel, kutime estos multaj konsumantaj petskriboj dividantaj la saman konsumantgrupon.

La problemo de legado povas esti prezentita jene:

  • Temo havas plurajn sekciojn
  • Multoblaj grupoj de konsumantoj povas uzi temon samtempe
  • Grupo de konsumantoj povas havi plurajn apartajn okazojn

Ĉi tio estas ne-triviala mult-al-multa problemo. Por kompreni kiel Kafka pritraktas rilatojn inter konsumantaj grupoj, konsumantaj petskriboj kaj sekcioj, ni rigardu serion de iom post iom pli kompleksaj legadscenaroj.

Konsumantoj kaj konsumantaj grupoj

Ni prenu kiel deirpunkton temon kun unu subdisko (Figuro 3-2).

Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka
Figuro 3-2. Konsumanto legas el sekcio

Kiam konsumanto-instanco konektas kun sia propra group_id al ĉi tiu temo, al ĝi estas asignita legdisko kaj ofseto en tiu sekcio. La pozicio de ĉi tiu ofseto estas agordebla en la kliento kiel montrilo al la plej lastatempa pozicio (plej nova mesaĝo) aŭ plej frua pozicio (plej malnova mesaĝo). La konsumanto petas (sondas) mesaĝojn de la temo, kio igas ilin sinsekve legi de la protokolo.
La kompensa pozicio estas regule transdonata al Kafka kaj konservita kiel mesaĝoj en interna temo _konsumantoj_offsets. Legitaj mesaĝoj ankoraŭ ne estas forigitaj, male al kutima makleristo, kaj la kliento povas rebobeni la ofseton por reprocezi jam viditajn mesaĝojn.

Kiam dua logika konsumanto konektas per malsama group_id, ĝi administras duan montrilon kiu estas sendependa de la unua (Figuro 3-3). Tiel, Kafka-temo agas kiel atendovico kie estas unu konsumanto kaj kiel normala publikig-abono (pub-sub) temo al kiu multoblaj konsumantoj abonas, kun la kroma avantaĝo ke ĉiuj mesaĝoj estas stokitaj kaj povas esti prilaboritaj plurfoje.

Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka
Figuro 3-3. Du konsumantoj en malsamaj konsumantgrupoj legas el la sama sekcio

Konsumantoj en konsumantogrupo

Kiam unu konsumanta petskribo legas datumojn de sekcio, ĝi havas plenan kontrolon de la montrilo kaj prilaboras mesaĝojn kiel priskribite en la antaŭa sekcio.
Se pluraj okazoj de konsumantoj estis ligitaj kun la sama group_id al temo kun unu subdisko, tiam la instanco kiu ligis laste ricevos kontrolon de la montrilo kaj ekde tiu momento ĝi ricevos ĉiujn mesaĝojn (Figuro 3-4).

Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka
Figuro 3-4. Du konsumantoj en la sama konsumantogrupo legas el la sama sekcio

Ĉi tiu reĝimo de pretigo, en kiu la nombro da konsumantkazoj superas la nombron da sekcioj, povas esti opiniita kiel speco de ekskluziva konsumanto. Ĉi tio povas esti utila se vi bezonas "aktiva-pasiva" (aŭ "varma-varma") grupigo de viaj konsumantoj, kvankam ruli plurajn konsumantojn paralele ("aktiva-aktiva" aŭ "varma-varma") estas multe pli tipa ol konsumantoj.En standby.

Ĉi tiu mesaĝo distribua konduto priskribita supre povas esti surpriza kompare kun kiel normala JMS-vico kondutas. En ĉi tiu modelo, mesaĝoj senditaj al la atendovico estos egale distribuitaj inter la du konsumantoj.

Plej ofte, kiam ni kreas plurajn kazojn de konsumantoj, ni faras tion aŭ por procesi mesaĝojn paralele, aŭ por pliigi la rapidecon de legado, aŭ por pliigi la stabilecon de la legado. Ĉar nur unu konsumanto povas legi datumojn de sekcio samtempe, kiel tio estas atingita en Kafka?

Unu maniero fari tion estas uzi ununuran konsuman petskribon por legi ĉiujn mesaĝojn kaj transdoni ilin al la fadena grupo. Dum ĉi tiu aliro pliigas pretigan trairon, ĝi pliigas la kompleksecon de la konsumantlogiko kaj faras nenion por pliigi la fortikecon de la legosistemo. Se unu kopio de la konsumanto malaltiĝas pro elektropaneo aŭ simila okazaĵo, tiam la subtraho ĉesas.

La kanona maniero solvi ĉi tiun problemon en Kafka estas uzi bОpli da vandoj.

Dispartigo

Sekcioj estas la ĉefa mekanismo por paraleligi legadon kaj grimpi temon preter la bendolarĝo de ununura maklerista petskribo. Por pli bone kompreni ĉi tion, ni konsideru situacion kie estas temo kun du sekcioj kaj unu konsumanto abonas ĉi tiun temon (Figuro 3-5).

Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka
Figuro 3-5. Unu konsumanto legas el pluraj sekcioj

En ĉi tiu scenaro, la konsumanto ricevas kontrolon de la montriloj egalrilatantaj al ĝia group_id en ambaŭ sekcioj kaj komencas legi mesaĝojn de ambaŭ sekcioj.
Kiam plia konsumanto por la sama group_id estas aldonita al ĉi tiu temo, Kafka reasignas unu el la sekcioj de la unua al la dua konsumanto. Post tio, ĉiu okazo de la konsumanto legos el unu sekcio de la temo (Figuro 3-6).

Por certigi, ke mesaĝoj estas procesitaj paralele en 20 fadenoj, vi bezonas almenaŭ 20 sekciojn. Se estas malpli da sekcioj, vi restos kun konsumantoj, kiuj havas nenion por labori, kiel priskribite pli frue en la diskuto pri ekskluzivaj konsumantoj.

Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 3. Kafka
Figuro 3-6. Du konsumantoj en la sama konsumantogrupo legas el malsamaj sekcioj

Ĉi tiu skemo multe reduktas la kompleksecon de la Kafka makleristo kompare kun la mesaĝdistribuo necesa por konservi la JMS-vicon. Ĉi tie vi ne bezonas zorgi pri la sekvaj punktoj:

  • Kiu konsumanto devus ricevi la sekvan mesaĝon, surbaze de cirkla-subskribolista asigno, nuna kapacito de antaŭprenaj bufroj, aŭ antaŭaj mesaĝoj (kiel por JMS-mesaĝogrupoj).
  • Kiuj mesaĝoj estas senditaj al kiuj konsumantoj kaj ĉu ili devus esti re-liveritaj en kazo de fiasko.

Ĉio, kion la makleristo de Kafka devas fari, estas transdoni mesaĝojn sinsekve al la konsumanto kiam ĉi-lasta petas ilin.

Tamen, la postuloj por paraleligi la provlegadon kaj resendi malsukcesajn mesaĝojn ne foriras - la respondeco pri ili simple pasas de la makleristo al la kliento. Ĉi tio signifas, ke ili devas esti konsiderataj en via kodo.

Sendante mesaĝojn

Estas la respondeco de la produktanto de tiu mesaĝo decidi al kiu sekcio sendi mesaĝon. Por kompreni la mekanismon per kiu ĉi tio estas farita, ni unue devas konsideri, kion ĝuste ni efektive sendas.

Dum en JMS ni uzas mesaĝan strukturon kun metadatenoj (kapoj kaj propraĵoj) kaj korpo enhavanta la utilan ŝarĝon (utila ŝarĝo), en Kafka la mesaĝo estas paro "ŝlosilvaloro". La mesaĝo utila ŝarĝo estas sendita kiel valoro. La ŝlosilo, aliflanke, estas ĉefe uzata por dispartigo kaj devas enhavi komerca logiko specifa ŝlosilopor meti rilatajn mesaĝojn en la saman sekcion.

En Ĉapitro 2, ni diskutis la interretan vetan scenaron kie rilataj eventoj devas esti prilaboritaj en ordo de ununura konsumanto:

  1. La uzantkonto estas agordita.
  2. Mono estas kreditita al la konto.
  3. Veto estas farita, kiu eltiras monon de la konto.

Se ĉiu evento estas mesaĝo afiŝita al temo, tiam la natura ŝlosilo estus la konta ID.
Kiam mesaĝo estas sendita uzante la Kafka Producer API, ĝi estas pasita al sekciofunkcio kiu, donita la mesaĝon kaj la nunan staton de la Kafka areto, resendas la ID de la sekcio al kiu la mesaĝo devus esti sendita. Ĉi tiu funkcio estas efektivigita en Java tra la Partitioner-interfaco.

Ĉi tiu interfaco aspektas jene:

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

La Partitioner-efektivigo uzas la defaŭltan ĝeneraluzeblan haŝalgoritmon super la ŝlosilo por determini la sekcion, aŭ cirkla-subskribolista se neniu ŝlosilo estas precizigita. Ĉi tiu defaŭlta valoro funkcias bone en la plej multaj kazoj. Tamen estonte vi volos skribi vian propran.

Skribante vian propran dispartigan strategion

Ni rigardu ekzemplon, kie vi volas sendi metadatumojn kune kun la mesaĝa ŝarĝo. La utila ŝarĝo en nia ekzemplo estas instrukcio por fari deponejon al la ludkonto. Instrukcio estas io, kion ni ŝatus, ke ni garantiu, ke ni ne estu modifitaj dum transdono kaj volas certigi, ke nur fidinda kontraŭflua sistemo povas iniciati tiun instrukcion. En ĉi tiu kazo, la sendantaj kaj ricevantaj sistemoj konsentas pri la uzo de subskribo por aŭtentikigi la mesaĝon.
En normala JMS, ni simple difinas posedaĵon "mesaĝo-signaturo" kaj aldonas ĝin al la mesaĝo. Tamen Kafka ne provizas al ni mekanismon por transdoni metadatumojn, nur ŝlosilon kaj valoron.

Ĉar la valoro estas banktransiga utila ŝarĝo, kies integrecon ni volas konservi, ni havas neniun elekton ol difini la datumstrukturon por uzi en la ŝlosilo. Supozante, ke ni bezonas kontan ID por dispartigo, ĉar ĉiuj mesaĝoj rilataj al konto devas esti prilaboritaj en ordo, ni elpensos la sekvan JSON-strukturon:

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

Ĉar la valoro de la subskribo varias depende de la utila ŝarĝo, la defaŭlta haĉa strategio de la Partitioner-interfaco ne fidinde grupigos rilatajn mesaĝojn. Tial ni devos skribi nian propran strategion, kiu analizos ĉi tiun ŝlosilon kaj dispartigos la valoron accountId.

Kafka inkluzivas kontrolsumojn por detekti korupton de mesaĝoj en la vendejo kaj havas plenan aron da sekurecaj funkcioj. Eĉ tiel, foje aperas industri-specifaj postuloj, kiel tiu ĉi supre.

La partiga strategio de la uzanto devas certigi, ke ĉiuj rilataj mesaĝoj finiĝas en la sama sekcio. Kvankam ĉi tio ŝajnas simpla, la postulo povas esti malfaciligita pro la graveco de ordigo de rilataj mesaĝoj kaj kiom fiksita la nombro da sekcioj en temo estas.

La nombro da sekcioj en temo povas ŝanĝiĝi kun la tempo, ĉar ili povas esti aldonitaj se trafiko iras preter komencaj atendoj. Tiel, mesaĝŝlosiloj povas esti asociitaj kun la sekcio al kiun ili estis origine senditaj, implicante pecon de ŝtato esti dividita inter produktantokazoj.

Alia faktoro por konsideri estas la ebena distribuado de mesaĝoj tra sekcioj. Tipe, ŝlosiloj ne estas distribuitaj egale tra mesaĝoj, kaj hashfunkcioj ne garantias justan distribuadon de mesaĝoj por malgranda aro de ŝlosiloj.
Gravas noti, ke kiel ajn vi elektas dividi mesaĝojn, la apartigilo mem eble devas esti reuzita.

Konsideru la postulon reprodukti datumojn inter Kafka-aretoj en malsamaj geografiaj lokoj. Por ĉi tiu celo, Kafka venas kun komandlinia ilo nomita MirrorMaker, kiu estas uzata por legi mesaĝojn de unu areto kaj transdoni ilin al alia.

MirrorMaker devas kompreni la ŝlosilojn de la reproduktita temo por konservi relativan ordon inter mesaĝoj dum reproduktado inter aretoj, ĉar la nombro da sekcioj por tiu temo eble ne estas la sama en du aretoj.

Propraj dispartigaj strategioj estas relative maloftaj, ĉar defaŭlta hashing aŭ cirkla robin funkcias bone en la plej multaj scenaroj. Tamen, se vi postulas fortajn mendajn garantiojn aŭ bezonas ĉerpi metadatumojn el utilaj ŝarĝoj, tiam dispartigo estas io, kion vi devus pli detale rigardi.

La skaleblo kaj agado-profitoj de Kafka venas de translokado de iuj el la respondecoj de la tradicia makleristo al la kliento. En ĉi tiu kazo, oni decidas distribui eble rilatajn mesaĝojn inter pluraj konsumantoj laborantaj paralele.

JMS-makleristoj ankaŭ devas trakti tiajn postulojn. Interese, la mekanismo por sendi rilatajn mesaĝojn al la sama konsumanto, efektivigita per JMS Message Groups (vario de la glueca ŝarĝbalancado (SLB) strategio), ankaŭ postulas la sendinto marki mesaĝojn kiel rilataj. En la kazo de JMS, la makleristo respondecas sendi ĉi tiun grupon de rilataj mesaĝoj al unu konsumanto el multaj, kaj transdoni proprieton de la grupo se la konsumanto defalas.

Produktanto-Interkonsentoj

Dispartigo ne estas la nura afero por konsideri dum sendado de mesaĝoj. Ni rigardu la send()-metodojn de la Produktanto-klaso en la Java API:

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

Oni devas tuj rimarki, ke ambaŭ metodoj resendas Estontecon, kio indikas, ke la senda operacio ne estas tuj farita. La rezulto estas, ke mesaĝo (ProducerRecord) estas skribita al la senda bufro por ĉiu aktiva subdisko kaj sendita al la makleristo kiel fona fadeno en la Kafka klienta biblioteko. Kvankam ĉi tio faras aferojn nekredeble rapidaj, ĝi signifas, ke nesperta aplikaĵo povas perdi mesaĝojn se ĝia procezo estas ĉesigita.

Kiel ĉiam, ekzistas maniero fari la sendan operacion pli fidinda koste de agado. La grandeco de ĉi tiu bufro povas esti agordita al 0, kaj la sendanta aplikaĵa fadeno estos devigita atendi ĝis la mesaĝo-transdono al la makleristo finiĝos jene:

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

Pli pri legado de mesaĝoj

Legado de mesaĝoj havas pliajn kompleksaĵojn, pri kiuj oni devas konjekti. Male al la JMS API, kiu povas ruli mesaĝaŭskultanton responde al mesaĝo, la konsumanto Kafka nur balotas. Ni rigardu pli detale la metodon balotado ()uzata por ĉi tiu celo:

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

La revena valoro de la metodo estas ujo strukturo enhavanta plurajn objektojn konsumanta registro de eble pluraj sekcioj. konsumanta registro estas mem posedobjekto por ŝlosil-valora paro kun rilataj metadatenoj, kiel ekzemple la sekcio de kiu ĝi estas derivita.

Kiel diskutite en Ĉapitro 2, ni devas memori kio okazas al mesaĝoj post kiam ili estis sukcese aŭ malsukcese prilaboritaj, ekzemple, se la kliento ne kapablas prilabori la mesaĝon aŭ se ĝi ĉesas. En JMS, tio estis pritraktita per agnoska reĝimo. La makleristo aŭ forigos la sukcese prilaboritan mesaĝon, aŭ retransdonos la krudan aŭ falsan mesaĝon (supozante ke transakcioj estis uzitaj).
Kafka funkcias tre malsame. Mesaĝoj ne estas forigitaj en la makleristo post provlegado, kaj kio okazas ĉe malsukceso estas la respondeco de la provlegado mem.

Kiel ni diris, la konsumanta grupo estas asociita kun la ofseto en la protokolo. La protokolo-pozicio asociita kun ĉi tiu ofseto respondas al la sekva mesaĝo por esti eldonita responde al balotado (). La momento en kiu ĉi tiu kompenso pliiĝas estas decida por legado.

Revenante al la legomodelo diskutita pli frue, mesaĝprilaborado konsistas el tri stadioj:

  1. Prenu mesaĝon por legado.
  2. Prilaboru la mesaĝon.
  3. Konfirmu mesaĝon.

La Kafka-konsumanto venas kun agorda opcio enable.auto.commit. Ĉi tio estas ofte uzata defaŭlta agordo, kiel kutimas ĉe agordoj enhavantaj la vorton "aŭto".

Antaŭ Kafka 0.10, kliento uzanta ĉi tiun opcion sendus la ofseton de la lasta mesaĝo legita en la sekva voko balotado () post prilaborado. Ĉi tio signifis ke ĉiuj mesaĝoj kiuj jam estis alportitaj povus esti reprocesitaj se la kliento jam prilaboris ilin sed estis neatendite detruita antaŭ vokado. balotado (). Ĉar la makleristo ne konservas ajnan staton pri kiom da fojoj mesaĝo estis legita, la sekva konsumanto, kiu prenas tiun mesaĝon, ne scios, ke io malbona okazis. Ĉi tiu konduto estis pseŭdo-transakcia. La kompenso estis farita nur se la mesaĝo estis sukcese prilaborita, sed se la kliento abortus, la makleristo sendus la saman mesaĝon denove al alia kliento. Ĉi tiu konduto kongruis kun la garantio de livero de mesaĝoj "almenaŭ unufoje".

En Kafka 0.10, la klientokodo estis ŝanĝita tiel ke la kommit periode estas ekigita de la klientbiblioteko, kiel agordita auto.commit.interval.ms. Ĉi tiu konduto estas ie inter la modoj JMS AUTO_ACKNOWLEDGE kaj DUPS_OK_ACKNOWLEDGE. Kiam oni uzas aŭtomatan transdonon, mesaĝoj povus esti faritaj sendepende de ĉu ili estis efektive prilaboritaj - tio povus okazi en la kazo de malrapida konsumanto. Se konsumanto abortus, mesaĝoj estus prenitaj fare de la venonta konsumanto, komencante ĉe la farita pozicio, kiu povus rezultigi maltrafitan mesaĝon. En ĉi tiu kazo, Kafka ne perdis la mesaĝojn, la legokodo simple ne prilaboris ilin.

Ĉi tiu reĝimo havas la saman promeson kiel en versio 0.9: mesaĝoj povas esti prilaboritaj, sed se ĝi malsukcesas, la kompenso eble ne estas farita, eble kaŭzante liveradon duobliĝi. Ju pli da mesaĝoj vi ricevas dum ekzekuto balotado (), des pli ĉi tiu problemo.

Kiel diskutite en "Legado de Mesaĝoj el Vico" sur paĝo 21, ne ekzistas unufoja livero de mesaĝo en mesaĝsistemo kiam malsukcesaj reĝimoj estas konsiderataj.

En Kafka, estas du manieroj fari (fari) ofseton (offseton): aŭtomate kaj permane. En ambaŭ kazoj, mesaĝoj povas esti prilaboritaj plurfoje se la mesaĝo estis prilaborita sed malsukcesis antaŭ la transdono. Vi ankaŭ povas elekti tute ne prilabori la mesaĝon se la transdono okazis en la fono kaj via kodo estis kompletigita antaŭ ol ĝi povus esti procesita (eble en Kafka 0.9 kaj pli frue).

Vi povas kontroli la manan kompensan procezon en la Kafka-konsumanto API per agordo de la parametro enable.auto.commit al falsa kaj eksplicite voki unu el la sekvaj metodoj:

void commitSync();
void commitAsync();

Se vi volas prilabori la mesaĝon "almenaŭ unufoje", vi devas fari la ofseton permane per commitSync()per ekzekuto de ĉi tiu komando tuj post prilaborado de la mesaĝoj.

Ĉi tiuj metodoj ne permesas ke mesaĝoj estu agnoskitaj antaŭ ol ili estas prilaboritaj, sed ili faras nenion por elimini eblajn pretigprokrastojn donante la aspekton esti transakciaj. Ne estas transakcioj en Kafka. La kliento ne havas la kapablon fari la jenon:

  • Aŭtomate reiru falsan mesaĝon. Konsumantoj mem devas pritrakti esceptojn de problemaj utilaj ŝarĝoj kaj malfunkcioj de backend, ĉar ili ne povas fidi je la makleristo por re-liveri mesaĝojn.
  • Sendu mesaĝojn al pluraj temoj en unu atoma operacio. Kiel ni vidos baldaŭ, kontrolo de malsamaj temoj kaj sekcioj povas loĝi sur malsamaj maŝinoj en la Kafka-grupo, kiuj ne kunordigas transakciojn kiam ili estas senditaj. En la momento de ĉi tiu skribado, iu laboro estis farita por ebligi tion kun la KIP-98.
  • Asociu legi unu mesaĝon de unu temo kun sendado de alia mesaĝo al alia temo. Denove, la arkitekturo de Kafka dependas de multaj sendependaj maŝinoj funkcianta kiel unu buso kaj neniu provo estas farita por kaŝi tion. Ekzemple, ne ekzistas API-komponentoj, kiuj permesus vin ligi konsumanto и Produktanto en transakcio. En JMS, ĉi tio estas disponigita per la objekto kunsidoel kiuj estas kreitaj Mesaĝproduktantoj и MesaĝoKonsumantoj.

Se ni ne povas fidi je transakcioj, kiel ni povas provizi semantikon pli proksiman al tiuj provizitaj de tradiciaj mesaĝaj sistemoj?

Se ekzistas ebleco ke la kompenso de la konsumanto povas pliiĝi antaŭ ol la mesaĝo estis prilaborita, kiel ekzemple dum konsumantkraŝo, tiam la konsumanto havas neniun manieron scii ĉu ĝia konsumantogrupo sopiris la mesaĝon kiam ĝi estas asignita sekcio. Do unu strategio estas rebobeni la ofseton al la antaŭa pozicio. La Kafka-konsumanto API disponigas la sekvajn metodojn por tio:

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

Metodo serĉi () povas esti uzata kun metodo
offsetsForTimes(Mapo tempomarkojAl Serĉi) rebobeni al stato je iu specifa punkto en la pasinteco.

Implicite, uzi ĉi tiun aliron signifas, ke estas tre verŝajne ke iuj mesaĝoj, kiuj antaŭe estis prilaboritaj, estos legitaj kaj procesitaj denove. Por eviti tion, ni povas uzi idempotentan legadon, kiel priskribite en Ĉapitro 4, por konservi trakon de antaŭe viditaj mesaĝoj kaj forigi duplikatojn.

Alternative, via konsumanta kodo povas esti simpla, kondiĉe ke mesaĝo perdo aŭ duobligo estas akceptebla. Kiam ni rigardas uzkazojn por kiuj Kafka estas ofte uzata, kiel pritraktado de protokolaj eventoj, metrikoj, klakspurado ktp., ni rimarkas, ke la perdo de individuaj mesaĝoj verŝajne ne havos gravan efikon al ĉirkaŭaj aplikoj. En tiaj kazoj, la defaŭltaj valoroj estas perfekte akcepteblaj. Aliflanke, se via aplikaĵo bezonas sendi pagojn, vi devas zorge prizorgi ĉiun individuan mesaĝon. Ĉio dependas de kunteksto.

Personaj observoj montras, ke kiam la intenseco de mesaĝoj pliiĝas, la valoro de ĉiu individua mesaĝo malpliiĝas. Grandaj mesaĝoj tendencas esti valoraj kiam rigardataj en agregita formo.

Alta Havebleco

La aliro de Kafka al alta havebleco estas tre malsama de la aliro de ActiveMQ. Kafka estas desegnita ĉirkaŭ skalaj grupoj kie ĉiuj makleristaj petskriboj ricevas kaj distribuas mesaĝojn samtempe.

Kafka areto konsistas el multoblaj makleristaj petskriboj kurantaj sur malsamaj serviloj. Kafka estis dizajnita por funkcii per ordinara memstara aparataro, kie ĉiu nodo havas sian propran dediĉitan stokadon. La uzo de reto alkroĉita stokado (SAN) ne estas rekomendita ĉar pluraj komputaj nodoj povas konkuri pri tempo.Ыe stokado intervaloj kaj krei konfliktojn.

Kafka estas ĉiam sur sistemo. Multaj grandaj uzantoj de Kafka neniam fermas siajn aretojn kaj la programaro ĉiam ĝisdatiĝas per sinsekva rekomenco. Ĉi tio estas atingita garantiante kongruon kun la antaŭa versio por mesaĝoj kaj interagoj inter makleristoj.

Makleristoj konektitaj al servila aro ZooKeeper, kiu funkcias kiel agorda datuma registro kaj estas uzata por kunordigi la rolojn de ĉiu makleristo. ZooKeeper mem estas distribuita sistemo kiu disponigas altan haveblecon tra la reproduktado de informoj per establado kvorumo.

En la baza kazo, temo estas kreita en Kafka areto kun la sekvaj trajtoj:

  • La nombro da sekcioj. Kiel diskutite antaŭe, la preciza valoro uzata ĉi tie dependas de la dezirata nivelo de paralela legado.
  • La reproduktadfaktoro (faktoro) determinas kiom da makleristokazoj en la areto devus enhavi protokolojn por ĉi tiu sekcio.

Uzante ZooKeepers por kunordigo, Kafka provas juste distribui novajn sekciojn inter la makleristoj en la areto. Ĉi tio estas farita de ununura kazo kiu funkcias kiel Regilo.

Ĉe rultempo por ĉiu temsekcio Regilo atribui rolojn al makleristo gvidanto (gvidanto, majstro, prezentisto) kaj sekvantoj (sekvantoj, sklavoj, subuloj). La makleristo, agante kiel la gvidanto por ĉi tiu sekcio, respondecas ricevi ĉiujn mesaĝojn senditajn al ĝi de la produktantoj kaj distribui la mesaĝojn al la konsumantoj. Kiam mesaĝoj estas senditaj al temosekcio, ili estas reproduktitaj al ĉiuj makleristnodoj agantaj kiel sekvantoj por tiu sekcio. Ĉiu nodo enhavanta protokolojn por sekcio estas vokita kopio. Makleristo povas agi kiel gvidanto por iuj sekcioj kaj kiel sekvanto por aliaj.

Sekvanto enhavanta ĉiujn mesaĝojn tenitajn fare de la gvidanto estas vokita sinkronigita kopio (kopio kiu estas en sinkronigita stato, en-sinkronigita kopio). Se makleristo aganta kiel gvidanto por sekcio malsukcesas, ĉiu makleristo kiu estas ĝisdatigita aŭ sinkronigita por tiu sekcio povas transpreni la gvidan rolon. Ĝi estas nekredeble daŭrigebla dezajno.

Parto de la produktanto-agordo estas la parametro akoj, kiu determinas kiom da kopioj devas agnoski (konfirmi) ricevon de mesaĝo antaŭ ol la aplikaĵa fadeno daŭre sendas: 0, 1, aŭ ĉiuj. Se agordita al ĉiuj, tiam kiam mesaĝo estas ricevita, la gvidanto sendos konfirmon reen al la produktanto tuj kiam ĝi ricevas konfirmojn (rekonojn) de la rekordo de pluraj signalvortoj (inkluzive de si mem) difinitaj per la temo fikso. min.insync.replicas (defaŭlte 1). Se la mesaĝo ne povas esti sukcese reproduktita, tiam la produktanto ĵetos aplikaĵescepton (NotEnoughReplicasNot EnoughReplicasAfterAppend).

Tipa agordo kreas temon kun reproduktadfaktoro de 3 (1 gvidanto, 2 sekvantoj per sekcio) kaj la parametro min.insync.replicas estas agordita al 2. En ĉi tiu kazo, la areto permesos al unu el la makleristoj administrantaj la teman subdiskon sen tuŝi klientajn aplikojn.

Ĉi tio revenas nin al la jam konata kompromiso inter rendimento kaj fidindeco. Reproduktado okazas koste de plia atendotempo por konfirmoj (rekonoj) de sekvantoj. Kvankam, ĉar ĝi funkcias paralele, reproduktado al almenaŭ tri nodoj havas la saman efikecon kiel du (ignorante la pliiĝon en reta bendolarĝa uzokutimo).

Uzante ĉi tiun reproduktadskemon, Kafka lerte evitas la bezonon fizike skribi ĉiun mesaĝon al disko kun la operacio. sinkronigi (). Ĉiu mesaĝo sendita de la produktanto estos skribita al la partiga protokolo, sed kiel diskutite en Ĉapitro 2, skribi al dosiero estas komence farita en la bufro de la operaciumo. Se ĉi tiu mesaĝo estas reproduktita al alia Kafka-instanco kaj estas en ĝia memoro, la perdo de la gvidanto ne signifas ke la mesaĝo mem estis perdita - ĝi povas esti transprenita per sinkronigita kopio.
Rifuzo plenumi la operacion sinkronigi () signifas, ke Kafka povas ricevi mesaĝojn tiel rapide kiel ĝi povas skribi ilin al memoro. Male, ju pli longe vi povas eviti flui memoron al disko, des pli bone. Tial, ne estas malofte, ke Kafka makleristoj estas asignitaj 64 GB aŭ pli da memoro. Ĉi tiu memoruzo signifas, ke ununura Kafka-instanco povas facile funkcii kun rapidecoj multaj miloj da fojoj pli rapide ol tradicia mesaĝmakleristo.

Kafka ankaŭ povas esti agordita por apliki la operacion sinkronigi () al mesaĝpakaĵoj. Ĉar ĉio en Kafka estas pak-orientita, ĝi fakte funkcias sufiĉe bone por multaj uzkazoj kaj estas utila ilo por uzantoj kiuj postulas tre fortajn garantiojn. Granda parto de la pura agado de Kafka venas de la mesaĝoj, kiuj estas senditaj al la makleristo kiel pakaĵoj kaj ke ĉi tiuj mesaĝoj estas legitaj de la makleristo en sinsekvaj blokoj uzante nula kopio operacioj (operacioj dum kiuj la tasko kopii datumojn de unu memorareo al alia ne estas plenumita). Ĉi-lasta estas granda rendimento kaj rimeda gajno kaj nur eblas per la uzo de subesta protokolo-datumstrukturo, kiu difinas la dispartigan skemon.

Multe pli bona agado estas ebla en Kafka areto ol kun ununura Kafka makleristo, ĉar temaj sekcioj povas malgrandigi tra multaj apartaj maŝinoj.

Rezultoj

En ĉi tiu ĉapitro, ni rigardis kiel la Kafka-arkitekturo reimagas la rilaton inter klientoj kaj makleristoj por provizi nekredeble fortikan mesaĝan dukton, kun trafluo multajn fojojn pli granda ol tiu de konvencia mesaĝa makleristo. Ni diskutis la funkciojn, kiujn ĝi uzas por atingi ĉi tion, kaj mallonge rigardis la arkitekturon de aplikaĵoj, kiuj provizas ĉi tiun funkcion. En la sekva ĉapitro, ni rigardos oftajn problemojn, kiujn mesaĝ-bazitaj aplikaĵoj bezonas por solvi kaj diskuti strategiojn por trakti ilin. Ni finos la ĉapitron skizante kiel paroli pri mesaĝaj teknologioj ĝenerale, por ke vi povu taksi ilian taŭgecon por viaj uzkazoj.

Antaŭa tradukita parto: Kompreni mesaĝajn makleristojn. Lernante la mekanikon de mesaĝado kun ActiveMQ kaj Kafka. Ĉapitro 1

Traduko farita: tele.gg/mezo_java

Daŭrigota…

Nur registritaj uzantoj povas partopreni la enketon. Ensaluti, bonvolu.

Ĉu Kafka estas uzata en via organizo?

  • Jes

  • Neniu

  • Antaŭe uzata, nun ne

  • Ni planas uzi

38 uzantoj voĉdonis. 8 uzantoj sindetenis.

fonto: www.habr.com

Aldoni komenton