{"id":38172,"date":"2019-10-31T22:22:05","date_gmt":"2019-10-31T19:22:05","guid":{"rendered":"https:\/\/prohoster.info\/blog\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\/"},"modified":"2019-10-31T22:22:05","modified_gmt":"2019-10-31T19:22:05","slug":"ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","status":"publish","type":"post","link":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","title":{"rendered":"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Continuarea traducerii unei c\u0103r\u021bi mici:<br \/>\n\u201eUnderstanding Message Brokers\u201d,<br \/>\nautor: Jakub Korab, editura: O'Reilly Media, Inc., data public\u0103rii: iunie 2017, ISBN: 9781492049296.<\/p>\n<p>Partea precedent tradus\u0103: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 1. Introducere<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>CAPITOLUL 3<\/h2>\n<p><\/p>\n<h2>Kafka<\/h2>\n<p>\nKafka a fost dezvoltat\u0103 la LinkedIn pentru a ocoli unele dintre limit\u0103rile tradi\u021bionalelor brokeri de mesaje \u0219i a evita necesitatea de a configura mai mul\u021bi brokeri de mesaje pentru diferite interac\u021biuni \u201epunct la punct\u201d, a\u0219a cum este descris \u00een aceast\u0103 carte \u00een sec\u021biunea \u201eScalabilitate vertical\u0103 \u0219i orizontal\u0103\u201d de pe pagina 28. Scenariile de utilizare \u00een LinkedIn s-au bazat \u00een principal pe absorb\u021bia unidirec\u021bional\u0103 a unor volume foarte mari de date, cum ar fi clicurile pe pagini \u0219i jurnalele de acces, permi\u021b\u00e2nd \u00een acela\u0219i timp utilizarea acestor date de c\u0103tre mai multe sisteme, f\u0103r\u0103 a afecta performan\u021ba produc\u0103torilor sau a altor consumatori. De fapt, motivul existen\u021bei Kafka este acela de a ob\u021bine o arhitectur\u0103 de schimb de mesaje, a\u0219a cum este descris\u0103 \u00een Universal Data Pipeline.<\/p>\n<p>Av\u00e2nd \u00een vedere acest obiectiv final, s-au ivit \u0219i alte cerin\u021be. Kafka trebuie s\u0103:<\/p>\n<ul>\n<li>Fie extrem de rapid\u0103<\/li>\n<li>Ofer\u0103 un throughput mare \u00een gestionarea mesajelor<\/li>\n<li>S\u0103 sus\u021bin\u0103 modelele \u201ePublisher-Subscriber\u201d \u0219i \u201ePoint-to-Point\u201d<\/li>\n<li>S\u0103 nu se \u00eencetineasc\u0103 odat\u0103 cu ad\u0103ugarea consumatorilor. De exemplu, performan\u021ba at\u00e2t a coadelor, c\u00e2t \u0219i a topicelor \u00een ActiveMQ se deterioreaz\u0103 pe m\u0103sur\u0103 ce cre\u0219te num\u0103rul de consumatori pe destina\u021bie<\/li>\n<li>S\u0103 fie scalabil\u0103 orizontal; dac\u0103 un broker care stocheaz\u0103 (persists) mesaje poate face acest lucru doar la viteza maxim\u0103 a discului, atunci are sens s\u0103 ie\u0219im din limitele unui singur exemplu de broker pentru a cre\u0219te performan\u021ba<\/li>\n<li>S\u0103 limiteze accesul la stocare \u0219i reextrac\u021bia mesajelor<\/li>\n<\/ul>\n<p>\nPentru a atinge toate acestea, Kafka adopt\u0103 o arhitectur\u0103 care redefine\u0219te rolurile \u0219i responsabilit\u0103\u021bile clien\u021bilor \u0219i brokerilor de mesaje. Modelul JMS este foarte orientat spre broker, care este responsabil pentru distribu\u021bia mesajelor, iar clien\u021bii trebuie s\u0103 se ocupe doar de trimiterea \u0219i primirea mesajelor. Kafka, pe de alt\u0103 parte, este orientat\u0103 spre client, clientul asum\u00e2ndu-\u0219i multe func\u021bii tradi\u021bionale ale brokerului, cum ar fi distribuirea corect\u0103 a mesajelor relevante \u00eentre consumatori, ob\u021bin\u00e2nd \u00een schimb un broker extrem de rapid \u0219i scalabil. Pentru cei care au lucrat cu sisteme tradi\u021bionale de mesagerie, lucrul cu Kafka necesit\u0103 schimb\u0103ri fundamentale de mentalitate.<br \/>\nAceast\u0103 direc\u021bie de inginerie a dus la crearea unei infrastructuri de mesagerie capabil\u0103 s\u0103 creasc\u0103 cu multe ordine de m\u0103rime l\u0103\u021bimea de band\u0103 comparativ cu un broker obi\u0219nuit. A\u0219a cum vom vedea, aceast\u0103 abordare vine cu compromisuri, ceea ce \u00eenseamn\u0103 c\u0103 Kafka nu este potrivit\u0103 pentru anumite tipuri de sarcini \u0219i software stabilit.<\/p>\n<h3>Modelul unificat de destina\u021bie<\/h3>\n<p>\nPentru a \u00eendeplini cerin\u021bele descrise mai sus, Kafka a combinat mesageria de tip \u201epublicare-abonare\u201d \u0219i \u201epunct-la-punct\u201d \u00eentr-un singur tip de destina\u021bie \u2014 <i>subiect<\/i>. Acest lucru \u00eei confund\u0103 pe cei care au lucrat cu sisteme de mesagerie, unde termenul \u201esubiect\u201d se refer\u0103 la un mecanism de difuzare, din care (din subiect) citirea nu este fiabil\u0103 (este nondurabil). Subiectele din Kafka ar trebui considerate un tip hibrid de destina\u021bie, conform defini\u021biei date \u00een introducerea acestei c\u0103r\u021bi.<\/p>\n<blockquote><p>\u00cen restul acestui capitol, dac\u0103 nu indic\u0103m altfel, termenul \u201esubiect\u201d se va referi la subiectul Kafka.<\/p><\/blockquote>\n<p>\nPentru a \u00een\u021belege pe deplin cum se comport\u0103 subiectele \u0219i ce garan\u021bii ofer\u0103, trebuie mai \u00eent\u00e2i s\u0103 examin\u0103m cum sunt implementate \u00een Kafka.<br \/>\n<i>Fiecare subiect din Kafka are propriul jurnal.<\/i><br \/>\nProduc\u0103torii care trimit mesaje \u00een Kafka adaug\u0103 aceste mesaje \u00een jurnal, iar consumatorii citesc din jurnal folosind indicatoare care se deplaseaz\u0103 constant \u00eenainte. Periodic, Kafka \u0219terge cele mai vechi p\u0103r\u021bi ale jurnalului, indiferent dac\u0103 mesajele din aceste p\u0103r\u021bi au fost citite sau nu. O component\u0103 central\u0103 a designului Kafka este c\u0103 brokerul nu se preocup\u0103 de faptul c\u0103 mesajele au fost citite sau nu - aceasta este responsabilitatea clientului.<\/p>\n<blockquote><p>Termenii \u201ejurnal\u201d \u0219i \u201eindic\u0103tor\u201d nu sunt \u00eent\u00e2lni\u021bi \u00een <noindex><a rel=\"nofollow\" href=\"https:\/\/kafka.apache.org\/documentation.html\">documenta\u021bia Kafka<\/a><\/noindex>. Ace\u0219ti termeni bine cunoscu\u021bi sunt folosi\u021bi aici pentru a ajuta la \u00een\u021belegere.<\/p><\/blockquote>\n<p>\nAceast\u0103 modelare este complet diferit\u0103 de ActiveMQ, unde mesajele din toate cozi sunt stocate \u00eentr-un singur jurnal, iar brokerul marcheaz\u0103 mesajele ca fiind \u0219terse dup\u0103 ce au fost citite.<br \/>\nS\u0103 ne aprofund\u0103m acum \u0219i s\u0103 discut\u0103m despre jurnalul unui topic mai \u00een detaliu.<br \/>\nJurnalul Kafka const\u0103 din mai multe parti\u021bii (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/tm\/w2\/yf\/tmw2yf3lanppqtrumxoidotplhi.png\">Figura 3-1<\/a><\/noindex>). Kafka garanteaz\u0103 o ordonare strict\u0103 \u00een fiecare parti\u021bie. Aceasta \u00eenseamn\u0103 c\u0103 mesajele scrise \u00eentr-o parti\u021bie \u00eentr-o anumit\u0103 ordine vor fi citite \u00een aceea\u0219i ordine. Fiecare parti\u021bie este implementat\u0103 sub forma unui fi\u0219ier de jurnal ciclic (rolling) care con\u021bine <i>un subset <\/i>(subset) al tuturor mesajelor trimise c\u0103tre topic de produc\u0103torii s\u0103i. Topicul creat con\u021bine, \u00een mod implicit, o parti\u021bie. Ideea de parti\u021bii este conceptul central al Kafka pentru scalarea orizontal\u0103.<\/p>\n<p><img decoding=\"async\" alt=\"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/39f41ebcb73ec247656c0dea438158a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-1. Parti\u021biile Kafka<\/i><\/p>\n<p>C\u00e2nd un produc\u0103tor trimite un mesaj \u00eentr-un topic Kafka, decide \u00een care parti\u021bie s\u0103 trimit\u0103 mesajul. Vom discuta despre acest lucru mai \u00een detaliu mai t\u00e2rziu.<\/p>\n<h2>Citirea mesajelor<\/h2>\n<p>\nClientul care dore\u0219te s\u0103 citeasc\u0103 mesajele gestioneaz\u0103 un indic\u0103tor numit <i>grup de consumatori (consumer group)<\/i>, care indic\u0103 <i>deplasamentul (offset)<\/i> mesajului din parti\u021bie. Deplasamentul este o pozi\u021bie cu un num\u0103r cresc\u0103tor care \u00eencepe de la 0 la \u00eenceputul parti\u021biei. Acest grup de consumatori, la care se face referire \u00een API printr-un identificator group_id definit de utilizator, corespunde <i>unui consumator sau sistem logic.<\/i>.<\/p>\n<p>Cele mai multe sisteme care utilizeaz\u0103 mesagerie citesc datele din adresa destinatarului prin intermediul mai multor instan\u021be \u0219i fluxuri pentru procesarea paralel\u0103 a mesajelor. Astfel, de obicei, vor exista multe instan\u021be de consumatori care partajeaz\u0103 acela\u0219i grup de consumatori.<\/p>\n<p>Problema citirii poate fi prezentat\u0103 astfel:<\/p>\n<ul>\n<li>Un topic are mai multe parti\u021bii<\/li>\n<li>Mai multe grupuri de consumatori pot folosi un topic simultan<\/li>\n<li>Un grup de consumatori poate avea mai multe instan\u021be separate<\/li>\n<\/ul>\n<p>\nAceasta este o problem\u0103 netrivial\u0103 de tip \u201emul\u021bi la mul\u021bi\u201d. Pentru a \u00een\u021belege cum gestioneaz\u0103 Kafka rela\u021biile dintre grupurile de consumatori, instan\u021bele de consumatori \u0219i parti\u021bii, s\u0103 analiz\u0103m o serie de scenarii de citire care devin treptat mai complexe.<\/p>\n<h3>Consumatori \u0219i grupuri de consumatori<\/h3>\n<p>\nS\u0103 lu\u0103m ca punct de plecare un topic cu o singur\u0103 parti\u021bie (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/6z\/tz\/dh\/6ztzdhqmjweck-z15htxb2xbe28.png\">Figura 3-2<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/46c92e6bd38774dfef3be4bd198bf35d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-2. Consumatorul cite\u0219te din parti\u021bie<\/i><\/p>\n<p>C\u00e2nd o instan\u021b\u0103 de consumator se conecteaz\u0103 cu propriul s\u0103u group_id la acest topic, \u00eei este alocat\u0103 o parti\u021bie pentru citire \u0219i un offset \u00een acea parti\u021bie. Pozi\u021bia acestui offset este configurat\u0103 \u00een client ca un pointer c\u0103tre cea mai recent\u0103 pozi\u021bie (cel mai nou mesaj) sau cea mai veche pozi\u021bie (cel mai vechi mesaj). Consumatorul solicit\u0103 (polls) mesaje din topic, ceea ce duce la citirea secven\u021bial\u0103 a acestora din jurnal.<br \/>\nPozi\u021bia offset-ului este comis\u0103 periodic \u00eenapoi \u00een Kafka \u0219i este p\u0103strat\u0103, ca mesaje \u00een topicul intern <i>_consumer_offsets<\/i>. Mesajele citite totu\u0219i nu sunt eliminate, spre deosebire de un broker obi\u0219nuit, iar clientul poate derula (rewind) offset-ul pentru a reprocessa mesajele deja vizualizate.<\/p>\n<p>C\u00e2nd un al doilea consumator logic se conecteaz\u0103, folosind un alt group_id, el gestioneaz\u0103 un al doilea pointer, care nu depinde de primul (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/qe\/v1\/yk\/qev1yktga3s-g1gqlynylbe3n9w.png\">Figura 3-3<\/a><\/noindex>). Astfel, topicul Kafka func\u021bioneaz\u0103 ca o coad\u0103, \u00een care exist\u0103 un singur consumator \u0219i, ca un topic obi\u0219nuit de tip publisher-subscriber (pub-sub), la care sunt abona\u021bi mai mul\u021bi consumatori, av\u00e2nd avantajul suplimentar c\u0103 toate mesajele sunt p\u0103strate \u0219i pot fi procesate de mai multe ori.<\/p>\n<p><img decoding=\"async\" alt=\"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/e9e8b9063ef7367005254d36abb47f4f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-3. Doi consumatori din grupuri de consumatori diferite citesc din aceea\u0219i parti\u021bie<\/i><\/p>\n<h3>Consumatori \u00een grupul de consumatori<\/h3>\n<p>\nC\u00e2nd o instan\u021b\u0103 a consumatorului cite\u0219te date dintr-o parti\u021bie, aceasta controleaz\u0103 complet pointerul \u0219i proceseaz\u0103 mesajele, a\u0219a cum a fost descris \u00een sec\u021biunea anterioar\u0103.<br \/>\nDac\u0103 mai multe instan\u021be ale consumatorilor au fost conectate cu acela\u0219i group_id la un topic care are o parti\u021bie, atunci instan\u021bei care s-a conectat ultima \u00eei va fi transferat controlul asupra pointerului, iar de atunci \u00eenainte va primi toate mesajele (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/0j\/ao\/f2\/0jaof2mdwg3cqvmwemhtxkrltuq.png\">Figura 3-4<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/ec6af819445dad4028f65449a735ae22.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-4. Dou\u0103 consumatoare din aceea\u0219i grup\u0103 de consumatori citesc din aceea\u0219i parti\u021bie<\/i><\/p>\n<p>Acest mod de procesare, \u00een care num\u0103rul de instan\u021be ale consumatorilor dep\u0103\u0219e\u0219te num\u0103rul de parti\u021bii, poate fi considerat o varia\u021bie a consumatorului monopol. Acest lucru poate fi util dac\u0103 ai nevoie de o clasterizare \u201eactiv-\u00een a\u0219teptare\u201d (sau \u201eplictisit\u0103-c\u0103ldu\u021b\u0103\u201d) a instan\u021belor tale de consumatori, de\u0219i func\u021bionarea paralel\u0103 a mai multor consumatori (\u201eactiv-activ\u201d sau \u201eplictisit\u0103-plictisit\u0103\u201d) este mult mai tipic\u0103 dec\u00e2t consumatorii \u00een modul de a\u0219teptare.<\/p>\n<blockquote><p>Comportamentul de distribu\u021bie a mesajelor descris mai sus poate fi surprinz\u0103tor \u00een compara\u021bie cu modul \u00een care func\u021bioneaz\u0103 o coad\u0103 JMS obi\u0219nuit\u0103. \u00cen acest model, mesajele trimise \u00eentr-o coad\u0103 vor fi distribuite uniform \u00eentre cele dou\u0103 consumatoare.<\/p><\/blockquote>\n<p>\nCel mai adesea, atunci c\u00e2nd cre\u0103m mai multe instan\u021be ale consumatorilor, facem acest lucru fie pentru procesarea paralel\u0103 a mesajelor, fie pentru cre\u0219terea vitezei de citire, fie pentru \u00eembun\u0103t\u0103\u021birea rezilien\u021bei procesului de citire. Deoarece datele dintr-o parti\u021bie pot fi citite simultan doar de o singur\u0103 instan\u021b\u0103 a consumatorului, cum se realizeaz\u0103 acest lucru \u00een Kafka?<\/p>\n<p>Un mod de a face acest lucru este s\u0103 folose\u0219ti o singur\u0103 instan\u021b\u0103 a consumatorului pentru a citi toate mesajele \u0219i a le trimite \u00eentr-un pool de thread-uri. De\u0219i aceast\u0103 abordare cre\u0219te capacitatea de procesare, spore\u0219te complexitatea logicii consumatorilor \u0219i nu \u00eembun\u0103t\u0103\u021be\u0219te rezilien\u021ba sistemului de citire. Dac\u0103 o instan\u021b\u0103 a consumatorului se opre\u0219te din cauza unei pene de curent sau a unui eveniment similar, citirea se opre\u0219te.<\/p>\n<p>Modul canonical de a rezolva aceast\u0103 problem\u0103 \u00een Kafka este s\u0103 folose\u0219ti un<i>O<\/i>num\u0103r mai mare de parti\u021bii.<\/p>\n<h3>Parti\u021bionare<\/h3>\n<p>\nParti\u021biile sunt mecanismul principal pentru paralelizarea citirii \u0219i scalarea subiectului dincolo de capacitatea unui singur broker. Pentru a \u00een\u021belege mai bine acest lucru, s\u0103 analiz\u0103m situa\u021bia \u00een care exist\u0103 un subiect cu dou\u0103 parti\u021bii, iar un consumator se aboneaz\u0103 la acest subiect (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/en\/9g\/ct\/en9gct0o017cqp8buawguwlscty.png\">Figura 3-5<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/cc766bf69af22698aacc3f1ac70b067f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-5. Un consumator cite\u0219te din mai multe parti\u021bii<\/i><\/p>\n<p>\u00cen acest scenariu, consumatorului i se ofer\u0103 control asupra pointerilor corespunz\u0103tori group_id-ului s\u0103u \u00een ambele parti\u021bii \u0219i \u00eencepe citirea mesajelor din ambele parti\u021bii.<br \/>\nC\u00e2nd la acest subiect se adaug\u0103 un consumator suplimentar pentru acela\u0219i group_id, Kafka \u00ee\u0219i reasigneaz\u0103 (reallocate) una dintre parti\u021bii de la primul la al doilea consumator. Dup\u0103 aceea, fiecare instan\u021b\u0103 a consumatorului va citi dintr-o parti\u021bie a subiectului (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/8b\/a0\/um\/8ba0umn2yzr9yy3vztonhdfiub0.png\">Figura 3-6<\/a><\/noindex>).<\/p>\n<p>Pentru a asigura procesarea mesajelor \u00een paralel \u00een 20 de fire, ave\u021bi nevoie de cel pu\u021bin 20 de parti\u021bii. Dac\u0103 exist\u0103 mai pu\u021bine parti\u021bii, ve\u021bi avea consumatori care nu vor avea nimic de procesat, a\u0219a cum s-a discutat anterior \u00een cazul consumatorilor monopol.<\/p>\n<p><img decoding=\"async\" alt=\"\u00cen\u021belegerea brokerilor de mesaje. Studierea mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/a3c4001e4a5b92d53b6f529b2633254a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figura 3-6. Doi consumatori din aceea\u0219i grup\u0103 de consumatori citesc din diferite parti\u021bii<\/i><\/p>\n<p>Aceast\u0103 schem\u0103 reduce semnificativ complexitatea func\u021bion\u0103rii brokerului Kafka comparativ cu distribu\u021bia mesajelor necesar\u0103 pentru sus\u021binerea unei cozi JMS. Aici nu trebuie s\u0103 v\u0103 face\u021bi griji cu privire la urm\u0103toarele aspecte:<\/p>\n<ul>\n<li>Care consumator ar trebui s\u0103 primeasc\u0103 urm\u0103torul mesaj, pe baza distribuirii circulare (round-robin), a capacit\u0103\u021bii curente a bufferelor de preluare sau a mesajelor anterioare (ca \u00een cazul grupurilor de mesaje JMS).<\/li>\n<li>Ce mesaje au fost trimise c\u0103tre care consumatori \u0219i dac\u0103 acestea ar trebui s\u0103 fie livrate din nou \u00een caz de e\u0219ec.<\/li>\n<\/ul>\n<p>\nTot ceea ce trebuie s\u0103 fac\u0103 brokerul Kafka este s\u0103 transmit\u0103 \u00een mod secven\u021bial mesajele consumatorului, atunci c\u00e2nd acesta le solicit\u0103.<\/p>\n<p>Cu toate acestea, cerin\u021bele pentru paralelizarea citirii \u0219i retrimiterea mesajelor e\u0219uate nu dispar \u2014 responsabilitatea pentru acestea se transfer\u0103 simplu de la broker la client. Aceasta \u00eenseamn\u0103 c\u0103 ele trebuie s\u0103 fie considerate \u00een codul dumneavoastr\u0103.<\/p>\n<h2>Trimiterea mesajelor<\/h2>\n<p>\nResponsabilitatea de a decide \u00een care parti\u021bie s\u0103 fie trimis un mesaj revine producerului acestui mesaj. Pentru a \u00een\u021belege mecanismul prin care se face acest lucru, trebuie mai \u00eent\u00e2i s\u0103 analiz\u0103m ce anume trimitem de fapt.<\/p>\n<p>\u00cen timp ce \u00een JMS folosim o structur\u0103 de mesaj cu metadate (antete \u0219i propriet\u0103\u021bi) \u0219i un corp care con\u021bine sarcina util\u0103 (payload), \u00een Kafka, un mesaj este <i>un pereche \u201echeie-valoare\u201d<\/i>. Sarcina util\u0103 a mesajului este trimis\u0103 ca valoare (value). Cheia, pe de alt\u0103 parte, este folosit\u0103 \u00een principal pentru partajare \u0219i ar trebui s\u0103 con\u021bin\u0103 <i>o cheie specific\u0103 logicii de afaceri<\/i>, astfel \u00eenc\u00e2t s\u0103 plaseze mesajele corelate \u00een aceea\u0219i parti\u021bie.<\/p>\n<p>\u00cen Capitolul 2, am discutat scenariul pariurilor online, c\u00e2nd evenimentele corelate trebuie s\u0103 fie procesate \u00een ordinea corect\u0103 de c\u0103tre un consumator:<\/p>\n<ol>\n<li>Contul utilizatorului este configurat.<\/li>\n<li>Banii sunt transfera\u021bi \u00een cont.<\/li>\n<li>Se face o pariu, care scoate bani din cont.<\/li>\n<\/ol>\n<p>\nDac\u0103 fiecare eveniment reprezint\u0103 un mesaj trimis \u00eentr-un topic, \u00een acest caz, cheia natural\u0103 va fi identificatorul contului.<br \/>\nC\u00e2nd un mesaj este trimis folosind Kafka Producer API, acesta este redirec\u021bionat c\u0103tre func\u021bia de partajare, care, av\u00e2nd \u00een vedere mesajul \u0219i starea curent\u0103 a cluster-ului Kafka, returneaz\u0103 identificatorul parti\u021biei \u00een care mesajul ar trebui s\u0103 fie trimis. Aceast\u0103 func\u021bie este implementat\u0103 \u00een Java prin intermediul interfe\u021bei Partitioner.<\/p>\n<p>Aceast\u0103 interfa\u021b\u0103 arat\u0103 astfel:<\/p>\n<pre><code class=\"java\">interface Partitioner {\n    int partition(String topic,\n        Object key, byte[] keyBytes, Object value, byte[] valueBytes, Cluster cluster);\n}<\/code><\/pre>\n<p>\nImplementarea Partitioner pentru determinarea parti\u021biei folose\u0219te, \u00een mod implicit, algoritmul de hashing al cheii (general-purpose hashing algorithm over the key) sau rotirea (round-robin), dac\u0103 cheia nu este specificat\u0103. Aceast\u0103 valoare implicit\u0103 func\u021bioneaz\u0103 bine \u00een majoritatea cazurilor. Totu\u0219i, \u00een viitor, poate dori\u021bi s\u0103 scrie\u021bi propria metod\u0103.<\/p>\n<h3>Scrierea propriei strategii de partajare<\/h3>\n<p>\nS\u0103 lu\u0103m un exemplu \u00een care dori\u021bi s\u0103 trimite\u021bi metadate \u00eempreun\u0103 cu sarcina util\u0103 a mesajului. Sarcina util\u0103 \u00een exemplul nostru este instruc\u021biunea de a face un depozit \u00een contul de joc. Instruc\u021biunea este ceea ce am dori s\u0103 nu modific\u0103m garantat \u00een timpul transmiterii \u0219i vrem s\u0103 ne asigur\u0103m c\u0103 doar sistemul de \u00eencredere superior poate ini\u021bia aceast\u0103 instruc\u021biune. \u00cen acest caz, sistemele emitent \u0219i receptor se pun de acord s\u0103 utilizeze o semn\u0103tur\u0103 pentru a verifica autentificarea mesajului.<br \/>\n\u00centr-un JMS obi\u0219nuit, pur \u0219i simplu definim proprietatea \u201esemn\u0103tur\u0103 a mesajului\u201d \u0219i o ad\u0103ug\u0103m la mesaj. Cu toate acestea, Kafka nu ne ofer\u0103 un mecanism pentru transmiterea metadatelor \u2014 doar cheie \u0219i valoare.<\/p>\n<p>Deoarece valoarea reprezint\u0103 sarcina util\u0103 a transferului bancar (bank transfer payload), integritatea c\u0103reia vrem s\u0103 o men\u021binem, nu avem alt\u0103 op\u021biune dec\u00e2t s\u0103 definim structura de date pentru utilizarea \u00een cheie. Presupun\u00e2nd c\u0103 avem nevoie de un identificator al contului pentru partitionare, deoarece toate mesajele referitoare la cont trebuie s\u0103 fie procesate \u00een ordine, vom veni cu urm\u0103toarea structur\u0103 JSON:<\/p>\n<pre><code class=\"json\">{\n  \"signature\": \"541661622185851c248b41bf0cea7ad0\",\n  \"accountId\": \"10007865234\"\n}<\/code><\/pre>\n<p>\nDeoarece valoarea semn\u0103turii va varia \u00een func\u021bie de sarcina util\u0103, strategia de hashing implicit\u0103 a interfe\u021bei Partitioner nu va grupa \u00een mod fiabil mesajele corelate. Prin urmare, va trebui s\u0103 scriem propria noastr\u0103 strategie care va analiza aceast\u0103 cheie \u0219i va partitiona valoarea accountId.<\/p>\n<blockquote><p>Kafka include checksum-uri pentru a detecta deteriorarea mesajelor \u00een stocare \u0219i are un set complet de func\u021bii de securitate. Chiar \u0219i a\u0219a, uneori apar cerin\u021be specifice industriei, cum ar fi cea men\u021bionat\u0103 mai sus.<\/p><\/blockquote>\n<p>\nStrategia personalizat\u0103 de partitionare trebuie s\u0103 garanteze c\u0103 toate mesajele corelate se vor afla \u00een aceea\u0219i parti\u021bie. De\u0219i aceasta pare simpl\u0103, cerin\u021ba poate fi complicat\u0103 de importan\u021ba ordon\u0103rii mesajelor corelate \u0219i c\u00e2t de fixat este num\u0103rul de parti\u021bii din topic.<\/p>\n<p>Num\u0103rul de parti\u021bii din topic poate varia \u00een timp, deoarece acestea pot fi ad\u0103ugate dac\u0103 traficul dep\u0103\u0219e\u0219te a\u0219tept\u0103rile ini\u021biale. Astfel, cheile mesajelor pot fi legate de parti\u021bia \u00een care au fost trimise ini\u021bial, implic\u00e2nd o parte din starea care trebuie distribuit\u0103 \u00eentre instan\u021bele produc\u0103torului.<\/p>\n<p>Un alt factor de avut \u00een vedere este uniformitatea distribuirii mesajelor \u00eentre parti\u021bii. \u00cen general, cheile nu sunt distribuite uniform \u00een mesaje, iar func\u021biile de hash nu garanteaz\u0103 o distribu\u021bie echitabil\u0103 a mesajelor pentru un set mic de chei.<br \/>\nEste important de men\u021bionat c\u0103, indiferent de modul \u00een care decide\u021bi s\u0103 \u00eemp\u0103r\u021bi\u021bi mesajele, separatorul \u00een sine poate necesita reutilizare.<\/p>\n<p>S\u0103 lu\u0103m \u00een considerare cerin\u021ba replic\u0103rii datelor \u00eentre clustere Kafka situate \u00een diferite loca\u021bii geografice. \u00cen acest scop, Kafka vine cu un instrument de linie de comand\u0103 numit MirrorMaker, care este utilizat pentru a citi mesajele dintr-un cluster \u0219i a le transmite \u00eentr-un alt cluster.<\/p>\n<p>MirrorMaker trebuie s\u0103 \u00een\u021beleag\u0103 cheile topicului replicat pentru a men\u021bine ordinea relativ\u0103 \u00eentre mesaje \u00een timpul replic\u0103rii \u00eentre clustere, deoarece num\u0103rul de partitii pentru acest topic poate s\u0103 nu coincid\u0103 \u00eentre cele dou\u0103 clustere.<\/p>\n<p>Strategiile personalizate de partizionare sunt relativ rare, deoarece hashingul sau rotirea implicit\u0103 func\u021bioneaz\u0103 cu succes \u00een majoritatea scenariilor. Cu toate acestea, dac\u0103 ave\u021bi nevoie de garan\u021bii stricte de ordonare sau trebuie s\u0103 extrage\u021bi metadate din sarcinile utile, atunci partizionarea este ceva la care ar trebui s\u0103 v\u0103 g\u00e2ndi\u021bi mai \u00een detaliu.<\/p>\n<p>Avantajele scalabilit\u0103\u021bii \u0219i performan\u021bei Kafka sunt datorate transfer\u0103rii unor responsabilit\u0103\u021bi tradi\u021bionale ale broker-ului c\u0103tre client. \u00cen acest caz, se ia decizia de a distribui mesaje poten\u021bial corelate \u00eentre mai mul\u021bi consumatori care func\u021bioneaz\u0103 \u00een paralel.<\/p>\n<blockquote><p>Brokerii JMS trebuie, de asemenea, s\u0103 se ocupe de aceste cerin\u021be. Interesant este c\u0103 mecanismul de livrare a mesajelor corelate aceluia\u0219i consumator, realizat prin JMS Message Groups (un tip de strategie de echilibrare a \u00eenc\u0103rc\u0103rii sticky load balancing (SLB)), necesit\u0103, de asemenea, ca expeditorul s\u0103 eticheteze mesajele ca fiind corelate. \u00cen cazul JMS, brokerul este responsabil pentru livrarea acestui grup de mesaje corelate unui consumator din mul\u021bi \u0219i pentru transferul dreptului de proprietate asupra grupului dac\u0103 consumatorul se \u00eentrerupe.<\/p><\/blockquote>\n<p><\/p>\n<h2>Acorduri pentru produc\u0103tor<\/h2>\n<p>\nParticionarea nu este singurul aspect de luat \u00een considerare atunci c\u00e2nd trimite\u021bi mesaje. S\u0103 examin\u0103m metodele send() ale clasei Producer din Java API:<\/p>\n<pre><code class=\"java\">Future  send(ProducerRecord  record);\nFuture  send(ProducerRecord  record, Callback callback);<\/code><\/pre>\n<p>\nEste important de men\u021bionat c\u0103 ambele metode returneaz\u0103 un Future, ceea ce indic\u0103 faptul c\u0103 opera\u021biunea de trimitere nu se efectueaz\u0103 imediat. Drept urmare, mesajul (ProducerRecord) este \u00eenregistrat \u00een buffer-ul de trimitere pentru fiecare parti\u021bie activ\u0103 \u0219i este transmis brokerului printr-un fir de fundal \u00een biblioteca clientului Kafka. De\u0219i acest lucru face ca opera\u021biunea s\u0103 fie incredibil de rapid\u0103, \u00eenseamn\u0103 c\u0103 o aplica\u021bie prost scris\u0103 poate pierde mesaje dac\u0103 procesul s\u0103u se opre\u0219te.<\/p>\n<p>Ca \u00eentotdeauna, exist\u0103 o modalitate de a face opera\u021biunea de trimitere mai fiabil\u0103 \u00een detrimentul performan\u021bei. Dimensiunea acestui buffer poate fi setat\u0103 la 0, iar firul de trimitere al aplica\u021biei va fi for\u021bat s\u0103 a\u0219tepte p\u00e2n\u0103 la finalizarea transmiterii mesajului c\u0103tre broker, dup\u0103 cum urmeaz\u0103:<\/p>\n<pre><code class=\"java\">RecordMetadata metadata = producer.send(record).get();<\/code><\/pre>\n<p><\/p>\n<h2>\u00cenc\u0103 o dat\u0103 despre citirea mesajelor<\/h2>\n<p>\nCitirea mesajelor are complexit\u0103\u021bi suplimentare despre care trebuie s\u0103 ne g\u00e2ndim. Spre deosebire de API-ul JMS, care poate lansa un listener de mesaje (message listener) \u00een r\u0103spuns la sosirea unui mesaj, interfa\u021ba <i>Consumer <\/i>Kafka doar interogheaz\u0103 (polling). S\u0103 examin\u0103m mai \u00een detaliu metoda <i>poll ()<\/i>, folosit\u0103 \u00een acest scop:<\/p>\n<pre><code class=\"java\">ConsumerRecords  poll(long timeout);<\/code><\/pre>\n<p>\nValoarea returnat\u0103 de metod\u0103 este o structur\u0103 deContainere care con\u021bine mai multe obiecte <i>ConsumerRecord <\/i>din poten\u021bial mai multe parti\u021bii. <i>ConsumerRecord <\/i>este el \u00eensu\u0219i un obiect holder pentru o pereche cheie-valoare cu metadate corespunz\u0103toare, cum ar fi parti\u021bia din care a fost ob\u021binut.<\/p>\n<p>A\u0219a cum s-a discutat \u00een Capitolul 2, trebuie s\u0103 ne amintim constant ce se \u00eent\u00e2mpl\u0103 cu mesajele dup\u0103 procesarea lor cu succes sau e\u0219uat\u0103, de exemplu, dac\u0103 clientul nu poate procesa mesajul sau dac\u0103 se opre\u0219te. \u00cen JMS, acest lucru era gestionat prin modul de confirmare (acknowledgement mode). Brokerul va \u0219terge fie mesajul procesat cu succes, fie va re livra mesajul neprocesat sau e\u0219uat (cu condi\u021bia ca tranzac\u021biile s\u0103 fi fost utilizate). <br \/>\nKafka func\u021bioneaz\u0103 complet diferit. Mesajele nu sunt \u0219terse \u00een broker dup\u0103 citire, iar responsabilitatea pentru ceea ce se \u00eent\u00e2mpl\u0103 \u00een cazul unei erori revine codului care face citirea.<\/p>\n<p>A\u0219a cum am men\u021bionat anterior, grupul de consumatori este legat de offset-ul din jurnal. Pozi\u021bia din jurnal asociat\u0103 acestui offset corespunde urm\u0103torului mesaj care va fi emis ca r\u0103spuns la <i>poll ()<\/i>Momentele \u00een care aceast\u0103 deplasare cre\u0219te au o semnifica\u021bie crucial\u0103 la citire.<\/p>\n<p>Revenind la modelul de citire prezentat anterior, procesarea mesajului const\u0103 \u00een trei etape:<\/p>\n<ol>\n<li>Extrage mesajul pentru citire.<\/li>\n<li>Proceseaz\u0103 mesajul.<\/li>\n<li>Confirm\u0103 mesajul.<\/li>\n<\/ol>\n<p>\nConsumatorul Kafka vine cu o op\u021biune de configurare <i>enable.auto.commit<\/i>. Aceasta este o setare implicit\u0103 utilizat\u0103 frecvent, a\u0219a cum se \u00eent\u00e2mpl\u0103 de obicei cu set\u0103rile care con\u021bin cuv\u00e2ntul \u201eauto\u201d.<\/p>\n<p>P\u00e2n\u0103 la Kafka 0.10, clientul care utiliza acest parametru trimitea deplasarea ultimului mesaj citit la urm\u0103toarea apelare <i>poll ()<\/i> dup\u0103 procesare. Asta \u00eensemna c\u0103 orice mesaje care au fost deja extrase (fetched) puteau fi procesate din nou, dac\u0103 clientul le-a procesat deja, dar a fost distrus nea\u0219teptat \u00eenainte de apel. <i>poll ()<\/i>. Deoarece brokerul nu p\u0103streaz\u0103 niciun fel de stare referitoare la c\u00e2te ori a fost citit un mesaj, urm\u0103torul consumator care extrage acest mesaj nu va \u0219ti c\u0103 s-a \u00eent\u00e2mplat ceva r\u0103u. Acest comportament a fost pseudo-transactional. Deplasarea a fost confirmat\u0103 doar \u00een cazul \u00een care mesajul a fost procesat cu succes, dar dac\u0103 clientul \u00eentrerupe activitatea, brokerul retransmite acela\u0219i mesaj unui alt client. Acest comportament corespundea garan\u021biei de livrare a mesajelor \u00ab<i>cel pu\u021bin o dat\u0103<\/i>&#171;.<\/p>\n<p>\u00cen Kafka 0.10, codul clientului a fost modificat astfel \u00eenc\u00e2t commit-ul s\u0103 fie ini\u021biat periodic de biblioteca clientului, conform set\u0103rii <i>auto.commit.interval.ms<\/i>. Acest comportament se afl\u0103 undeva \u00eentre modurile JMS AUTO_ACKNOWLEDGE \u0219i DUPS_OK_ACKNOWLEDGE. C\u00e2nd se folose\u0219te auto-commit, mesajele puteau fi confirmate indiferent dac\u0103 au fost de fapt procesate \u2014 acest lucru se putea \u00eent\u00e2mpla \u00een cazul \u00een care consumatorul era lent. Dac\u0103 consumatorul se \u00eentrerupe, mesajele erau extrase de urm\u0103torul consumator, \u00eencep\u00e2nd de la pozi\u021bia confirmat\u0103, ceea ce putea duce la omiterea unor mesaje. \u00cen acest caz, Kafka nu pierdea mesaje, codul de citire pur \u0219i simplu nu le procesa.<\/p>\n<p>Acest mod are acelea\u0219i perspective ca \u00een versiunea 0.9: mesajele pot fi procesate, dar \u00een caz de e\u0219ec, deplasarea poate s\u0103 nu fie confirmat\u0103, ceea ce poate duce la duplicarea livr\u0103rii. Cu c\u00e2t extragi mai multe mesaje \u00een timpul <i>poll ()<\/i>, cu at\u00e2t mai mare este aceast\u0103 problem\u0103.<\/p>\n<p>A\u0219a cum s-a discutat \u00een sec\u021biunea \u201eCitirea mesajelor din coad\u0103\u201d de pe pagina 21, \u00een sistemul de mesagerie nu exist\u0103 no\u021biunea de livrare unic\u0103 a mesajului, dac\u0103 lu\u0103m \u00een considerare modurile de e\u0219ec.<\/p>\n<p>\u00cen Kafka, exist\u0103 dou\u0103 modalit\u0103\u021bi de a marca (a comite) offsetul: automat \u0219i manual. \u00cen ambele cazuri, mesajele pot fi procesate de mai multe ori, \u00een cazul \u00een care mesajul a fost procesat, dar a avut loc o eroare \u00eenainte de comitere. De asemenea, este posibil s\u0103 nu procesa\u021bi deloc un mesaj dac\u0103 comiterea a avut loc \u00een fundal \u0219i codul dumneavoastr\u0103 a fost finalizat \u00eenainte de a \u00eencepe procesarea (poate \u00een Kafka 0.9 \u0219i versiunile anterioare).<\/p>\n<p>Gestionarea procesului de comitere a offset-ului manual poate fi realizat\u0103 \u00een API-ul consumatorului Kafka, set\u00e2nd parametrul <i>enable.auto.commit<\/i> la false \u0219i apel\u00e2nd explicit una dintre urm\u0103toarele metode:<\/p>\n<pre><code class=\"java\">void commitSync();\nvoid commitAsync();<\/code><\/pre>\n<p>\nDac\u0103 dori\u021bi s\u0103 procesa\u021bi un mesaj \u201ecel pu\u021bin o dat\u0103\u201d, trebuie s\u0103 comite\u021bi offsetul manual cu ajutorul <i>commitSync ()<\/i>, execut\u00e2nd aceast\u0103 comand\u0103 imediat dup\u0103 procesarea mesajelor.<\/p>\n<p>Aceste metode nu permit confirmarea (acknowledged) mesajelor p\u00e2n\u0103 c\u00e2nd nu sunt procesate, dar nu fac nimic pentru a elimina poten\u021bialele duplic\u0103ri de procesare, cre\u00e2nd \u00een acela\u0219i timp aparen\u021ba tranzac\u021bionalit\u0103\u021bii. \u00cen Kafka nu exist\u0103 tranzac\u021bii. Clientul nu poate realiza urm\u0103toarele:<\/p>\n<ul>\n<li>Anula automat (roll back) un mesaj e\u0219uat. Consumatorii trebuie s\u0103 gestioneze singuri excep\u021biile care apar din cauza payload-urilor problematice \u0219i a deconect\u0103rilor din backend, deoarece nu se pot baza pe livrarea repetat\u0103 a mesajelor de c\u0103tre broker.<\/li>\n<li>Trimite mesaje \u00een mai multe topicuri \u00eentr-o singur\u0103 opera\u021biune atomic\u0103. A\u0219a cum vom vedea \u00een cur\u00e2nd, controlul asupra diferitelor topicuri \u0219i parti\u021bii poate fi distribuit pe ma\u0219ini diferite \u00een clusterul Kafka, care nu coordoneaz\u0103 tranzac\u021biile la trimitere. P\u00e2n\u0103 la momentul redact\u0103rii acestui articol, au fost realizate unele lucr\u0103ri pentru a face acest lucru posibil prin KIP-98.<\/li>\n<li>A lega citirea unui mesaj dintr-un topic de trimiterea unui alt mesaj \u00eentr-un alt topic. Din nou, arhitectura Kafka depinde de multe ma\u0219ini independente care func\u021bioneaz\u0103 ca un singur bus \u0219i nu se fac \u00eencerc\u0103ri de a ascunde acest lucru. De exemplu, nu exist\u0103 componente API care s\u0103 permit\u0103 legarea <i>Consumator <\/i>\u0219i <i>Produc\u0103tor <\/i>\u00een tranzac\u021bie. \u00cen JMS, acest lucru este asigurat de obiectul <i>Sesiune<\/i>, din care sunt create <i>Produse de mesaje <\/i>\u0219i <i>Consumatori de mesaje<\/i>.<\/li>\n<\/ul>\n<p>\nDac\u0103 nu ne putem baza pe tranzac\u021bii, cum putem asigura o semantica mai apropiat\u0103 de cea furnizat\u0103 de sistemele tradi\u021bionale de mesagerie?<\/p>\n<p>Dac\u0103 exist\u0103 riscul ca offset-ul consumatorului s\u0103 creasc\u0103 \u00eenainte de a fi procesat mesajul, de exemplu, \u00een timpul unei erori a consumatorului, consumatorul nu are nicio modalitate de a \u0219ti dac\u0103 grupul s\u0103u de consumatori a ratat mesaje atunci c\u00e2nd i se atribuie o parti\u021bie. Astfel, una dintre strategii const\u0103 \u00een a derula (rewind) offset-ul la o pozi\u021bie anterioar\u0103. API-ul consumatorului Kafka ofer\u0103 urm\u0103toarele metode pentru acest lucru:<\/p>\n<pre><code class=\"java\">void seek(TopicPartition partition, long offset);\nvoid seekToBeginning(Collection  partitions);<\/code><\/pre>\n<p>\nMetoda <i>seek()<\/i> poate fi folosit cu metoda <br \/>\n<i>offsetsForTimes (Map timestampsToSearch)<\/i> pentru a derula la un anumit moment din trecut.<\/p>\n<p>Implicit, utilizarea acestei abord\u0103ri \u00eenseamn\u0103 c\u0103 este foarte probabil ca unele mesaje care au fost procesate anterior s\u0103 fie citite \u0219i procesate din nou. Pentru a evita acest lucru, putem utiliza citirea idempotent\u0103, a\u0219a cum este descris \u00een Capitolul 4, pentru a urm\u0103ri mesajele vizualizate anterior \u0219i a exclude duplicatele.<\/p>\n<p>Alternativ, codul consumatorului dumneavoastr\u0103 poate fi simplu, dac\u0103 se accept\u0103 pierderea sau dublarea mesajelor. C\u00e2nd analiz\u0103m scenariile de utilizare pentru care este utilizat de obicei Kafka, cum ar fi procesarea evenimentelor jurnalelor, metricilor, urm\u0103rirea clicurilor etc., \u00een\u021belegem c\u0103 pierderea unor mesaje individuale va avea probabil un impact semnificativ redus asupra aplica\u021biilor \u00eenconjur\u0103toare. \u00cen astfel de cazuri, valorile implicite sunt perfect acceptabile. Pe de alt\u0103 parte, dac\u0103 aplica\u021bia dumneavoastr\u0103 trebuie s\u0103 transmit\u0103 pl\u0103\u021bi, trebuie s\u0103 ave\u021bi grij\u0103 de fiecare mesaj \u00een parte. Totul se reduce la context.<\/p>\n<p>Observa\u021biile personale arat\u0103 c\u0103, pe m\u0103sur\u0103 ce intensitatea mesajelor cre\u0219te, valoarea fiec\u0103rui mesaj individual scade. Mesajele de volum mare devin, de obicei, valoroase dac\u0103 sunt considerate sub form\u0103 agregat\u0103.<\/p>\n<h2>Disponibilitate ridicat\u0103 (High Availability)<\/h2>\n<p>\nAbordarea Kafka \u00een ceea ce prive\u0219te disponibilitatea ridicat\u0103 se deosebe\u0219te semnificativ de abordarea ActiveMQ. Kafka este construit\u0103 pe baza clusterelor scalabile orizontal, \u00een care toate instan\u021bele brokerului accept\u0103 \u0219i distribuie mesaje simultan.<\/p>\n<p>Un cluster Kafka este format din mai multe instan\u021be broker care func\u021bioneaz\u0103 pe servere diferite. Kafka a fost conceput\u0103 pentru a func\u021biona pe hardware autonom obi\u0219nuit, unde fiecare nod are propriul s\u0103u sistem de stocare dedicat. Utilizarea stoc\u0103rii de re\u021bea (SAN) nu este recomandat\u0103, deoarece mai multe noduri de calcul pot concura pentru timpii de stocare \u0219i pot genera conflicte.<i>\u00ce<\/i>Intervale de stocare \u0219i a genera conflicte.<\/p>\n<p>Kafka este <i>o platform\u0103 mereu activ\u0103.<\/i> Mul\u021bi utilizatori mari ai Kafka nu \u00ee\u0219i opresc niciodat\u0103 clusterele, iar software-ul asigur\u0103 \u00eentotdeauna actualiz\u0103ri prin reporniri secven\u021biale. Acest lucru se realizeaz\u0103 prin garantarea compatibilit\u0103\u021bii cu versiunile anterioare pentru mesaje \u0219i interac\u021biuni \u00eentre brokeri.<\/p>\n<p>Brokerii sunt conecta\u021bi la un cluster de servere <noindex><a rel=\"nofollow\" href=\"http:\/\/zookeeper.apache.org\">ZooKeeper<\/a><\/noindex>, care ac\u021bioneaz\u0103 ca un registru de date de configurare \u0219i este utilizat pentru a coordona rolurile fiec\u0103rui broker. ZooKeeper este o sistem distribuit care asigur\u0103 disponibilitate ridicat\u0103 prin replicarea informa\u021biilor, stabilind <i>un cvorum.<\/i>.<\/p>\n<p>\u00cen cazul de baz\u0103, un topic este creat \u00een clusterul Kafka cu urm\u0103toarele propriet\u0103\u021bi:<\/p>\n<ul>\n<li>Num\u0103rul de parti\u021bii. Dup\u0103 cum s-a discutat anterior, valoarea exact\u0103 utilizat\u0103 aici depinde de nivelul dorit de citire paralel\u0103.<\/li>\n<li>Factoul de replicare determin\u0103 c\u00e2te instan\u021be broker din cluster trebuie s\u0103 con\u021bin\u0103 jurnalele pentru aceast\u0103 parti\u021bie.<\/li>\n<\/ul>\n<p>\nFolosind ZooKeeper pentru coordonare, Kafka \u00eencearc\u0103 s\u0103 distribuie echitabil noile parti\u021bii \u00eentre brokerii din cluster. Acest lucru este realizat de o instan\u021b\u0103 care \u00eendepline\u0219te rolul de Controler.<\/p>\n<p>\u00cen timpul execu\u021biei <i>pentru fiecare parti\u021bie a topicului<\/i> <i>Controler <\/i>aaloc\u0103 brokerului rolurile <i>liderilor <\/i>(lider, st\u0103p\u00e2n, principal) \u0219i <i>urm\u0103ritorilor <\/i>(urma\u0219e, sclavi, subordona\u021bi). Brokerul, care ac\u021bioneaz\u0103 ca lider pentru aceast\u0103 parti\u021bie, este responsabil pentru primirea tuturor mesajelor trimise lui de c\u0103tre produc\u0103tori \u0219i distribuirea mesajelor c\u0103tre consumatori. Atunci c\u00e2nd se trimit mesaje c\u0103tre parti\u021bia unui topic, acestea sunt replicate pe toate nodurile brokerului, care ac\u021bioneaz\u0103 ca urma\u0219i pentru aceast\u0103 parti\u021bie. Fiecare nod care con\u021bine jurnalele pentru parti\u021bie se nume\u0219te <i>replic\u0103<\/i>. Brokerul poate ac\u021biona ca lider pentru unele parti\u021bii \u0219i ca urm\u0103ritor pentru altele.<\/p>\n<p>Urm\u0103ritorul care con\u021bine toate mesajele stocate la lider se nume\u0219te <i>replic\u0103 sincronizat\u0103<\/i> (replic\u0103, care se afl\u0103 \u00een stare sincronizat\u0103, in-sync replica). Dac\u0103 brokerul, care ac\u021bioneaz\u0103 ca lider pentru parti\u021bie, se opre\u0219te, orice broker care se afl\u0103 \u00een stare actualizat\u0103 sau sincronizat\u0103 pentru aceast\u0103 parti\u021bie poate prelua rolul de lider. Acesta este un design extrem de rezistent.<\/p>\n<p>O parte a configura\u021biei produc\u0103torului este parametrul <i>acks<\/i>, care define\u0219te c\u00e2te replici trebuie s\u0103 confirme (acknowledge) primirea mesajului \u00eenainte ca fluxul aplica\u021biei s\u0103 continue trimiterea: 0, 1 sau toate. Dac\u0103 este specificat\u0103 o valoare <i>all<\/i>, atunci la primirea mesajului liderul va trimite o confirmare (confirmation) \u00eenapoi produc\u0103torului, imediat ce a primit confirm\u0103rile (acknowledgements) de la mai multe replici (inclusiv de la sine), a\u0219a cum este definit \u00een configura\u021bia topicului <i>min.insync.replicas<\/i> (implicit 1). Dac\u0103 mesajul nu poate fi replicat cu succes, atunci produc\u0103torul va genera o excep\u021bie pentru aplica\u021bie (<i>NotEnoughReplicas<\/i> sau <i>NotEnoughReplicasAfterAppend<\/i>).<\/p>\n<p>\u00centr-o configura\u021bie tipic\u0103, se creeaz\u0103 un topic cu un coeficient de replicare de 3 (1 lider, 2 urma\u0219i pentru fiecare parti\u021bie) \u0219i parametrul <i>min.insync.replicas<\/i> este setat la 2. \u00cen acest caz, clusterul va permite unui dintre brokerii care gestioneaz\u0103 parti\u021bia topicului s\u0103 se opreasc\u0103 f\u0103r\u0103 a afecta aplica\u021biile clien\u021bilor.<\/p>\n<p>Asta ne readuce la un compromis deja cunoscut \u00eentre performan\u021b\u0103 \u0219i fiabilitate. Replicarea are loc cu un timp suplimentar de a\u0219teptare pentru confirm\u0103rile (acknowledgments) de la urma\u0219i. Cu toate acestea, deoarece aceasta se execut\u0103 \u00een paralel, replicarea, cel pu\u021bin pe trei noduri, are acela\u0219i nivel de performan\u021b\u0103 ca \u0219i pe dou\u0103 (ignor\u00e2nd cre\u0219terea utiliz\u0103rii l\u0103\u021bimii de band\u0103 a re\u021belei).<\/p>\n<p>Folosind acest sistem de replicare, Kafka evit\u0103 cu abilitate necesitatea de a asigura scrierea fizic\u0103 a fiec\u0103rui mesaj pe disc prin opera\u021bia <i>sync ()<\/i>. Fiecare mesaj trimis de c\u0103tre produc\u0103tor va fi \u00eenregistrat \u00een jurnalul parti\u021biei, dar, a\u0219a cum s-a discutat \u00een Capitolul 2, scrierea \u00een fi\u0219ier se efectueaz\u0103 ini\u021bial \u00een memoria tampon a sistemului de operare. Dac\u0103 acest mesaj este replicat pe o alt\u0103 instan\u021b\u0103 Kafka \u0219i se afl\u0103 \u00een memoria ei, pierderea liderului nu \u00eenseamn\u0103 c\u0103 mesajul \u00een sine a fost pierdut \u2014 acesta poate fi preluat de replica sincronizat\u0103.<br \/>\nRenun\u021barea la necesitatea de a efectua opera\u021bia <i>sync ()<\/i> \u00eenseamn\u0103 c\u0103 Kafka poate accepta mesaje cu viteza cu care le poate scrie \u00een memorie. \u0218i invers, cu c\u00e2t se poate evita mai mult declan\u0219area (flushing) memoriei pe disc, cu at\u00e2t mai bine. Din aceast\u0103 cauz\u0103, nu este neobi\u0219nuit ca brokerii Kafka s\u0103 aib\u0103 alocate 64 GB de memorie sau mai mult. O astfel de utilizare a memoriei \u00eenseamn\u0103 c\u0103 o instan\u021b\u0103 Kafka poate func\u021biona cu u\u0219urin\u021b\u0103 la viteze de mii de ori mai rapid dec\u00e2t un broker de mesaje tradi\u021bional.<\/p>\n<p>Kafka poate fi, de asemenea, configurat pentru a aplica opera\u021bia <i>sync ()<\/i> la pachete de mesaje. Deoarece totul \u00een Kafka este orientat spre lucrul cu pachete, acest lucru func\u021bioneaz\u0103 de fapt destul de bine pentru multe scenarii de utilizare \u0219i este un instrument util pentru utilizatorii care necesit\u0103 garan\u021bii foarte puternice. O mare parte din performan\u021ba pur\u0103 a Kafka se leag\u0103 de mesajele care sunt trimise brokerului sub form\u0103 de pachete, precum \u0219i de faptul c\u0103 aceste mesaje sunt citite din broker \u00een blocuri consecutive prin <noindex><a rel=\"nofollow\" href=\"http:\/\/www.linuxjournal.com\/article\/6345\">zero-copy<\/a><\/noindex> opera\u021bii (opera\u021bii \u00een cursul c\u0103rora nu se efectueaz\u0103 sarcina de copiere a datelor dintr-o zon\u0103 de memorie \u00een alta). Ultimul este un c\u00e2\u0219tig semnificativ \u00een ceea ce prive\u0219te performan\u021ba \u0219i resursele \u0219i este posibil doar datorit\u0103 utiliz\u0103rii structurii de date din spatele jurnalului, care determin\u0103 schema parti\u021biei.<\/p>\n<p>\u00centr-un cluster Kafka, este posibil\u0103 o performan\u021b\u0103 deosebit de mare, comparativ cu utilizarea unui singur broker Kafka, deoarece parti\u021biile topicului pot fi scalate orizontal pe multe ma\u0219ini separate.<\/p>\n<h2>Concluzii<\/h2>\n<p>\n\u00cen acest capitol, am examinat cum arhitectura Kafka reconfigureaz\u0103 rela\u021biile dintre clien\u021bi \u0219i brokeri pentru a oferi un canal de mesaje incredibil de robust, cu o capacitate de procesare de multe ori mai mare dec\u00e2t a unui broker de mesaje obi\u0219nuit. Am discutat func\u021bionalit\u0103\u021bile pe care le utilizeaz\u0103 pentru a atinge acest obiectiv \u0219i am oferit o scurt\u0103 prezentare a arhitecturii aplica\u021biilor care faciliteaz\u0103 aceast\u0103 func\u021bionalitate. \u00cen capitolul urm\u0103tor, vom analiza problemele comune pe care trebuie s\u0103 le abordeze aplica\u021biile bazate pe mesaje \u0219i vom discuta strategiile pentru a le solu\u021biona. Vom \u00eencheia capitolul deline\u00e2nd cum s\u0103 g\u00e2ndim la tehnologiile de mesagerie \u00een general, astfel \u00eenc\u00e2t s\u0103 pute\u021bi evalua utilitatea lor pentru scenariile dumneavoastr\u0103 de utilizare.<\/p>\n<p>Partea precedent tradus\u0103: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">\u00cen\u021belegerea brokerilor de mesaje. Studiul mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 1<\/a><\/noindex><\/p>\n<p><b> Traducerea a fost realizat\u0103: <noindex><a rel=\"nofollow\" href=\"http:\/\/tele.gg\/middle_java\">tele.gg\/middle_java<\/a><\/noindex><\/b><\/p>\n<p><i>Continuare \u00een cur\u00e2nd\u2026<\/i><\/p>\n<p class=\"for_users_only_msg\">Numai utilizatorii \u00eenregistra\u021bi pot participa la sondaj. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Conecta\u021bi-v\u0103<\/a><\/noindex>, v\u0103 rug\u0103m.<\/p>\n<h2 class=\"default-block__polling-title\">Este Kafka folosit \u00een organiza\u021bia dumneavoastr\u0103?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Da<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Nu<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    A fost folosit anterior, acum nu mai este<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Planific\u0103m s\u0103 folosim<\/p>\n<\/li>\n<\/ul>\n<p>    Au votat 38 de utilizatori. 8 utilizatori s-au ab\u021binut.<br \/>\n<br \/>Sursa: <a content=\"nofollow\" rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466585\/\">habr.com<\/a><\/p>","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"excerpt":{"rendered":"<p>\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#8217;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f \u0447\u0430\u0441\u0442\u044c: \u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 1. \u0412\u0432\u0435\u0434\u0435\u043d\u0438\u0435 \u0413\u041b\u0410\u0412\u0410 3 Kafka Kafka \u0431\u044b\u043b\u0430 \u0440\u0430\u0437\u0440\u0430\u0431\u043e\u0442\u0430\u043d\u0430 \u0432 LinkedIn \u0434\u043b\u044f \u0442\u043e\u0433\u043e, \u0447\u0442\u043e\u0431\u044b \u043e\u0431\u043e\u0439\u0442\u0438 \u043d\u0435\u043a\u043e\u0442\u043e\u0440\u044b\u0435 \u043e\u0433\u0440\u0430\u043d\u0438\u0447\u0435\u043d\u0438\u044f \u0442\u0440\u0430\u0434\u0438\u0446\u0438\u043e\u043d\u043d\u044b\u0445 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439 \u0438 [&hellip;]<\/p>\n","protected":false,"gt_translate_keys":[{"key":"rendered","format":"html"}]},"author":1,"featured_media":0,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[688],"tags":[],"class_list":["post-38172","post","type-post","status-publish","format-standard","hentry","category-administrirovanie"],"aioseo_notices":[],"aioseo_head":"\n\t\t<!-- All in One SEO 5.0.2.1 - aioseo.com -->\n\t<meta name=\"description\" content=\"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#039;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.\" \/>\n\t<meta name=\"robots\" content=\"max-image-preview:large\" \/>\n\t<meta name=\"author\" content=\"Yuri Gagarin\"\/>\n\t<link rel=\"canonical\" href=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\n\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.2.1\" \/>\n\t\t<meta property=\"og:locale\" content=\"ro_RO\" \/>\n\t\t<meta property=\"og:site_name\" content=\"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b\" \/>\n\t\t<meta property=\"og:type\" content=\"article\" \/>\n\t\t<meta property=\"og:title\" content=\"\ud83e\udd47\u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 3. Kafka | ProHoster\" \/>\n\t\t<meta property=\"og:description\" content=\"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O&#039;Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.\" \/>\n\t\t<meta property=\"og:url\" content=\"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\n\t\t<meta property=\"og:image\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:secure_url\" content=\"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg\" \/>\n\t\t<meta property=\"og:image:width\" content=\"350\" \/>\n\t\t<meta property=\"og:image:height\" content=\"350\" \/>\n\t\t<meta property=\"article:published_time\" content=\"2019-10-31T19:22:05+00:00\" \/>\n\t\t<meta property=\"article:modified_time\" content=\"2019-10-31T19:22:05+00:00\" \/>\n\t\t<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<meta property=\"article:author\" content=\"https:\/\/www.facebook.com\/prohoster\" \/>\n\t\t<!-- All in One SEO -->\n\n","aioseo_head_json":{"title":"\ud83e\udd47\u00cen\u021belegerea brokerilor de mesaje. Studiul mecanicii schimbului de mesaje prin ActiveMQ \u0219i Kafka. Capitolul 3. Kafka | ProHoster","description":"Continuarea traducerii unei c\u0103r\u021bi mici: \u201eUnderstanding Message Brokers\u201d, autor: Jakub Korab, editura: O'Reilly Media, Inc., data public\u0103rii: iunie 2017, ISBN: 9781492049296. Anterior tradus\u0103.","canonical_url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","robots":"max-image-preview:large","keywords":"","webmasterTools":{"miscellaneous":""},"schema":null,"og:locale":"ro_RO","og:site_name":"ProHoster | \u041a\u0443\u043f\u0438\u0442\u044c \u043d\u0430\u0434\u0435\u0436\u043d\u044b\u0439 \u0445\u043e\u0441\u0442\u0438\u043d\u0433 \u0434\u043b\u044f \u0441\u0430\u0439\u0442\u043e\u0432 \u0441 \u0437\u0430\u0449\u0438\u0442\u043e\u0439 \u043e\u0442 DDoS, VPS VDS \u0441\u0435\u0440\u0432\u0435\u0440\u044b","og:type":"article","og:title":"\ud83e\udd47\u041f\u043e\u043d\u0438\u043c\u0430\u043d\u0438\u0435 \u0431\u0440\u043e\u043a\u0435\u0440\u043e\u0432 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u0439. \u0418\u0437\u0443\u0447\u0435\u043d\u0438\u0435 \u043c\u0435\u0445\u0430\u043d\u0438\u043a\u0438 \u043e\u0431\u043c\u0435\u043d\u0430 \u0441\u043e\u043e\u0431\u0449\u0435\u043d\u0438\u044f\u043c\u0438 \u043f\u043e\u0441\u0440\u0435\u0434\u0441\u0442\u0432\u043e\u043c ActiveMQ \u0438 Kafka. \u0413\u043b\u0430\u0432\u0430 3. Kafka | ProHoster","og:description":"\u041f\u0440\u043e\u0434\u043e\u043b\u0436\u0435\u043d\u0438\u0435 \u043f\u0435\u0440\u0435\u0432\u043e\u0434\u0430 \u043d\u0435\u0431\u043e\u043b\u044c\u0448\u043e\u0439 \u043a\u043d\u0438\u0433\u0438: \u00abUnderstanding Message Brokers\u00bb, \u0430\u0432\u0442\u043e\u0440: Jakub Korab, \u0438\u0437\u0434\u0430\u0442\u0435\u043b\u044c\u0441\u0442\u0432\u043e: O'Reilly Media, Inc., \u0434\u0430\u0442\u0430 \u0438\u0437\u0434\u0430\u043d\u0438\u044f: June 2017, ISBN: 9781492049296. \u041f\u0440\u0435\u0434\u044b\u0434\u0443\u0449\u0430\u044f \u043f\u0435\u0440\u0435\u0432\u0435\u0434\u0435\u043d\u043d\u0430\u044f.","og:url":"https:\/\/prohoster.info\/ro\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","og:image":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:secure_url":"https:\/\/prohoster.info\/wp-content\/uploads\/2021\/11\/logo-350.jpg","og:image:width":350,"og:image:height":350,"article:published_time":"2019-10-31T19:22:05+00:00","article:modified_time":"2019-10-31T19:22:05+00:00","article:publisher":"https:\/\/www.facebook.com\/prohoster","article:author":"https:\/\/www.facebook.com\/prohoster"},"aioseo_meta_data":{"post_id":"38172","title":null,"description":null,"keywords":null,"keyphrases":null,"primary_term":null,"canonical_url":null,"og_title":null,"og_description":null,"og_object_type":"default","og_image_type":"default","og_image_url":null,"og_image_width":null,"og_image_height":null,"og_image_custom_url":null,"og_image_custom_fields":null,"og_video":null,"og_custom_url":null,"og_article_section":null,"og_article_tags":null,"twitter_use_og":false,"twitter_card":"default","twitter_image_type":"default","twitter_image_url":null,"twitter_image_custom_url":null,"twitter_image_custom_fields":null,"twitter_title":null,"twitter_description":null,"schema":{"blockGraphs":[],"customGraphs":[],"default":{"data":{"Article":[],"Course":[],"Dataset":[],"FAQPage":[],"Movie":[],"Person":[],"Product":[],"ProductReview":[],"Car":[],"Recipe":[],"Service":[],"SoftwareApplication":[],"WebPage":[]},"graphName":"","isEnabled":true},"graphs":[]},"schema_type":null,"schema_type_options":null,"pillar_content":false,"robots_default":true,"robots_noindex":false,"robots_noarchive":false,"robots_nosnippet":false,"robots_nofollow":false,"robots_noimageindex":false,"robots_noodp":false,"robots_notranslate":false,"robots_max_snippet":null,"robots_max_videopreview":null,"robots_max_imagepreview":"large","priority":null,"frequency":null,"local_seo":null,"seo_analyzer_scan_date":"2026-01-23 20:46:00","breadcrumb_settings":null,"limit_modified_date":false,"reviewed_by":null,"ai":null,"created":"2021-02-28 15:34:26","updated":"2026-01-23 20:46:00","focus_keyword":null,"additional_keywords":null,"truseo_locale":null},"gt_translate_keys":[{"key":"link","format":"url"}],"_links":{"self":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/38172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/comments?post=38172"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/posts\/38172\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/media?parent=38172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/categories?post=38172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/ro\/wp-json\/wp\/v2\/tags?post=38172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}