Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka

Voortsetting van die vertaling van 'n klein boek:
Verstaan ​​boodskapmakelaars
skrywer: Jakub Korab, uitgewer: O'Reilly Media, Inc., datum van publikasie: Junie 2017, ISBN: 9781492049296.

Vorige vertaalde deel: Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 1 Inleiding

HOOFSTUK 3

Kafka

Kafka is deur LinkedIn ontwikkel om sommige van die beperkings van tradisionele boodskapmakelaars te omseil en om te verhoed dat verskeie boodskapmakelaars opgestel moet word vir verskillende punt-tot-punt-interaksies, wat in hierdie boek beskryf word onder "Op- en uitskaal" op bladsy 28 Gebruiksgevalle LinkedIn het grootliks staatgemaak op eenrigting-inname van baie groot hoeveelhede data, soos bladsyklikke en toegangslogboeke, terwyl dit steeds toegelaat word dat daardie data deur verskeie stelsels gebruik word sonder om die produktiwiteit van produsente of ander verbruikers te beïnvloed. Trouens, die rede waarom Kafka bestaan, is om die soort boodskapargitektuur te kry wat die Universal Data Pipeline beskryf.

Gegewe hierdie uiteindelike doelwit het ander vereistes natuurlik ontstaan. Kafka moet:

  • Wees uiters vinnig
  • Verskaf meer bandwydte wanneer jy met boodskappe werk
  • Ondersteun uitgewer-intekenaar en punt-tot-punt-modelle
  • Moenie stadiger met die byvoeging van verbruikers nie. Byvoorbeeld, die prestasie van beide die tou en die onderwerp in ActiveMQ verswak namate die aantal verbruikers op die bestemming groei.
  • Wees horisontaal skaalbaar; as een makelaar wat boodskappe aanhou dit net teen maksimum skyfspoed kan doen, dan maak dit sin om verder te gaan as 'n enkele makelaar-instansie om prestasie te verhoog
  • Beperk toegang tot die berging en herwinning van boodskappe

Om dit alles te bereik, het Kafka 'n argitektuur aangeneem wat die rolle en verantwoordelikhede van kliënte en boodskapmakelaars herdefinieer. Die JMS-model is baie makelaar-georiënteerd, waar die makelaar verantwoordelik is vir die verspreiding van boodskappe en kliënte hoef net bekommerd te wees oor die stuur en ontvang van boodskappe. Kafka, aan die ander kant, is kliëntgesentreerd, met die kliënt wat baie van die kenmerke van 'n tradisionele makelaar aanneem, soos billike verspreiding van relevante boodskappe aan verbruikers, in ruil vir 'n uiters vinnige en skaalbare makelaar. Vir mense wat met tradisionele boodskapstelsels gewerk het, vereis werk met Kafka 'n fundamentele verandering van gedagtes.
Hierdie ingenieursrigting het gelei tot die skepping van 'n boodskap-infrastruktuur wat in staat is om deurset met baie ordes van grootte te verhoog in vergelyking met 'n konvensionele makelaar. Soos ons sal sien, kom hierdie benadering met trade-offs, wat beteken dat Kafka nie geskik is vir sekere soorte werkladings en geïnstalleerde sagteware nie.

Verenigde bestemmingsmodel

Om aan die vereistes hierbo beskryf te voldoen, het Kafka publiseer-inteken en punt-tot-punt boodskappe gekombineer onder een soort bestemming − onderwerp. Dit is verwarrend vir mense wat met boodskapstelsels gewerk het, waar die woord "onderwerp" verwys na 'n uitsaaimeganisme waaruit (van die onderwerp) lees nie duursaam is nie. Kafka-onderwerpe moet as 'n hibriede bestemmingstipe beskou word, soos gedefinieer in die inleiding tot hierdie boek.

Vir die res van hierdie hoofstuk, tensy ons uitdruklik anders sê, sal die term "onderwerp" na 'n Kafka-onderwerp verwys.

Om ten volle te verstaan ​​hoe onderwerpe optree en watter waarborge dit bied, moet ons eers kyk hoe dit in Kafka geïmplementeer word.
Elke onderwerp in Kafka het sy eie logboek.
Produsente wat boodskappe aan Kafka stuur, skryf na hierdie logboek, en verbruikers lees uit die log met behulp van wysers wat voortdurend vorentoe beweeg. Kafka vee periodiek die oudste dele van die log uit, of die boodskappe in daardie dele gelees is of nie. ’n Sentrale deel van Kafka se ontwerp is dat die makelaar nie omgee of boodskappe gelees word of nie – dit is die kliënt se verantwoordelikheid.

Die terme "log" en "wyser" verskyn nie in nie Kafka dokumentasie. Hierdie bekende terme word hier gebruik om begrip te help.

