Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka

Nastavak prijevoda male knjige:
Razumijevanje posrednika za poruke
autor: Jakub Korab, izdavač: O'Reilly Media, Inc., datum izdanja: jun 2017, ISBN: 9781492049296.

Prethodni prevedeni dio: Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 1 Uvod

POGLAVLJE 3

Kafka

Kafka je razvijena u LinkedIn-u kako bi se zaobišla neka od ograničenja tradicionalnih posrednika poruka i izbjegla potreba za postavljanjem više posrednika poruka za različite interakcije od tačke do tačke, što je opisano u ovoj knjizi pod "Skaliranje i smanjenje" na stranici 28. Slučajevi korišćenja LinkedIn se u velikoj meri oslanjao na jednosmerno unošenje veoma velikih količina podataka, kao što su klikovi na stranice i evidencije pristupa, dok je i dalje dozvoljavao da te podatke koriste više sistema bez uticaja na produktivnost proizvođača ili drugih potrošača. U stvari, razlog zašto Kafka postoji je da dobije arhitekturu za razmjenu poruka koju opisuje Univerzalni cevovod podataka.

S obzirom na ovaj krajnji cilj, prirodno su se pojavili i drugi zahtjevi. Kafka bi trebao:

  • Budite izuzetno brzi
  • Omogućite veću propusnost kada radite s porukama
  • Podržava modele izdavač-pretplatnik i od tačke do tačke
  • Nemojte usporavati sa dodavanjem potrošača. Na primjer, performanse i reda i teme u ActiveMQ-u opadaju kako broj korisnika na odredištu raste.
  • Budite horizontalno skalabilni; ako jedan broker koji perzistira poruke može to učiniti samo pri maksimalnoj brzini diska, onda ima smisla ići dalje od jedne brokerske instance kako bi se povećale performanse
  • Ograničite pristup pohranjivanju i ponovnom preuzimanju poruka

Da bi sve ovo postigao, Kafka je usvojio arhitekturu koja je redefinirala uloge i odgovornosti klijenata i posrednika za razmjenu poruka. JMS model je veoma orijentisan na brokera, gde je broker odgovoran za distribuciju poruka, a klijenti moraju samo da brinu o slanju i primanju poruka. Kafka je, s druge strane, usmjeren na klijenta, pri čemu klijent preuzima mnoge karakteristike tradicionalnog brokera, kao što je fer distribucija relevantnih poruka potrošačima, u zamjenu za izuzetno brzog i skalabilnog brokera. Za ljude koji su radili s tradicionalnim sistemima za razmjenu poruka, rad sa Kafkom zahtijeva temeljnu promjenu mišljenja.
Ovaj smjer inženjeringa doveo je do stvaranja infrastrukture za razmjenu poruka koja je sposobna povećati propusnost za mnogo reda veličine u poređenju sa konvencionalnim brokerom. Kao što ćemo vidjeti, ovaj pristup dolazi sa kompromisima, što znači da Kafka nije pogodan za određene vrste opterećenja i instaliranog softvera.

Model objedinjenog odredišta

Da bi ispunio gore opisane zahtjeve, Kafka je kombinirao publikovanje-pretplatu i razmjenu poruka od tačke do tačke pod jednom vrstom odredišta − tema. Ovo je zbunjujuće za ljude koji su radili sa sistemima za razmjenu poruka, gdje se riječ "tema" odnosi na mehanizam emitiranja iz kojeg (iz teme) čitanje nije trajno. Kafkine teme treba smatrati hibridnim tipom odredišta, kao što je definisano u uvodu ove knjige.

U ostatku ovog poglavlja, osim ako izričito ne kažemo drugačije, termin "tema" odnosit će se na Kafkinu temu.

Da bismo u potpunosti razumjeli kako se teme ponašaju i koje garancije pružaju, prvo moramo pogledati kako su implementirane u Kafki.
Svaka tema u Kafki ima svoj dnevnik.
Proizvođači koji šalju poruke Kafki pišu u ovaj dnevnik, a potrošači čitaju iz dnevnika koristeći pokazivače koji se stalno kreću naprijed. Povremeno, Kafka briše najstarije dijelove dnevnika, bez obzira da li su poruke u tim dijelovima pročitane ili ne. Centralni dio Kafkinog dizajna je da brokera nije briga da li se poruke čitaju ili ne – to je odgovornost klijenta.