Hierdie model is heeltemal anders as ActiveMQ, waar boodskappe van alle rye in dieselfde logboek gestoor word, en die makelaar merk die boodskappe as uitgevee nadat dit gelees is.
Kom ons delf nou 'n bietjie dieper en kyk na die onderwerplog in meer besonderhede.
Die Kafka-logboek bestaan ​​uit verskeie partisies (Figuur 3-1). Kafka waarborg streng ordening in elke partisie. Dit beteken dat boodskappe wat in 'n sekere volgorde na die partisie geskryf is, in dieselfde volgorde gelees sal word. Elke partisie word geïmplementeer as 'n rollende loglêer wat bevat 'n subset (subset) van alle boodskappe wat deur die vervaardigers na die onderwerp gestuur word. Die geskepte onderwerp bevat by verstek een partisie. Die idee van partisies is die sentrale idee van Kafka vir horisontale skaal.

Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka
Figuur 3-1. Kafka-afskortings

Wanneer 'n vervaardiger 'n boodskap na 'n Kafka-onderwerp stuur, besluit hy na watter partisie om die boodskap te stuur. Ons sal later in meer besonderhede hierna kyk.

Lees boodskappe

Die kliënt wat die boodskappe wil lees, bestuur 'n benoemde wyser wat genoem word verbruikersgroep, wat wys op verreken boodskappe in die partisie. 'n Verskuiwing is 'n inkrementele posisie wat by 0 begin aan die begin van 'n partisie. Hierdie verbruikersgroep, waarna verwys word in die API via die gebruikergedefinieerde group_id, stem ooreen met een logiese verbruiker of stelsel.

Die meeste boodskapstelsels lees data vanaf die bestemming deur verskeie gevalle en drade te gebruik om boodskappe parallel te verwerk. Daar sal dus gewoonlik baie verbruikersgevalle wees wat dieselfde verbruikersgroep deel.

Die leesprobleem kan soos volg voorgestel word:

  • Onderwerp het veelvuldige partisies
  • Veelvuldige groepe verbruikers kan 'n onderwerp op dieselfde tyd gebruik
  • 'n Groep verbruikers kan verskeie afsonderlike gevalle hê

Dit is 'n nie-triviale baie-tot-baie-probleem. Om te verstaan ​​hoe Kafka verhoudings tussen verbruikersgroepe, verbruikersgevalle en partisies hanteer, kom ons kyk na 'n reeks progressief meer komplekse leesscenario's.

Verbruikers en verbruikersgroepe

Kom ons neem as 'n beginpunt 'n onderwerp met een partisie (Figuur 3-2).

Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka
Figuur 3-2. Verbruiker lees vanaf partisie

Wanneer 'n verbruiker-instansie met sy eie group_id aan hierdie onderwerp koppel, word 'n leespartisie en 'n offset in daardie partisie toegeken. Die posisie van hierdie offset is instelbaar in die kliënt as 'n wyser na die mees onlangse posisie (nuutste boodskap) of vroegste posisie (oudste boodskap). Die verbruiker versoek (peilings) boodskappe van die onderwerp, wat veroorsaak dat hulle opeenvolgend uit die log gelees word.
Die verrekenposisie word gereeld aan Kafka teruggebind en as boodskappe in 'n interne onderwerp gestoor _verbruiker_offsets. Lees boodskappe word steeds nie uitgevee nie, anders as 'n gewone makelaar, en die kliënt kan die verrekening terugspoel om reeds bekykte boodskappe weer te verwerk.

Wanneer 'n tweede logiese verbruiker verbind met 'n ander group_id, bestuur dit 'n tweede wyser wat onafhanklik is van die eerste (Figuur 3-3). Dus tree 'n Kafka-onderwerp op soos 'n tou waar daar een verbruiker is en soos 'n normale publiseer-subscribe (pub-sub) onderwerp waarop verskeie verbruikers inteken, met die bykomende voordeel dat alle boodskappe gestoor word en verskeie kere verwerk kan word.

Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka
Figuur 3-3. Twee verbruikers in verskillende verbruikersgroepe lees vanaf dieselfde partisie

Verbruikers in 'n verbruikersgroep

Wanneer een verbruikersinstansie data vanaf 'n partisie lees, het dit volle beheer oor die wyser en verwerk boodskappe soos beskryf in die vorige afdeling.
As verskeie gevalle van verbruikers met dieselfde group_id aan 'n onderwerp met een partisie gekoppel is, sal die geval wat laas gekoppel is beheer oor die wyser gegee word en van daardie oomblik af sal dit alle boodskappe ontvang (Figuur 3-4).

Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka
Figuur 3-4. Twee verbruikers in dieselfde verbruikersgroep lees vanaf dieselfde partisie

Hierdie wyse van verwerking, waarin die aantal verbruikersgevalle die aantal partisies oorskry, kan beskou word as 'n soort eksklusiewe verbruiker. Dit kan nuttig wees as jy "aktief-passiewe" (of "warm-warm") groepering van jou verbruikersgevalle benodig, hoewel dit baie meer tipies is om verskeie verbruikers in parallel ("aktief-aktief" of "warm-warm") te laat loop. verbruikers In bystand.

Hierdie boodskapverspreidingsgedrag wat hierbo beskryf word, kan verbasend wees in vergelyking met hoe 'n normale JMS-tou optree. In hierdie model sal boodskappe wat na die tou gestuur word eweredig tussen die twee verbruikers versprei word.

Meestal, wanneer ons veelvuldige gevalle van verbruikers skep, doen ons dit óf om boodskappe parallel te verwerk, óf om die spoed van lees te verhoog, óf om die stabiliteit van die leesproses te verhoog. Aangesien slegs een verbruikersinstansie data van 'n partisie op 'n slag kan lees, hoe word dit in Kafka bereik?

Een manier om dit te doen is om 'n enkele verbruikersinstansie te gebruik om al die boodskappe te lees en dit na die draadpoel deur te gee. Terwyl hierdie benadering verwerkingsdeurset verhoog, verhoog dit die kompleksiteit van die verbruikerslogika en doen dit niks om die robuustheid van die leesstelsel te verhoog nie. As een kopie van die verbruiker afgaan as gevolg van 'n kragonderbreking of soortgelyke gebeurtenis, dan stop die aftrekking.

Die kanonieke manier om hierdie probleem in Kafka op te los, is om bОmeer partisies.

Afskorting

Partisies is die hoofmeganisme om 'n onderwerp te parallel lees en te skaal buite die bandwydte van 'n enkele makelaarinstansie. Om dit beter te verstaan, kom ons kyk na 'n situasie waar daar 'n onderwerp met twee partisies is en een verbruiker op hierdie onderwerp inteken (Figuur 3-5).

Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka
Figuur 3-5. Een verbruiker lees vanaf verskeie partisies

In hierdie scenario word die verbruiker beheer gegee oor die wysers wat ooreenstem met sy group_id in beide partisies en begin boodskappe van beide partisies lees.
Wanneer 'n bykomende verbruiker vir dieselfde group_id by hierdie onderwerp gevoeg word, hertoeken Kafka een van die partisies van die eerste na die tweede verbruiker. Daarna sal elke geval van die verbruiker van een partisie van die onderwerp (Figuur 3-6).

Om te verseker dat boodskappe parallel in 20 drade verwerk word, benodig jy ten minste 20 partisies. As daar minder partisies is, sal jy gelaat word met verbruikers wat niks het om aan te werk nie, soos vroeër beskryf in die bespreking van eksklusiewe verbruikers.

Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 3. Kafka
Figuur 3-6. Twee verbruikers in dieselfde verbruikersgroep lees vanaf verskillende partisies

Hierdie skema verminder die kompleksiteit van die Kafka-makelaar aansienlik in vergelyking met die boodskapverspreiding wat nodig is om die JMS-tou te handhaaf. Hier hoef jy nie bekommerd te wees oor die volgende punte nie:

  • Watter verbruiker moet die volgende boodskap ontvang, gebaseer op round-robin-toekenning, huidige kapasiteit van voorafhaalbuffers, of vorige boodskappe (soos vir JMS-boodskapgroepe).
  • Watter boodskappe word aan watter verbruikers gestuur en of dit weer afgelewer moet word in geval van mislukking.

Al wat die Kafka-makelaar hoef te doen is om boodskappe opeenvolgend aan die verbruiker deur te gee wanneer laasgenoemde dit versoek.

Die vereistes vir die parallellisering van die proeflees en die herstuur van mislukte boodskappe gaan egter nie weg nie – die verantwoordelikheid daarvoor gaan eenvoudig van die makelaar na die kliënt oor. Dit beteken dat hulle in u kode in ag geneem moet word.

Stuur boodskappe

Dit is die verantwoordelikheid van die vervaardiger van daardie boodskap om te besluit na watter partisie om 'n boodskap te stuur. Om die meganisme waardeur dit gedoen word te verstaan, moet ons eers oorweeg wat presies ons eintlik stuur.

Terwyl ons in JMS 'n boodskapstruktuur gebruik met metadata (opskrifte en eienskappe) en 'n liggaam wat die loonvrag (loonvrag) bevat, is die boodskap in Kafka paar "sleutel-waarde". Die boodskaploonvrag word as 'n waarde gestuur. Die sleutel, aan die ander kant, word hoofsaaklik gebruik vir partisionering en moet bevat besigheidslogika spesifieke sleutelom verwante boodskappe in dieselfde partisie te plaas.

In Hoofstuk 2 het ons die aanlyn weddery-scenario bespreek waar verwante gebeurtenisse in volgorde deur 'n enkele verbruiker verwerk moet word:

  1. Die gebruikersrekening is gekonfigureer.
  2. Geld word op die rekening gekrediteer.
  3. 'n Weddenskap word gemaak wat geld uit die rekening onttrek.