Izrazi "log" i "pokazivač" se ne pojavljuju u Kafka dokumentacija. Ovi dobro poznati termini se ovdje koriste za lakše razumijevanje.

Ovaj model je potpuno drugačiji od ActiveMQ, gdje se poruke iz svih redova pohranjuju u isti dnevnik, a broker označava poruke kao izbrisane nakon što su pročitane.
Kopajmo sada malo dublje i detaljnije pogledajmo dnevnik tema.
Kafka dnevnik se sastoji od nekoliko particija (Slika 3-1). Kafka garantuje strogi poredak u svakoj particiji. To znači da će poruke napisane na particiji određenim redoslijedom biti pročitane istim redoslijedom. Svaka particija je implementirana kao pokretna datoteka dnevnika koja sadrži podskup (podskup) svih poruka koje su na temu poslali njeni proizvođači. Kreirana tema podrazumevano sadrži jednu particiju. Ideja particija je središnja Kafkina ideja za horizontalno skaliranje.

Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka
Slika 3-1. Kafka Partitions

Kada proizvođač pošalje poruku Kafkinoj temi, on odlučuje na koju particiju će poslati poruku. Kasnije ćemo ovo detaljnije pogledati.

Čitanje poruka

Klijent koji želi da pročita poruke upravlja imenovanim pokazivačem koji se zove grupa potrošača, što ukazuje na offset poruke na particiji. Pomak je inkrementalna pozicija koja počinje od 0 na početku particije. Ova grupa potrošača, referencirana u API-ju preko korisnički definiranog group_id, odgovara jedan logički potrošač ili sistem.

Većina sistema za razmenu poruka čita podatke sa odredišta koristeći više instanci i niti za paralelnu obradu poruka. Stoga će obično biti mnogo potrošačkih instanci koje dijele istu grupu potrošača.

Problem čitanja može se predstaviti na sljedeći način:

  • Tema ima više particija
  • Više grupa potrošača može koristiti temu u isto vrijeme
  • Grupa potrošača može imati više zasebnih instanci

Ovo je netrivijalan problem „više prema mnogo“. Da bismo razumjeli kako Kafka upravlja odnosima između potrošačkih grupa, potrošačkih instanci i particija, pogledajmo niz progresivno složenijih scenarija čitanja.

Potrošači i grupe potrošača

Uzmimo kao polaznu tačku temu sa jednom particijom (Slika 3-2).

Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka
Slika 3-2. Potrošač čita sa particije

Kada se potrošačka instanca poveže sa svojim vlastitim group_id na ovu temu, dodjeljuje joj se particija za čitanje i pomak u toj particiji. Pozicija ovog pomaka je konfigurisana u klijentu kao pokazivač na najnoviju poziciju (najnovija poruka) ili najraniju poziciju (najstarija poruka). Potrošač traži (anketira) poruke iz teme, što uzrokuje njihovo uzastopno čitanje iz dnevnika.
Pozicija offseta se redovno vraća Kafki i pohranjuje kao poruke u internoj temi _consumer_offsets. Pročitane poruke se i dalje ne brišu, za razliku od običnog brokera, a klijent može premotati pomak da bi ponovo obradio već pregledane poruke.

Kada se drugi logički potrošač poveže koristeći drugačiji group_id, on upravlja drugim pokazivačem koji je nezavisan od prvog (Slika 3-3). Dakle, Kafka tema djeluje kao red u kojem postoji jedan potrošač i kao normalna tema za objavljivanje-pretplatu (pub-sub) na koju se pretplati više korisnika, uz dodatnu prednost da se sve poruke pohranjuju i mogu više puta obraditi.

Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka
Slika 3-3. Dva potrošača u različitim grupama potrošača čitaju sa iste particije

Potrošači u grupi potrošača

Kada jedna potrošačka instanca čita podatke sa particije, ima punu kontrolu nad pokazivačem i obrađuje poruke kao što je opisano u prethodnom odjeljku.
Ako je više instanci potrošača bilo povezano s istim group_id na temu s jednom particijom, tada će instanca koja se posljednja povezala dobiti kontrolu nad pokazivačem i od tog trenutka će primati sve poruke (Slika 3-4).

Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka
Slika 3-4. Dva potrošača u istoj grupi potrošača čitaju sa iste particije