As elke gebeurtenis 'n boodskap is wat na 'n onderwerp geplaas is, sal die natuurlike sleutel die rekening-ID wees.
Wanneer 'n boodskap met behulp van die Kafka Producer API gestuur word, word dit na 'n partisiefunksie oorgedra wat, gegewe die boodskap en die huidige toestand van die Kafka-groepering, die ID van die partisie terugstuur waarna die boodskap gestuur moet word. Hierdie kenmerk word in Java geïmplementeer deur die Partitioner-koppelvlak.

Hierdie koppelvlak lyk soos volg:

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

Die Partitioner implementering gebruik die verstek algemene-doel hashing algoritme oor die sleutel om die partisie te bepaal, of round-robin as geen sleutel gespesifiseer is nie. Hierdie verstekwaarde werk in die meeste gevalle goed. In die toekoms sal jy egter jou eie wil skryf.

Skryf jou eie partisiestrategie

Kom ons kyk na 'n voorbeeld waar jy metadata saam met die boodskaploonvrag wil stuur. Die loonvrag in ons voorbeeld is 'n instruksie om 'n deposito op die spelrekening te maak. 'n Instruksie is iets waarvan ons gewaarborg wil hê dat dit nie tydens transmissie gewysig word nie en wil seker wees dat slegs 'n betroubare stroomop-stelsel daardie instruksie kan inisieer. In hierdie geval stem die stuur- en ontvangstelsels ooreen oor die gebruik van 'n handtekening om die boodskap te staaf.
In normale JMS, definieer ons eenvoudig 'n "boodskap handtekening" eienskap en voeg dit by die boodskap. Kafka voorsien ons egter nie van 'n meganisme om metadata deur te gee nie, slegs 'n sleutel en 'n waarde.

Aangesien die waarde 'n bankoordragloonvrag is wie se integriteit ons wil bewaar, het ons geen ander keuse as om die datastruktuur te definieer om in die sleutel te gebruik nie. As ons aanvaar dat ons 'n rekening-ID nodig het vir partisionering, aangesien alle boodskappe wat met 'n rekening verband hou, in volgorde verwerk moet word, sal ons met die volgende JSON-struktuur vorendag kom:

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

Omdat die waarde van die handtekening sal wissel na gelang van die loonvrag, sal die verstek hashstrategie van die Partitioner-koppelvlak nie verwante boodskappe betroubaar groepeer nie. Daarom sal ons ons eie strategie moet skryf wat hierdie sleutel sal ontleed en die rekeningId-waarde sal partisieer.

Kafka sluit kontrolesomme in om korrupsie van boodskappe in die winkel op te spoor en het 'n volledige stel sekuriteitskenmerke. Desondanks verskyn bedryfspesifieke vereistes, soos die een hierbo, soms.

Die gebruiker se partisiestrategie moet verseker dat alle verwante boodskappe in dieselfde partisie beland. Alhoewel dit eenvoudig lyk, kan die vereiste gekompliseer word deur die belangrikheid om verwante plasings te bestel en hoe vas die aantal partisies in 'n onderwerp is.

Die aantal partisies in 'n onderwerp kan met verloop van tyd verander, aangesien hulle bygevoeg kan word as die verkeer bo aanvanklike verwagtinge gaan. Boodskapsleutels kan dus geassosieer word met die partisie waarna hulle oorspronklik gestuur is, wat impliseer dat 'n deel van die toestand tussen produsentegevalle gedeel moet word.

Nog 'n faktor om te oorweeg is die eweredige verspreiding van boodskappe oor partisies. Tipies word sleutels nie eweredig oor boodskappe versprei nie, en hash-funksies waarborg nie 'n regverdige verspreiding van boodskappe vir 'n klein stel sleutels nie.
Dit is belangrik om daarop te let dat jy ook al kies om boodskappe te verdeel, die skeier self sal dalk hergebruik moet word.

Oorweeg die vereiste om data tussen Kafka-klusters in verskillende geografiese liggings te herhaal. Vir hierdie doel kom Kafka met 'n opdragreëlinstrument genaamd MirrorMaker, wat gebruik word om boodskappe van een groepie te lees en na 'n ander oor te dra.

MirrorMaker moet die sleutels van die gerepliseerde onderwerp verstaan ​​om relatiewe orde tussen boodskappe te handhaaf wanneer tussen groepe repliseer, aangesien die aantal partisies vir daardie onderwerp dalk nie dieselfde is in twee groepe nie.

Pasgemaakte partisiestrategieë is relatief skaars, aangesien verstek-hashing of round robin goed werk in die meeste scenario's. As u egter sterk bestelwaarborge benodig of metadata uit loonvragte moet onttrek, dan is partisionering iets waarna u van nader moet kyk.