Ovaj način obrade, u kojem broj potrošačkih instanci premašuje broj particija, može se smatrati vrstom ekskluzivnog potrošača. Ovo može biti korisno ako vam je potrebno "aktivno-pasivno" (ili "vruće-toplo") grupiranje vaših potrošačkih instanci, iako je pokretanje više potrošača paralelno ("aktivno-aktivno" ili "vruće-vruće") mnogo tipičnije od potrošači.U stanju pripravnosti.

Ovo gore opisano ponašanje distribucije poruka može biti iznenađujuće u poređenju sa načinom na koji se ponaša normalan JMS red. U ovom modelu, poruke poslane u red čekanja će biti ravnomjerno raspoređene između dva potrošača.

Najčešće, kada kreiramo više instanci potrošača, to radimo ili da bismo obradili poruke paralelno, ili da bismo povećali brzinu čitanja, ili da bismo povećali stabilnost procesa čitanja. Pošto samo jedna potrošačka instanca može istovremeno čitati podatke sa particije, kako se to postiže u Kafki?

Jedan od načina da to učinite je korištenje jedne potrošačke instance za čitanje svih poruka i prosljeđivanje u skup niti. Iako ovaj pristup povećava propusnost obrade, on povećava složenost potrošačke logike i ne čini ništa da poveća robusnost sistema za čitanje. Ako se jedna kopija potrošača pokvari zbog nestanka struje ili sličnog događaja, tada se oduzimanje zaustavlja.

Kanonski način za rješavanje ovog problema kod Kafke je korištenje bОviše particija.

Particioniranje

Particije su glavni mehanizam za paraleliziranje čitanja i skaliranja teme izvan propusnosti jedne brokerske instance. Da bismo ovo bolje razumjeli, razmotrimo situaciju u kojoj postoji tema s dvije particije i jedan potrošač se pretplatio na ovu temu (Slika 3-5).

Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka
Slika 3-5. Jedan potrošač čita sa više particija

U ovom scenariju, potrošaču se daje kontrola nad pokazivačima koji odgovaraju njegovom group_id u obje particije i počinje čitati poruke s obje particije.
Kada se ovoj temi doda dodatni potrošač za isti group_id, Kafka preusmjerava jednu od particija s prvog na drugog potrošača. Nakon toga, svaka instanca korisnika će čitati sa jedne particije teme (Slika 3-6).

Da biste osigurali da se poruke obrađuju paralelno u 20 niti, potrebno vam je najmanje 20 particija. Ako ima manje particija, ostat ćete s potrošačima koji nemaju na čemu raditi, kao što je opisano ranije u raspravi o ekskluzivnim potrošačima.

Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 3. Kafka
Slika 3-6. Dva potrošača u istoj grupi potrošača čitaju s različitih particija

Ova šema uvelike smanjuje složenost Kafka brokera u poređenju sa distribucijom poruka koja je potrebna za održavanje JMS reda. Ovdje ne morate brinuti o sljedećim tačkama:

  • Koji potrošač treba da primi sljedeću poruku, na osnovu round-robin alokacije, trenutnog kapaciteta bafera za prethodno dohvaćanje ili prethodnih poruka (kao za grupe JMS poruka).
  • Koje poruke se šalju kojim potrošačima i da li ih treba ponovo dostaviti u slučaju kvara.

Sve što Kafka broker treba da uradi je da uzastopno prosledi poruke potrošaču kada ih ovaj zatraži.

Međutim, zahtjevi za paralelno čitanje i ponovno slanje neuspjelih poruka ne nestaju - odgovornost za njih jednostavno prelazi sa brokera na klijenta. To znači da se oni moraju uzeti u obzir u vašem kodu.

Slanje poruka

Odgovornost proizvođača te poruke je da odluči na koju particiju će poslati poruku. Da bismo razumjeli mehanizam pomoću kojeg se to radi, prvo moramo razmotriti šta tačno zapravo šaljemo.

Dok u JMS-u koristimo strukturu poruke sa metapodacima (zaglavlja i svojstva) i tijelom koje sadrži korisni teret (korisno opterećenje), u Kafki je poruka par "ključ-vrijednost". Korisno opterećenje poruke se šalje kao vrijednost. Ključ se, s druge strane, uglavnom koristi za particioniranje i mora sadržavati ključ specifičan za poslovnu logikuda stavite povezane poruke u istu particiju.

U Poglavlju 2, raspravljali smo o scenariju klađenja na mreži u kojem povezani događaji moraju biti obrađeni po redu od strane jednog potrošača:

  1. Korisnički nalog je konfigurisan.
  2. Novac se pripisuje na račun.
  3. Napravljena je opklada koja povlači novac sa računa.

Ako je svaki događaj poruka objavljena na temu, tada bi prirodni ključ bio ID naloga.
Kada se poruka pošalje pomoću Kafka Producer API-ja, ona se prosljeđuje particionoj funkciji koja, s obzirom na poruku i trenutno stanje Kafka klastera, vraća ID particije na koju treba poslati poruku. Ova funkcija je implementirana u Javi kroz Partitioner interfejs.

Ovaj interfejs izgleda ovako:

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

Implementacija Partitioner-a koristi zadani algoritam za raspršivanje opće namjene preko ključa za određivanje particije ili round-robin ako ključ nije specificiran. Ova zadana vrijednost dobro funkcionira u većini slučajeva. Međutim, u budućnosti ćete htjeti pisati svoje.

Pisanje vlastite strategije particioniranja

Pogledajmo primjer gdje želite poslati metapodatke zajedno s korisnim opterećenjem poruke. Korisno opterećenje u našem primjeru je instrukcija za uplatu depozita na račun igre. Instrukcija je nešto za šta bismo željeli da bude zajamčeno da neće biti modificirano pri prijenosu i želimo biti sigurni da samo pouzdani uzvodni sistem može pokrenuti tu instrukciju. U ovom slučaju, sistemi za slanje i prijem slažu se o korištenju potpisa za provjeru autentičnosti poruke.
U normalnom JMS-u, jednostavno definiramo svojstvo "potpisa poruke" i dodamo ga poruci. Međutim, Kafka nam ne daje mehanizam za prosljeđivanje metapodataka, već samo ključ i vrijednost.

Budući da je vrijednost teret bankovnog prijenosa čiji integritet želimo sačuvati, nemamo izbora nego definirati strukturu podataka koju ćemo koristiti u ključu. Pod pretpostavkom da nam je potreban ID naloga za particioniranje, pošto sve poruke koje se odnose na nalog moraju biti obrađene po redu, doći ćemo do sljedeće JSON strukture:

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

Budući da će vrijednost potpisa varirati u zavisnosti od korisnog opterećenja, zadana strategija heširanja Partitioner interfejsa neće pouzdano grupirati povezane poruke. Stoga ćemo morati napisati našu vlastitu strategiju koja će analizirati ovaj ključ i particionirati vrijednost accountId.

Kafka uključuje kontrolne sume za otkrivanje oštećenja poruka u prodavnici i ima pun skup sigurnosnih funkcija. Čak i tako, ponekad se pojavljuju zahtjevi specifični za industriju, kao što je onaj iznad.

Korisnička strategija particioniranja mora osigurati da sve povezane poruke završe na istoj particiji. Iako se ovo čini jednostavnim, zahtjev može biti komplikovan zbog važnosti redoslijeda povezanih poruka i koliko je fiksni broj particija u temi.

Broj particija u temi može se promijeniti tokom vremena, jer se mogu dodati ako promet prelazi početna očekivanja. Dakle, ključevi poruka mogu biti povezani s particijom na koju su prvobitno poslani, što implicira dio stanja koji se dijeli između instanci proizvođača.

Drugi faktor koji treba uzeti u obzir je ravnomjerna distribucija poruka po particijama. Tipično, ključevi nisu ravnomjerno raspoređeni po porukama, a funkcije heširanja ne garantuju fer distribuciju poruka za mali skup ključeva.
Važno je napomenuti da kako god da odaberete da podijelite poruke, sam separator će možda morati ponovo da se koristi.

Razmotrite zahtjev za repliciranjem podataka između Kafka klastera na različitim geografskim lokacijama. U tu svrhu, Kafka dolazi sa alatom komandne linije pod nazivom MirrorMaker, koji se koristi za čitanje poruka iz jednog klastera i njihovo prebacivanje u drugi.

MirrorMaker mora razumjeti ključeve replicirane teme kako bi održao relativni red između poruka kada se replicira između klastera, budući da broj particija za tu temu možda neće biti isti u dva klastera.

Prilagođene strategije particioniranja su relativno rijetke, jer zadano heširanje ili round robin dobro funkcionira u većini scenarija. Međutim, ako su vam potrebne jake garancije za naručivanje ili morate izdvojiti metapodatke iz korisnih opterećenja, onda je particioniranje nešto što biste trebali bolje pogledati.