Die skaalbaarheid en prestasievoordele van Kafka kom van die aflaai van sommige van die verantwoordelikhede van die tradisionele makelaar aan die kliënt. In hierdie geval word 'n besluit geneem om potensieel verwante boodskappe te versprei onder verskeie verbruikers wat parallel werk.

JMS-makelaars moet ook sulke vereistes hanteer. Interessant genoeg vereis die meganisme vir die stuur van verwante boodskappe aan dieselfde verbruiker, geïmplementeer deur JMS Message Groups ('n variasie op die taai lasbalansering (SLB) strategie), ook van die sender om boodskappe as verwant te merk. In die geval van JMS is die makelaar verantwoordelik vir die stuur van hierdie groep verwante boodskappe aan een verbruiker uit baie, en die oordrag van eienaarskap van die groep as die verbruiker afval.

Produsenteooreenkomste

Partisionering is nie die enigste ding om te oorweeg wanneer boodskappe gestuur word nie. Kom ons kyk na die send()-metodes van die Producer-klas in die Java API:

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

Daar moet dadelik kennis geneem word dat beide metodes Toekoms terugstuur, wat aandui dat die stuuroperasie nie onmiddellik uitgevoer word nie. Die gevolg is dat 'n boodskap (ProducerRecord) na die stuurbuffer vir elke aktiewe partisie geskryf word en na die makelaar gestuur word as 'n agtergronddraad in die Kafka-kliëntbiblioteek. Alhoewel dit dinge ongelooflik vinnig maak, beteken dit dat 'n onervare toepassing boodskappe kan verloor as die proses gestop word.

Soos altyd is daar 'n manier om die stuuroperasie meer betroubaar te maak ten koste van prestasie. Die grootte van hierdie buffer kan op 0 gestel word, en die stuurtoepassingsdraad sal gedwing word om te wag totdat die boodskapoordrag na die makelaar voltooi is, soos volg:

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

Meer oor die lees van boodskappe

Die lees van boodskappe het bykomende kompleksiteite waaroor bespiegel moet word. Anders as die JMS API, wat 'n boodskapluisteraar in reaksie op 'n boodskap kan laat loop, is die Verbruiker Kafka slegs meningspeilings. Kom ons kyk na die metode van naderby meningpeiling()vir hierdie doel gebruik:

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

Die terugkeerwaarde van die metode is 'n houerstruktuur wat veelvuldige voorwerpe bevat verbruikersrekord van moontlik verskeie partisies. verbruikersrekord is self 'n houerobjek vir 'n sleutelwaarde-paar met gepaardgaande metadata, soos die partisie waaruit dit afgelei is.

Soos bespreek in Hoofstuk 2, moet ons in gedagte hou wat met boodskappe gebeur nadat dit suksesvol of onsuksesvol verwerk is, byvoorbeeld as die kliënt nie die boodskap kan verwerk nie of as dit afbreek. In JMS is dit deur 'n erkenningsmodus hanteer. Die makelaar sal óf die suksesvol verwerkte boodskap uitvee, óf die rou of vals boodskap weer aflewer (met die veronderstelling dat transaksies gebruik is).
Kafka werk baie anders. Boodskappe word nie in die makelaar uitgevee na proeflees nie, en wat by mislukking gebeur, is die verantwoordelikheid van die proefleeskode self.

Soos ons gesê het, word die verbruikersgroep geassosieer met die verrekening in die logboek. Die logposisie wat met hierdie afwyking geassosieer word, stem ooreen met die volgende boodskap wat in reaksie op uitgereik moet word meningpeiling(). Die tydstip wanneer hierdie verrekening toeneem, is deurslaggewend vir lees.

Om terug te keer na die leesmodel wat vroeër bespreek is, bestaan ​​boodskapverwerking uit drie fases:

  1. Kry 'n boodskap om te lees.
  2. Verwerk die boodskap.
  3. Bevestig boodskap.

Die Kafka-verbruiker kom met 'n konfigurasie-opsie enable.auto.commit. Dit is 'n gereeld gebruikte verstekinstelling, soos algemeen is met instellings wat die woord "outo" bevat.

Voor Kafka 0.10, sal 'n kliënt wat hierdie opsie gebruik die kompensasie stuur van die laaste boodskap wat op die volgende oproep gelees is meningpeiling() na verwerking. Dit het beteken dat enige boodskappe wat reeds afgehaal is, herverwerk kon word as die kliënt dit reeds verwerk het, maar onverwags vernietig is voordat hy gebel het meningpeiling(). Omdat die makelaar geen staat hou oor hoeveel keer 'n boodskap gelees is nie, sal die volgende verbruiker wat daardie boodskap ophaal, nie weet dat iets sleg gebeur het nie. Hierdie gedrag was pseudo-transaksies. Die verrekening is slegs gepleeg as die boodskap suksesvol verwerk is, maar as die kliënt geaborteer het, sou die makelaar dieselfde boodskap weer aan 'n ander kliënt stuur. Hierdie gedrag was in ooreenstemming met die boodskap aflewering waarborg "ten minste een keer«.

In Kafka 0.10 is die kliëntkode verander sodat die commit periodiek deur die kliëntbiblioteek geaktiveer word, soos gekonfigureer outo.commit.interval.ms. Hierdie gedrag is iewers tussen die JMS AUTO_ACKNOWLEDGE en DUPS_OK_ACKNOWLEDGE modusse. Wanneer outocommit gebruik word, kan boodskappe gepleeg word, ongeag of dit werklik verwerk is - dit kan gebeur in die geval van 'n stadige verbruiker. As 'n verbruiker aborteer, sal boodskappe deur die volgende verbruiker gehaal word, begin by die toegewyde posisie, wat kan lei tot 'n gemiste boodskap. In hierdie geval het Kafka nie die boodskappe verloor nie, die leeskode het dit net nie verwerk nie.

Hierdie modus het dieselfde belofte as in weergawe 0.9: boodskappe kan verwerk word, maar as dit misluk, kan die verrekening nie gepleeg word nie, wat moontlik veroorsaak dat aflewering verdubbel. Hoe meer boodskappe jy haal wanneer jy dit uitvoer meningpeiling(), hoe meer hierdie probleem.

Soos bespreek in “Lees boodskappe vanaf 'n tou” op bladsy 21, is daar nie iets soos 'n eenmalige aflewering van 'n boodskap in 'n boodskapstelsel wanneer mislukkingsmodusse in ag geneem word nie.

In Kafka is daar twee maniere om 'n offset (offset) te pleeg: outomaties en met die hand. In beide gevalle kan boodskappe verskeie kere verwerk word as die boodskap verwerk is maar misluk het voor die commit. Jy kan ook kies om glad nie die boodskap te verwerk as die commit in die agtergrond gebeur het en jou kode voltooi is voordat dit verwerk kon word nie (miskien in Kafka 0.9 en vroeër).

Jy kan die handmatige offset-commit-proses in die Kafka-verbruikers-API beheer deur die parameter te stel enable.auto.commit om een ​​van die volgende metodes te vals en eksplisiet te noem:

void commitSync();
void commitAsync();

As jy die boodskap "ten minste een keer" wil verwerk, moet jy die verrekening met die hand pleeg commitSync()deur hierdie opdrag onmiddellik uit te voer nadat die boodskappe verwerk is.

Hierdie metodes laat nie toe dat boodskappe erken word voordat dit verwerk word nie, maar hulle doen niks om potensiële verwerkingsvertragings uit te skakel nie, terwyl dit die voorkoms van transaksioneel gee. Daar is geen transaksies in Kafka nie. Die kliënt het nie die vermoë om die volgende te doen nie:

  • Rol 'n vervalste boodskap outomaties terug. Verbruikers moet self uitsonderings hanteer wat voortspruit uit problematiese loonvragte en agterplaasonderbrekings, aangesien hulle nie op die makelaar kan staatmaak om boodskappe weer te lewer nie.
  • Stuur boodskappe na verskeie onderwerpe in een atoomoperasie. Soos ons binnekort sal sien, kan beheer oor verskillende onderwerpe en partisies op verskillende masjiene in die Kafka-groepering wees wat nie transaksies koördineer wanneer dit gestuur word nie. Ten tyde van hierdie skrywe is 'n bietjie werk gedoen om dit moontlik te maak met die KIP-98.
  • Assosieer die lees van een boodskap van een onderwerp met die stuur van 'n ander boodskap na 'n ander onderwerp. Weereens, die Kafka-argitektuur is afhanklik van baie onafhanklike masjiene wat as een bus loop en geen poging word aangewend om dit weg te steek nie. Daar is byvoorbeeld geen API-komponente wat jou sal toelaat om te skakel nie verbruiker и produsent in 'n transaksie. In JMS word dit deur die voorwerp verskaf Sessiewaaruit geskep word Boodskapvervaardigers и Boodskap Verbruikers.

As ons nie op transaksies kan staatmaak nie, hoe kan ons semantiek nader aan dié verskaf deur tradisionele boodskapstelsels verskaf?

As daar 'n moontlikheid is dat die verbruiker se verrekening kan toeneem voordat die boodskap verwerk is, soos tydens 'n verbruikerongeluk, dan het die verbruiker geen manier om te weet of sy verbruikersgroep die boodskap gemis het toe 'n partisie aan hom toegeken is nie. Een strategie is dus om die verrekening terug te spoel na die vorige posisie. Die Kafka-verbruikers-API bied die volgende metodes hiervoor:

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

metode soek() kan met metode gebruik word
offsetsForTimes(Map tydstempelsToSearch) om terug te spoel na 'n toestand op 'n spesifieke punt in die verlede.

Implisiet beteken die gebruik van hierdie benadering dat dit baie waarskynlik is dat sommige boodskappe wat voorheen verwerk is, gelees en weer verwerk sal word. Om dit te vermy, kan ons idempotente lees gebruik, soos beskryf in Hoofstuk 4, om tred te hou met voorheen bekykte boodskappe en duplikate uit te skakel.

Alternatiewelik kan jou verbruikerskode eenvoudig gehou word, solank boodskapverlies of duplisering aanvaarbaar is. Wanneer ons gebruiksgevalle oorweeg waarvoor Kafka algemeen gebruik word, soos die hantering van loggebeurtenisse, statistieke, kliknasporing, ens., verstaan ​​ons dat die verlies van individuele boodskappe waarskynlik nie 'n noemenswaardige impak op omliggende toepassings sal hê nie. In sulke gevalle is die verstekwaardes heeltemal aanvaarbaar. Aan die ander kant, as jou aansoek betalings moet stuur, moet jy sorgvuldig na elke individuele boodskap omsien. Dit kom alles neer op konteks.

Persoonlike waarnemings toon dat namate die intensiteit van boodskappe toeneem, die waarde van elke individuele boodskap afneem. Groot boodskappe is geneig om waardevol te wees wanneer dit in 'n saamgevoegde vorm bekyk word.

Hoë beskikbaarheid

Kafka se benadering tot hoë beskikbaarheid verskil baie van ActiveMQ se benadering. Kafka is ontwerp rondom uitskaalgroepe waar alle makelaargevalle terselfdertyd boodskappe ontvang en versprei.

'n Kafka-kluster bestaan ​​uit verskeie makelaargevalle wat op verskillende bedieners loop. Kafka is ontwerp om op gewone selfstandige hardeware te werk, waar elke nodus sy eie toegewyde berging het. Die gebruik van netwerkgehegte berging (SAN) word nie aanbeveel nie, want veelvuldige rekenaarnodusse kan om tyd meeding.Ыe stoor intervalle en skep konflikte.

Kafka is altyd aan stelsel. Baie groot Kafka-gebruikers sluit nooit hul groepe af nie en die sagteware word altyd opgedateer met 'n opeenvolgende herbegin. Dit word bereik deur versoenbaarheid met die vorige weergawe vir boodskappe en interaksies tussen makelaars te waarborg.

Makelaars wat aan 'n bedienerkluster gekoppel is Dieretuinopsigter, wat dien as 'n konfigurasiedataregister en word gebruik om die rolle van elke makelaar te koördineer. ZooKeeper self is 'n verspreide stelsel wat hoë beskikbaarheid bied deur die replisering van inligting deur die vestiging kworum.

In die basisgeval word 'n onderwerp in 'n Kafka-kluster geskep met die volgende eienskappe:

  • Die aantal partisies. Soos vroeër bespreek, hang die presiese waarde wat hier gebruik word af van die verlangde vlak van parallelle lees.
  • Die replikasiefaktor (faktor) bepaal hoeveel makelaargevalle in die groep logs vir hierdie partisie moet bevat.

Deur ZooKeepers vir koördinering te gebruik, poog Kafka om nuwe partisies regverdig onder die makelaars in die groepie te versprei. Dit word gedoen deur 'n enkele instansie wat as 'n Kontroleur optree.

Tydens looptyd vir elke onderwerp partisie kontroleerder ken rolle aan 'n makelaar toe leier (leier, meester, aanbieder) en volgelinge (volgelinge, slawe, ondergeskiktes). Die makelaar, wat as die leier vir hierdie partisie optree, is verantwoordelik vir die ontvangs van al die boodskappe wat deur die produsente aan hom gestuur word en die verspreiding van die boodskappe aan die verbruikers. Wanneer boodskappe na 'n onderwerppartisie gestuur word, word dit na alle makelaarnodusse gerepliseer wat as volgelinge vir daardie partisie optree. Elke nodus wat logs vir 'n partisie bevat, word opgeroep replika. 'n Makelaar kan optree as 'n leier vir sommige partisies en as 'n volger vir ander.

'n Volger wat alle boodskappe bevat wat deur die leier gehou word, word geroep gesinchroniseerde replika ('n replika wat in 'n gesinchroniseerde toestand is, in-sinkroniseer replika). As 'n makelaar wat as 'n leier vir 'n partisie optree, afneem, kan enige makelaar wat op datum is of gesinchroniseer is vir daardie partisie, die leierrol oorneem. Dit is 'n ongelooflike volhoubare ontwerp.

Deel van die vervaardigerkonfigurasie is die parameter akks, wat bepaal hoeveel replikas ontvangs van 'n boodskap moet erken (erken) voordat die toepassingsdraad voortgaan om te stuur: 0, 1 of almal. Indien gestel op almal, wanneer 'n boodskap dan ontvang word, sal die leier 'n bevestiging aan die vervaardiger terugstuur sodra hy bevestigings (erkennings) van die rekord ontvang vanaf verskeie leidrade (insluitend homself) wat deur die onderwerpinstelling gedefinieer is min.insync.replikas (verstek 1). As die boodskap nie suksesvol herhaal kan word nie, sal die produsent 'n aansoek-uitsondering gooi (Nie Genoeg Replikas nie of Nie GenoegReplicasAfterAppend).

'n Tipiese konfigurasie skep 'n onderwerp met 'n replikasiefaktor van 3 (1 leier, 2 volgers per partisie) en die parameter min.insync.replikas is ingestel op 2. In hierdie geval sal die cluster een van die makelaars wat die onderwerppartisie bestuur toelaat om af te gaan sonder om kliënttoepassings te beïnvloed.

Dit bring ons terug na die reeds bekende afweging tussen prestasie en betroubaarheid. Replikasie vind plaas ten koste van bykomende wagtyd vir bevestigings (erkennings) van volgelinge. Alhoewel, omdat dit parallel loop, het replikasie na ten minste drie nodusse dieselfde werkverrigting as twee (die toename in netwerkbandwydtegebruik ignoreer).

Deur hierdie replikasieskema te gebruik, vermy Kafka slim die behoefte om elke boodskap fisies na skyf te skryf met die operasie sinchroniseer (). Elke boodskap wat deur die vervaardiger gestuur word, sal na die partisielogboek geskryf word, maar soos bespreek in Hoofstuk 2, word die skryf van 'n lêer aanvanklik in die bedryfstelsel se buffer gedoen. As hierdie boodskap na 'n ander Kafka-instansie gerepliseer word en in sy geheue is, beteken die verlies van die leier nie dat die boodskap self verlore gegaan het nie - dit kan deur 'n gesinchroniseerde replika oorgeneem word.
Weiering om die operasie uit te voer sinchroniseer () beteken dat Kafka boodskappe so vinnig kan ontvang as wat hy dit in die geheue kan skryf. Omgekeerd, hoe langer jy kan vermy om geheue na skyf te spoel, hoe beter. Om hierdie rede is dit nie ongewoon dat Kafka-makelaars 64 GB of meer geheue toegeken word nie. Hierdie geheuegebruik beteken dat 'n enkele Kafka-instansie maklik duisende kere vinniger kan hardloop as 'n tradisionele boodskapmakelaar.

Kafka kan ook gekonfigureer word om die bewerking toe te pas sinchroniseer () pakkette te stuur. Aangesien alles in Kafka pakketgeoriënteerd is, werk dit eintlik redelik goed vir baie gebruiksgevalle en is dit 'n nuttige hulpmiddel vir gebruikers wat baie sterk waarborge benodig. Baie van die suiwer prestasie van Kafka kom van die boodskappe wat as pakkies aan die makelaar gestuur word en dat hierdie boodskappe van die makelaar gelees word in opeenvolgende blokke met nul kopie bewerkings (bewerkings waartydens die taak om data van een geheuearea na 'n ander te kopieer nie uitgevoer word nie). Laasgenoemde is 'n groot prestasie- en hulpbronwins en is slegs moontlik deur die gebruik van 'n onderliggende logdatastruktuur wat die partisieskema definieer.