Prednosti skalabilnosti i performansi Kafke proizlaze iz prebacivanja nekih odgovornosti tradicionalnog brokera na klijenta. U ovom slučaju se donosi odluka da se potencijalno povezane poruke distribuiraju među nekoliko potrošača koji rade paralelno.

JMS brokeri takođe moraju da se pozabave takvim zahtevima. Zanimljivo je da mehanizam za slanje srodnih poruka istom potrošaču, implementiran kroz JMS grupe poruka (varijacija na strategiji ljepljivog balansiranja opterećenja (SLB), također zahtijeva od pošiljaoca da označi poruke kao povezane. U slučaju JMS-a, broker je odgovoran za slanje ove grupe povezanih poruka jednom od mnogih potrošača i prijenos vlasništva nad grupom ako potrošač otpadne.

Ugovori proizvođača

Particioniranje nije jedina stvar koju treba uzeti u obzir prilikom slanja poruka. Pogledajmo metode send() klase Producer u Java API-ju:

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

Odmah treba napomenuti da oba metoda vraćaju Future, što ukazuje da se operacija slanja ne izvodi odmah. Rezultat je da se poruka (ProducerRecord) upisuje u bafer za slanje za svaku aktivnu particiju i šalje brokeru kao pozadinska nit u Kafka klijentskoj biblioteci. Iako ovo čini stvari nevjerovatno brzim, to znači da neiskusna aplikacija može izgubiti poruke ako se njen proces zaustavi.

Kao i uvijek, postoji način da se operacija slanja učini pouzdanijom nauštrb performansi. Veličina ovog bafera može se postaviti na 0, a nit aplikacije za slanje će biti prisiljena čekati dok se ne završi prijenos poruke brokeru, kako slijedi:

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

Više o čitanju poruka

Čitanje poruka ima dodatne složenosti o kojima treba spekulisati. Za razliku od JMS API-ja, koji može pokrenuti slušač poruka kao odgovor na poruku, potrošač Kafka samo ankete. Pogledajmo bliže metodu anketa()koristi se u tu svrhu:

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

Povratna vrijednost metode je struktura kontejnera koja sadrži više objekata rekord potrošača sa potencijalno nekoliko particija. rekord potrošača je sam po sebi objekat držač za par ključ-vrijednost sa pridruženim metapodacima, kao što je particija iz koje je izveden.

Kao što je objašnjeno u Poglavlju 2, moramo imati na umu šta se dešava sa porukama nakon što su uspešno ili neuspešno obrađene, na primer, ako klijent nije u mogućnosti da obradi poruku ili ako se prekine. U JMS-u, ovo je obrađeno putem načina potvrde. Broker će ili izbrisati uspješno obrađenu poruku, ili će ponovo dostaviti sirovu ili lažnu poruku (pod pretpostavkom da su transakcije korištene).
Kafka radi sasvim drugačije. Poruke se ne brišu u brokeru nakon lektoriranja, a ono što se događa u slučaju neuspjeha je odgovornost samog koda za lektoriranje.

Kao što smo rekli, grupa potrošača je povezana sa pomakom u dnevniku. Pozicija dnevnika povezana s ovim pomakom odgovara sljedećoj poruci koja će se izdati kao odgovor anketa(). Vremenski trenutak kada se ovaj pomak povećava je odlučujući za čitanje.

Vraćajući se na model čitanja o kojem smo ranije govorili, obrada poruke se sastoji od tri faze:

  1. Preuzmi poruku za čitanje.
  2. Obradite poruku.
  3. Potvrdite poruku.

Kafka potrošač dolazi sa opcijom konfiguracije enable.auto.commit. Ovo je često korištena zadana postavka, kao što je uobičajeno za postavke koje sadrže riječ "auto".

Prije Kafke 0.10, klijent koji koristi ovu opciju bi poslao pomak posljednje pročitane poruke pri sljedećem pozivu anketa() nakon obrade. To je značilo da se sve poruke koje su već preuzete mogle ponovno obraditi ako ih je klijent već obradio, ali je neočekivano uništen prije pozivanja anketa(). Budući da broker ne čuva nikakvu državu o tome koliko je puta poruka pročitana, sljedeći potrošač koji preuzme tu poruku neće znati da se ništa loše dogodilo. Ovo ponašanje je bilo pseudotransakciono. Pomak je izvršen samo ako je poruka uspješno obrađena, ali ako je klijent prekinuo, posrednik bi ponovo poslao istu poruku drugom klijentu. Ovo ponašanje je u skladu s garancijom isporuke poruke "barem jednom".

U Kafki 0.10, klijentski kod je promijenjen tako da se urezivanje povremeno pokreće od strane klijentske biblioteke, kako je konfigurirano auto.commit.interval.ms. Ovo ponašanje je negdje između JMS AUTO_ACKNOWLEDGE i DUPS_OK_ACKNOWLEDGE načina. Kada se koristi autocommit, poruke se mogu predati bez obzira na to da li su stvarno obrađene - to bi se moglo dogoditi u slučaju sporog korisnika. Ako je potrošač prekinuo, poruke bi dohvatio sljedeći potrošač, počevši od predane pozicije, što bi moglo rezultirati propuštenom porukom. U ovom slučaju, Kafka nije izgubio poruke, kod za čitanje ih jednostavno nije obradio.

Ovaj način rada ima isto obećanje kao u verziji 0.9: poruke se mogu obraditi, ali ako ne uspije, pomak možda neće biti urezan, što može uzrokovati udvostručenje isporuke. Što više poruka dohvatite prilikom izvršavanja anketa(), više je ovaj problem.

Kao što je objašnjeno u “Čitanje poruka iz reda” na stranici 21, ne postoji takva stvar kao što je jednokratna isporuka poruke u sistemu za razmjenu poruka kada se uzmu u obzir načini kvara.

U Kafki postoje dva načina za urezivanje (urezivanje) pomaka (offset): automatski i ručno. U oba slučaja, poruke se mogu obraditi više puta ako je poruka obrađena, ali nije uspjela prije urezivanja. Također možete odabrati da uopće ne obrađujete poruku ako se urezivanje dogodilo u pozadini i vaš kod je završen prije nego što je mogao biti obrađen (možda u Kafki 0.9 i ranije).

Možete kontrolirati proces ručnog urezivanja pomaka u Kafka potrošačkom API-ju postavljanjem parametra enable.auto.commit na lažno i eksplicitno pozivanje jedne od sljedećih metoda:

void commitSync();
void commitAsync();

Ako želite obraditi poruku "barem jednom", morate ručno urezati pomak sa commitSync()izvršavanjem ove naredbe odmah nakon obrade poruka.

Ove metode ne dozvoljavaju potvrđivanje poruka prije nego što budu obrađene, ali ne čine ništa da eliminišu potencijalna kašnjenja u obradi, a daju izgled da su transakcijske. U Kafki nema transakcija. Klijent nema mogućnost da uradi sledeće:

  • Automatski vrati lažnu poruku. Potrošači sami moraju rješavati izuzetke koji proizlaze iz problematičnog opterećenja i prekida rada pozadinske mreže, jer se ne mogu osloniti na brokera za ponovno isporuku poruka.
  • Šaljite poruke na više tema u jednoj atomskoj operaciji. Kao što ćemo uskoro vidjeti, kontrola nad različitim temama i particijama može se nalaziti na različitim strojevima u Kafka klasteru koji ne koordiniraju transakcije kada se pošalju. U vrijeme pisanja ovog teksta, urađen je određeni posao kako bi se to omogućilo sa KIP-98.
  • Povežite čitanje jedne poruke iz jedne teme sa slanjem druge poruke drugoj temi. Opet, arhitektura Kafke zavisi od mnogih nezavisnih mašina koje rade kao jedna magistrala i ne pokušava se to sakriti. Na primjer, ne postoje API komponente koje bi vam omogućile povezivanje potrošača и Proizvođač u transakciji. U JMS-u, to osigurava objekt sjednicaod kojih se stvaraju MessageProducers и MessageConsumers.

Ako se ne možemo osloniti na transakcije, kako možemo pružiti semantiku bližu onoj koju pružaju tradicionalni sistemi za razmjenu poruka?

Ako postoji mogućnost da se potrošački pomak može povećati prije nego što je poruka obrađena, kao na primjer tokom pada potrošača, tada potrošač nema načina da zna da li je njegova grupa potrošača propustila poruku kada joj je dodijeljena particija. Dakle, jedna strategija je premotavanje pomaka na prethodnu poziciju. Kafka korisnički API pruža sljedeće metode za ovo:

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

Metoda tražiti() može se koristiti sa metodom
offsetsForTimes(Map vremenske oznake za pretraživanje) premotati u stanje u nekom određenom trenutku u prošlosti.

Implicitno, korištenje ovog pristupa znači da je vrlo vjerovatno da će neke poruke koje su prethodno obrađene biti ponovo pročitane i obrađene. Da bismo ovo izbegli, možemo koristiti idempotentno čitanje, kao što je opisano u poglavlju 4, da bismo pratili prethodno pregledane poruke i eliminisali duplikate.

Alternativno, vaš potrošački kod može biti jednostavan, sve dok je gubitak ili dupliciranje poruke prihvatljivo. Kada uzmemo u obzir slučajeve upotrebe za koje se Kafka obično koristi, kao što su rukovanje događajima dnevnika, metrika, praćenje klikova, itd., razumijemo da je malo vjerovatno da će gubitak pojedinačnih poruka imati značajan utjecaj na okolne aplikacije. U takvim slučajevima, zadane vrijednosti su sasvim prihvatljive. S druge strane, ako vaša aplikacija treba da šalje uplate, morate pažljivo voditi računa o svakoj pojedinačnoj poruci. Sve se svodi na kontekst.

Lična zapažanja pokazuju da kako se intenzitet poruke povećava, vrijednost svake pojedinačne poruke opada. Velike poruke obično su vrijedne kada se gledaju u zbirnom obliku.

Visoka dostupnost

Kafkin pristup visokoj dostupnosti veoma se razlikuje od ActiveMQ-ovog pristupa. Kafka je dizajnirana oko klastera u kojima sve brokerske instance primaju i distribuiraju poruke u isto vrijeme.

Kafka klaster se sastoji od više brokerskih instanci koje rade na različitim serverima. Kafka je dizajniran da radi na običnom samostalnom hardveru, gdje svaki čvor ima svoju namjensku pohranu. Upotreba mrežne memorije (SAN) se ne preporučuje jer se više računarskih čvorova može takmičiti za vrijeme.Ыintervale skladištenja i stvaranje sukoba.

Kafka je uvijek uključen sistem. Mnogi veliki korisnici Kafke nikada ne gase svoje klastere i softver se uvijek ažurira uzastopnim ponovnim pokretanjem. Ovo se postiže garantovanjem kompatibilnosti sa prethodnom verzijom za poruke i interakcije između brokera.

Brokeri povezani na klaster servera ZooKeeper, koji djeluje kao registar konfiguracijskih podataka i koristi se za koordinaciju uloga svakog brokera. Sam ZooKeeper je distribuirani sistem koji obezbeđuje visoku dostupnost kroz replikaciju informacija uspostavljanjem kvorum.

U osnovnom slučaju, tema se kreira u Kafka klasteru sa sljedećim svojstvima:

  • Broj particija. Kao što je ranije objašnjeno, tačna vrijednost koja se ovdje koristi ovisi o željenom nivou paralelnog čitanja.
  • Faktor replikacije (faktor) određuje koliko instanci brokera u klasteru treba sadržavati dnevnike za ovu particiju.

Koristeći ZooKeepers za koordinaciju, Kafka pokušava pravedno distribuirati nove particije među brokerima u klasteru. To radi jedna instanca koja djeluje kao Kontrolor.

U vrijeme izvođenja za svaku particiju teme Kontroler dodijeliti uloge brokeru vođa (vođa, majstor, voditelj) i sljedbenici (sljedbenici, robovi, podređeni). Broker, koji djeluje kao vodeći za ovu particiju, odgovoran je za primanje svih poruka koje mu šalju proizvođači i distribuciju poruka potrošačima. Kada se poruke pošalju na particiju teme, one se repliciraju na sve brokerske čvorove koji djeluju kao sljedbenici za tu particiju. Poziva se svaki čvor koji sadrži dnevnike za particiju replika. Broker može djelovati kao vođa za neke particije i kao sljedbenik za druge.

Poziva se sljedbenik koji sadrži sve poruke koje drži vođa sinhronizovana replika (replika koja je u sinhroniziranom stanju, sinkronizirana replika). Ako broker koji djeluje kao vodeći za particiju nestane, bilo koji posrednik koji je ažuriran ili sinkroniziran za tu particiju može preuzeti ulogu vođe. To je nevjerovatno održiv dizajn.

Dio konfiguracije proizvođača je parametar acks, koji određuje koliko replika mora potvrditi (potvrditi) prijem poruke prije nego nit aplikacije nastavi slanje: 0, 1 ili sve. Ako je postavljeno na sve, onda kada se primi poruka, voditelj će poslati potvrdu nazad producentu čim primi potvrde (potvrde) rekorda od nekoliko znakova (uključujući i njega samog) definiranih postavkom teme min.insync.replicas (podrazumevano 1). Ako se poruka ne može uspješno replicirati, onda će proizvođač izbaciti izuzetak aplikacije (NotEnoughReplicas ili NotEnoughReplicasAfterAppend).

Tipična konfiguracija kreira temu s faktorom replikacije 3 (1 vođa, 2 sljedbenika po particiji) i parametrom min.insync.replicas je postavljeno na 2. U ovom slučaju, klaster će dozvoliti jednom od brokera koji upravljaju tematskom particijom da se spusti bez utjecaja na klijentske aplikacije.

Ovo nas vraća na već poznati kompromis između performansi i pouzdanosti. Replikacija se događa na račun dodatnog vremena čekanja na potvrde (potvrde) od pratilaca. Iako, budući da radi paralelno, replikacija na najmanje tri čvora ima iste performanse kao dva (zanemarujući povećanje korištenja propusnog opsega mreže).

Koristeći ovu šemu replikacije, Kafka pametno izbjegava potrebu za fizičkim pisanjem svake poruke na disk operacijom sync(). Svaka poruka koju pošalje proizvođač biće upisana u dnevnik particije, ali kao što je objašnjeno u Poglavlju 2, pisanje u datoteku se inicijalno vrši u baferu operativnog sistema. Ako se ova poruka replicira na drugu Kafka instancu i nalazi se u njenoj memoriji, gubitak vođe ne znači da je sama poruka izgubljena - može je preuzeti sinhronizirana replika.
Odbijanje izvođenja operacije sync() znači da Kafka može primati poruke onoliko brzo koliko ih može zapisati u memoriju. Suprotno tome, što duže možete izbjeći ispiranje memorije na disk, to bolje. Iz tog razloga, nije neuobičajeno da Kafka brokeri dobiju 64 GB ili više memorije. Ova upotreba memorije znači da jedna Kafka instanca može lako raditi na brzinama koje su hiljade puta brže od tradicionalnog brokera poruka.

Kafka se također može konfigurirati da primijeni operaciju sync() na pakete poruka. Budući da je sve u Kafki paketno orijentirano, on zapravo radi prilično dobro za mnoge slučajeve upotrebe i koristan je alat za korisnike koji zahtijevaju vrlo jake garancije. Velik dio čistih performansi Kafke dolazi od poruka koje se šalju brokeru kao paketi i da se te poruke čitaju od brokera u sekvencijalnim blokovima koristeći nula kopija operacije (operacije tokom kojih se ne izvodi zadatak kopiranja podataka iz jednog memorijskog područja u drugo). Ovo posljednje predstavlja veliku dobit u performansama i resursima i moguće je samo korištenjem osnovne strukture podataka dnevnika koja definira shemu particije.

Mnogo bolje performanse moguće su u Kafka klasteru nego sa jednim Kafka brokerom, jer se tematske particije mogu proširiti na mnoge odvojene mašine.

Ishodi

U ovom poglavlju pogledali smo kako Kafkina arhitektura ponovo zamišlja odnos između klijenata i brokera kako bi pružila nevjerovatno robustan cevovod za razmjenu poruka, sa propusnošću mnogo puta većom od one kod konvencionalnog posrednika poruka. Razgovarali smo o funkcionalnosti koju koristi da bi se to postiglo i ukratko pogledali arhitekturu aplikacija koje pružaju ovu funkcionalnost. U sledećem poglavlju ćemo pogledati uobičajene probleme koje aplikacije zasnovane na porukama treba da reše i razgovaraćemo o strategijama za njihovo rešavanje. Završit ćemo poglavlje navodeći kako općenito razgovarati o tehnologijama za razmjenu poruka kako biste mogli procijeniti njihovu prikladnost za vaše slučajeve upotrebe.

Prethodni prevedeni dio: Razumijevanje brokera poruka. Učenje mehanike razmjene poruka uz ActiveMQ i Kafku. Poglavlje 1

Prevod urađen: tele.gg/middle_java

Da se nastavi ...

Samo registrovani korisnici mogu učestvovati u anketi. Prijavite semolim.

Da li se Kafka koristi u vašoj organizaciji?

  • Da

  • Nijedan

  • Ranije korišteno, sada ne

  • Planiramo koristiti

Glasalo je 38 korisnika. Uzdržano je bilo 8 korisnika.

izvor: www.habr.com

Dodajte komentar