Baie beter werkverrigting is moontlik in 'n Kafka-groepering as met 'n enkele Kafka-makelaar, omdat onderwerppartisies oor baie afsonderlike masjiene kan skaal.

Resultate van

In hierdie hoofstuk het ons gekyk na hoe die Kafka-argitektuur die verhouding tussen kliënte en makelaars herverbeeld om 'n ongelooflike robuuste boodskappyplyn te verskaf, met deurset baie keer groter as dié van 'n konvensionele boodskapmakelaar. Ons het die funksionaliteit wat dit gebruik om dit te bereik bespreek en kortliks gekyk na die argitektuur van die toepassings wat hierdie funksionaliteit verskaf. In die volgende hoofstuk sal ons kyk na algemene probleme wat boodskapgebaseerde toepassings moet oplos en strategieë bespreek om dit te hanteer. Ons sal die hoofstuk afsluit deur te verduidelik hoe om oor boodskaptegnologie in die algemeen te praat sodat jy die geskiktheid daarvan vir jou gebruiksgevalle kan evalueer.

Vorige vertaalde deel: Verstaan ​​boodskap makelaars. Leer die meganika van boodskappe met ActiveMQ en Kafka. Hoofstuk 1

Vertaling gedoen: tele.gg/middle_java

Vervolg…

Slegs geregistreerde gebruikers kan aan die opname deelneem. Meld aan, asseblief.

Word Kafka in jou organisasie gebruik?

  • Ja

  • Geen

  • Voorheen gebruik, nou nie

  • Ons beplan om te gebruik

38 gebruikers het gestem. 8 gebruikers het buite stemming gebly.

Bron: will.com

Voeg 'n opmerking