{"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\/nl\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka","title":{"rendered":"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka","gt_translate_keys":[{"key":"rendered","format":"text"}]},"content":{"rendered":"<p>Vervolg van de vertaling van een klein boek:<br \/>\n\u00abUnderstanding Message Brokers\u00bb,<br \/>\nauteur: Jakub Korab, uitgeverij: O'Reilly Media, Inc., uitgave datum: juni 2017, ISBN: 9781492049296.<\/p>\n<p>Vorige vertaalde deel: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">Inzicht in berichtbrokers. Het bestuderen van de mechanica van berichtuitwisseling via ActiveMQ en Kafka. Hoofdstuk 1. Inleiding<\/a><\/noindex><br \/>\n<noindex><a rel=\"nofollow\" name=\"habracut\"><\/a><\/noindex><\/p>\n<h2>HOOFDSTUK 3<\/h2>\n<p><\/p>\n<h2>Kafka<\/h2>\n<p>\nKafka is ontwikkeld bij LinkedIn om bepaalde beperkingen van traditionele berichtbrokers te omzeilen en de noodzaak te vermijden om meerdere berichtbrokers in te stellen voor verschillende 'point-to-point' interacties, zoals beschreven in dit boek in het deel 'Verticaal en horizontaal schalen' op pagina 28. De gebruikscenario's bij LinkedIn waren voornamelijk gebaseerd op het eenrichtingsabsorberen van zeer grote hoeveelheden data, zoals klikken op pagina's en toegang logs, terwijl deze data tegelijkertijd door meerdere systemen konden worden gebruikt, zonder dat dit de prestaties van producenten of andere consumenten be\u00efnvloedde. In feite is de reden voor het bestaan van Kafka om een dergelijk architectuur van berichtuitwisseling te krijgen als beschreven in de Universal Data Pipeline.<\/p>\n<p>Met dit uiteindelijke doel in gedachten, ontstonden natuurlijk ook andere eisen. Kafka moet:<\/p>\n<ul>\n<li>Extreem snel zijn<\/li>\n<li>Hoge doorvoer bieden bij het verwerken van berichten<\/li>\n<li>Ondersteuning bieden voor de modellen 'Publisher-Subscriber' en 'Point-To-Point'<\/li>\n<li>Niet vertragen door het toevoegen van consumenten. Bijvoorbeeld, de prestaties van zowel de wachtrij als het onderwerp in ActiveMQ verslechteren bij een toename van het aantal consumenten aan de ontvangende kant.<\/li>\n<li>Horizontaal schaalbaar zijn; als \u00e9\u00e9n broker die berichten opslaat dit alleen kan doen op de maximale schijf snelheid, dan is het zinvol om verder te kijken dan \u00e9\u00e9n broker instantie om de prestaties te verbeteren.<\/li>\n<li>Toegang tot het opslaan en opnieuw ophalen van berichten scheiden<\/li>\n<\/ul>\n<p>\nOm dit alles te bereiken, heeft Kafka een architectuur aangenomen die de rollen en verantwoordelijkheden van klanten en message brokers heeft herschreven. Het JMS-model is sterk gericht op de broker, die verantwoordelijk is voor de distributie van berichten, terwijl klanten zich alleen moeten bekommeren om het verzenden en ontvangen van berichten. Kafka daarentegen is klantgericht, waarbij de klant veel functies van de traditionele broker overneemt, zoals het eerlijke verdelen van relevante berichten onder consumenten, in ruil voor een extreem snelle en schaalbare broker. Voor mensen die met traditionele messaging-systemen hebben gewerkt, vereist het werken met Kafka fundamentele veranderingen in perspectief.<br \/>\nDeze engineeringrichting heeft geleid tot de creatie van messaging-infrastructuur die in staat is om de doorvoer met meerdere orden van grootte te verhogen in vergelijking met een gewone broker. Zoals we zullen zien, zijn er compromissen verbonden aan deze benadering, wat betekent dat Kafka niet geschikt is voor bepaalde soorten belasting en gevestigde software.<\/p>\n<h3>Geco\u00f6rdineerd adresseringsmodel<\/h3>\n<p>\nOm aan de bovenstaande eisen te voldoen, heeft Kafka messaging van het type 'publicatie-abonnement' en 'punt-tot-punt' gecombineerd binnen \u00e9\u00e9n type ontvanger - <i>topic<\/i>. Dit verwart mensen die met messaging-systemen hebben gewerkt, waar het woord 'topic' verwijst naar een broadcastmechanisme, waarvan het lezen (uit het topic) niet betrouwbaar is (is nondurable). Topics in Kafka moeten worden beschouwd als een hybride type ontvanger, volgens de definitie die in de inleiding van dit boek is gegeven.<\/p>\n<blockquote><p>In de rest van dit hoofdstuk, tenzij we uitdrukkelijk anders aangeven, zal de term 'topic' verwijzen naar een Kafka-topic.<\/p><\/blockquote>\n<p>\nOm volledig te begrijpen hoe topics zich gedragen en welke garanties ze bieden, moeten we eerst kijken naar hoe ze in Kafka zijn ge\u00efmplementeerd.<br \/>\n<i>Elke topic in Kafka heeft zijn eigen log.<\/i><br \/>\nProducers die berichten naar Kafka verzenden, schrijven naar dit logboek, terwijl consumenten uit het logboek lezen met behulp van pointers die continu vooruit worden verplaatst. Periodiek verwijdert Kafka de oudste delen van het logboek, ongeacht of de berichten in die delen al dan niet zijn gelezen. Een centraal aspect van het ontwerp van Kafka is dat de broker zich niet bekommert om de vraag of berichten zijn gelezen of niet \u2014 dit is de verantwoordelijkheid van de cli\u00ebnt.<\/p>\n<blockquote><p>De termen \"logboek\" en \"pointer\" komen niet voor in <noindex><a rel=\"nofollow\" href=\"https:\/\/kafka.apache.org\/documentation.html\">de documentatie van Kafka<\/a><\/noindex>. Deze goed bekende termen worden hier gebruikt om het begrip te vergemakkelijken.<\/p><\/blockquote>\n<p>\nDit model verschilt volledig van ActiveMQ, waar berichten uit alle wachtrijen in \u00e9\u00e9n logboek worden opgeslagen en de broker berichten markeert als verwijderd nadat ze zijn gelezen.<br \/>\nLaten we nu wat dieper ingaan op het logboek van het topic.<br \/>\nHet Kafka-logboek bestaat uit verschillende partities (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/tm\/w2\/yf\/tmw2yf3lanppqtrumxoidotplhi.png\">Figuur 3-1<\/a><\/noindex>). Kafka garandeert een strikte volgorde binnen elke partitie. Dit betekent dat berichten die in een bepaalde volgorde naar een partitie zijn geschreven, ook in die volgorde zullen worden gelezen. Elke partitie is ge\u00efmplementeerd als een cyclisch logboekbestand dat een <i>subverzameling <\/i>(subset) van alle berichten bevat die door de producenten naar het topic zijn verzonden. Een aangemaakt topic bevat standaard \u00e9\u00e9n partitie. Het idee van partities is een centraal idee van Kafka voor horizontale schaalvergroting.<\/p>\n<p><img decoding=\"async\" alt=\"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/39f41ebcb73ec247656c0dea438158a9.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figuur 3-1. Partities van Kafka<\/i><\/p>\n<p>Wanneer een producent een bericht naar een Kafka-topic verzendt, besluit hij naar welke partitie hij het bericht moet sturen. We zullen hier later meer over bekijken.<\/p>\n<h2>Berichten lezen<\/h2>\n<p>\nEen cli\u00ebnt die berichten wil lezen, beheert een genummerde pointer, genaamd <i>consumentengroep (consumer group)<\/i>, die wijst naar <i>de offset<\/i> van berichten in de partitie. De offset is een positie met een oplopend nummer dat begint bij 0 aan het begin van de partitie. Deze consumentengroep, waarnaar wordt verwezen in de API via een door de gebruiker gedefinieerd id group_id, komt overeen met <i>\u00e9\u00e9n logische consument of systeem.<\/i>.<\/p>\n<p>De meeste systemen die berichtenuitwisseling gebruiken, lezen gegevens van de ontvanger via meerdere instanties en threads voor parallelle verwerking van berichten. Hierdoor zijn er meestal veel instanties van consumenten die dezelfde consumentengroep delen.<\/p>\n<p>Het probleem van het lezen kan als volgt worden weergegeven:<\/p>\n<ul>\n<li>Een topic heeft verschillende partitions<\/li>\n<li>Meerdere consumer groepen kunnen tegelijkertijd gebruik maken van een topic<\/li>\n<li>Een consumer groep kan meerdere aparte instanties hebben<\/li>\n<\/ul>\n<p>\nDit is een niet-triviaal probleem van \"veel-naar-veel\". Om te begrijpen hoe Kafka omgaat met de relaties tussen consumer groepen, consumer instanties en partitions, beschouwen we een reeks geleidelijk complexer wordende lees-scenario's.<\/p>\n<h3>Consumers en consumer groepen<\/h3>\n<p>\nLaten we als startpunt een topic met \u00e9\u00e9n partition nemen (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/6z\/tz\/dh\/6ztzdhqmjweck-z15htxb2xbe28.png\">Figuur 3-2<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/46c92e6bd38774dfef3be4bd198bf35d.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figuur 3-2. Een consumer leest uit een partition<\/i><\/p>\n<p>Wanneer een consumer instantie met zijn eigen group_id verbinding maakt met dit topic, wordt er een partition toegewezen voor het lezen en een offset in deze partition. De positie van deze offset is in de client geconfigureerd, als een aanwijzer naar de meest recente positie (het nieuwste bericht) of de vroegste positie (het oudste bericht). De consumer vraagt (polls) berichten op uit het topic, wat leidt tot het sequentieel lezen ervan uit het logboek.<br \/>\nDe offset positie wordt regelmatig teruggecommit naar Kafka en opgeslagen als berichten in het interne topic <i>_consumer_offsets<\/i>. Gelezen berichten worden niet verwijderd, in tegenstelling tot een gewone broker, en de client kan de offset terugspoelen (rewind) om eerder bekeken berichten opnieuw te verwerken.<\/p>\n<p>Wanneer een tweede logische consumer verbinding maakt, met een andere group_id, beheert deze een tweede aanwijzer die niet van de eerste afhankelijk is (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/qe\/v1\/yk\/qev1yktga3s-g1gqlynylbe3n9w.png\">Figuur 3-3<\/a><\/noindex>). Zo functioneert een Kafka topic als een wachtrij, waarbij er \u00e9\u00e9n consumer is en als een gewone publish-subscribe topic, waarop meerdere consumers zijn geabonneerd, met als extra voordeel dat alle berichten worden opgeslagen en meerdere keren kunnen worden verwerkt.<\/p>\n<p><img decoding=\"async\" alt=\"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/e9e8b9063ef7367005254d36abb47f4f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figuur 3-3. Twee consumers in verschillende consumer groepen lezen uit \u00e9\u00e9n partition<\/i><\/p>\n<h3>Consumers in een consumer groep<\/h3>\n<p>\nWanneer \u00e9\u00e9n instantie van een consumer gegevens uit een partition leest, controleert deze volledig de aanwijzer en verwerkt deze de berichten zoals beschreven in de vorige sectie.<br \/>\nAls meerdere exemplaren van consumenten met dezelfde group_id zijn verbonden aan een onderwerp met \u00e9\u00e9n partition, ontvangt het exemplaar dat als laatste verbinding maakt de controle over de pointer en zal vanaf dat moment alle berichten ontvangen (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/0j\/ao\/f2\/0jaof2mdwg3cqvmwemhtxkrltuq.png\">Figuur 3-4<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/ec6af819445dad4028f65449a735ae22.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figuur 3-4. Twee consumenten in dezelfde groep consumenten lezen uit \u00e9\u00e9n partition<\/i><\/p>\n<p>Deze verwerkingsmodus, waarin het aantal consumentexemplaren het aantal partitions overschrijdt, kan worden gezien als een soort monopolistische consument. Dit kan nuttig zijn als u een 'actief-passieve' (of 'hete-warme') clustering van uw consumentexemplaren nodig heeft, hoewel parallelle werking van meerdere consumenten ('actief-actief' of 'hete-hete') veel gebruikelijker is dan consumenten in een wachttijd.<\/p>\n<blockquote><p>Dit gedrag van berichtverdeling, zoals hierboven beschreven, kan verrassend zijn in vergelijking met hoe een reguliere JMS-rij werkt. In dit model worden berichten die naar de rij worden verzonden gelijkmatig verdeeld over twee consumenten.<\/p><\/blockquote>\n<p>\nMeestal, wanneer we meerdere exemplaren van consumenten aanmaken, doen we dit ofwel voor parallelle verwerking van berichten, ofwel om de leessnelheid te verhogen, of om de veerkracht van het leesproces te verbeteren. Aangezien gegevens uit een partition gelijktijdig alleen door \u00e9\u00e9n consumentenexemplaar kunnen worden gelezen, hoe wordt dit bereikt in Kafka?<\/p>\n<p>Een manier om dit te doen is door \u00e9\u00e9n exemplaar van de consument alle berichten te laten lezen en deze naar een threadpool door te geven. Hoewel deze benadering de verwerkingscapaciteit verhoogt, verhoogt deze de complexiteit van de logica van consumenten en draagt deze niet bij aan de veerkracht van het leessysteem. Als \u00e9\u00e9n exemplaar van de consument uitvalt door een stroomstoring of een soortgelijk evenement, stopt de verwerking.<\/p>\n<p>De canonieke manier om dit probleem in Kafka op te lossen, is door gebruik te maken van een<i>groot aantal partitions.<\/i>Partitionering<\/p>\n<h3>Partitions zijn het belangrijkste mechanisme voor het parallelle lezen en het schalen van een onderwerp buiten de bandbreedte van \u00e9\u00e9n broker-exemplaar. Om dit beter te begrijpen, laten we een situatie bekijken waarin er een onderwerp is met twee partitions en \u00e9\u00e9n consument zich op dat onderwerp abonneert (<\/h3>\n<p>\nFiguur 3-5<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/en\/9g\/ct\/en9gct0o017cqp8buawguwlscty.png\">Figuur 3-5<\/a><\/noindex>).<\/p>\n<p><img decoding=\"async\" alt=\"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/cc766bf69af22698aacc3f1ac70b067f.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figuur 3-5. E\u00e9n consument leest uit meerdere partities<\/i><\/p>\n<p>In dit scenario krijgt de consument controle over de indexen die overeenkomen met zijn group_id in beide partities en begint hij berichten uit beide partities te lezen.<br \/>\nWanneer een extra consument voor dezelfde group_id aan deze topic wordt toegevoegd, wijst Kafka een van de partities opnieuw toe (reallocate) van de eerste naar de tweede consument. Daarna zal elke instantie van de consument uit \u00e9\u00e9n partitie van de topic lezen (<noindex><a rel=\"nofollow\" href=\"https:\/\/habrastorage.org\/webt\/8b\/a0\/um\/8ba0umn2yzr9yy3vztonhdfiub0.png\">Figuur 3-6<\/a><\/noindex>).<\/p>\n<p>Om berichten parallel in 20 threads te verwerken, heeft u minimaal 20 partities nodig. Als dit aantal lager is, blijven er consumenten over zonder werk, zoals eerder besproken over monopolistische consumenten.<\/p>\n<p><img decoding=\"async\" alt=\"Begrip van berichten-brokers. Mechanica van berichtenuitwisseling via ActiveMQ en Kafka. Hoofdstuk 3. Kafka\" src=\"\/wp-content\/uploads\/2019\/09\/a3c4001e4a5b92d53b6f529b2633254a.jpg\" style=\"display:block;margin: 0 auto;\" \/><br \/>\n<i>Figuur 3-6. Twee consumenten in dezelfde groep consumenten lezen uit verschillende partities<\/i><\/p>\n<p>Dit schema vermindert de complexiteit van de Kafka-broker aanzienlijk in vergelijking met de verdeling van berichten die nodig is voor het ondersteunen van een JMS-queue. Hier hoeft men zich geen zorgen te maken over de volgende zaken:<\/p>\n<ul>\n<li>Welke consument het volgende bericht moet ontvangen, op basis van cyclische (round-robin) distributie, de huidige capaciteit van prefetch-buffers of eerdere berichten (zoals voor JMS-berichtgroepen).<\/li>\n<li>Welke berichten naar welke consumenten zijn verzonden en of ze opnieuw moeten worden afgeleverd in geval van een storing.<\/li>\n<\/ul>\n<p>\nAlles wat de Kafka-broker moet doen, is berichten sequentieel aan de consument doorgeven wanneer deze ze aanvraagt.<\/p>\n<p>Echter, de eisen voor het parallel lezen en opnieuw verzenden van mislukte berichten verdwijnen niet \u2014 de verantwoordelijkheid daarvoor verschuift gewoon van de broker naar de cli\u00ebnt. Dit betekent dat ze in uw code moeten worden meegenomen.<\/p>\n<h2>Berichten verzenden<\/h2>\n<p>\nDe verantwoordelijkheid voor de beslissing in welke partitie een bericht verzonden moet worden, ligt bij de producent van dat bericht. Om het mechanisme te begrijpen waarmee dit gebeurt, moeten we eerst bekijken wat we eigenlijk verzenden.<\/p>\n<p>Terwijl we in JMS een berichtstructuur met metadata (koppen en eigenschappen) en een lichaam dat de payload bevat, gebruiken, is in Kafka een bericht <i>een paar 'sleutel-waarde'<\/i>. De payload van het bericht wordt verzonden als waarde (value). De sleutel daarentegen wordt hoofdzakelijk gebruikt voor partitionering en moet bevatten <i>een sleutel die specifiek is voor de bedrijfslogica<\/i>, zodat gerelateerde berichten in dezelfde partition kunnen worden geplaatst.<\/p>\n<p>In Hoofdstuk 2 hebben we het scenario van online wedden besproken, waarbij gerelateerde gebeurtenissen in volgorde door \u00e9\u00e9n consument moeten worden verwerkt:<\/p>\n<ol>\n<li>De gebruikersaccount is ingesteld.<\/li>\n<li>Het geld wordt bijgeschreven op de rekening.<\/li>\n<li>Er wordt een inzet geplaatst die geld van de rekening haalt.<\/li>\n<\/ol>\n<p>\nAls elke gebeurtenis een bericht vertegenwoordigt dat naar het onderwerp is gestuurd, is in dit geval de natuurlijke sleutel de accountidentificatie.<br \/>\nWanneer een bericht wordt verzonden met behulp van de Kafka Producer API, wordt het doorgegeven aan de partitioneringsfunctie, die, rekening houdend met het bericht en de huidige status van het Kafka-cluster, het identificatienummer van de partition retourneert waarin het bericht moet worden verzonden. Deze functie is ge\u00efmplementeerd in Java via de Partitioner-interface.<\/p>\n<p>Deze interface ziet er als volgt uit:<\/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>\nDe implementatie van Partitioner voor het bepalen van de partition maakt standaard gebruik van een hashing-algoritme voor de sleutel (general-purpose hashing algorithm over the key) of ronde-robine (round-robin) als de sleutel niet is opgegeven. Deze standaardinstelling werkt goed in de meeste gevallen. Echter, in de toekomst wilt u misschien uw eigen versie schrijven.<\/p>\n<h3>Het schrijven van uw eigen partitioneringsstrategie<\/h3>\n<p>\nLaten we een voorbeeld bekijken waarbij u metadata wilt verzenden samen met de payload van het bericht. De payload in ons voorbeeld is een instructie voor het storten van geld op de speelrekening. De instructie is hetgeen wat we zeker niet willen aanpassen tijdens de overdracht en we willen er zeker van zijn dat alleen een vertrouwd hoger systeem deze instructie kan initi\u00ebren. In dit geval stemmen de verzendende en ontvangende systemen af over het gebruik van een handtekening voor de authenticatie van het bericht.<br \/>\nIn gewone JMS defini\u00ebren we eenvoudig de eigenschap 'handtekening van het bericht' en voegen deze toe aan het bericht. Kafka biedt ons echter geen mechanisme om metadata over te dragen \u2014 alleen een sleutel en waarde.<\/p>\n<p>Aangezien de waarde de payload van de bankoverschrijving is, waarvan we de integriteit willen behouden, hebben we geen andere keuze dan de datastructuur te defini\u00ebren die we in de sleutel gaan gebruiken. Aangenomen dat we een rekeningnummer nodig hebben voor partitionering, omdat alle berichten die aan de rekening zijn gekoppeld in volgorde moeten worden verwerkt, zullen we de volgende JSON-structuur bedenken:<\/p>\n<pre><code class=\"json\">{\n  \"signature\": \"541661622185851c248b41bf0cea7ad0\",\n  \"accountId\": \"10007865234\"\n}<\/code><\/pre>\n<p>\nAangezien de waarde van de handtekening zal vari\u00ebren afhankelijk van de payload, zal de standaard hashstrategie van de Partitioner waarschijnlijk niet betrouwbaar gerelateerde berichten groeperen. Daarom zullen we onze eigen strategie moeten schrijven die deze sleutel analyseert en de waarde accountId partitioneert.<\/p>\n<blockquote><p>Kafka omvat checksums voor het detecteren van beschadigde berichten in de opslag en heeft een compleet scala aan beveiligingsfuncties. Ondanks dit komen er soms sector-specifieke eisen voor, zoals hierboven vermeld.<\/p><\/blockquote>\n<p>\nEen aangepaste partitioneringsstrategie moet ervoor zorgen dat alle gerelateerde berichten zich in \u00e9\u00e9n partitie bevinden. Hoewel dit eenvoudig lijkt, kan de eis worden bemoeilijkt door het belang van de volgorde van gerelateerde berichten en hoe vast het aantal partitities in het onderwerp is.<\/p>\n<p>Het aantal partitities in een onderwerp kan in de loop van de tijd veranderen, omdat er nieuwe kunnen worden toegevoegd als het verkeer de oorspronkelijke verwachtingen overschrijdt. Hierdoor kunnen de sleutels van berichten worden gekoppeld aan de partitie waarvoor ze oorspronkelijk zijn verzonden, implicerend dat een deel van de status verdeeld moet worden over de instanties van de producer.<\/p>\n<p>Een andere factor om rekening mee te houden is de gelijkmatigheid van de verdeling van berichten over de partitities. Over het algemeen worden sleutels niet gelijkmatig verdeeld over berichten, en hashfuncties garanderen geen eerlijke verdeling van berichten voor een kleine set sleutels.<br \/>\nHet is belangrijk op te merken dat, hoe u ook beslist om berichten te splitsen, de scheiding mogelijk opnieuw moet worden gebruikt.<\/p>\n<p>Laten we de vereiste gegevensreplicatie tussen Kafka-clusters op verschillende geografische locaties bekijken. Hiervoor wordt Kafka geleverd met een commandoregeltool genaamd MirrorMaker, die wordt gebruikt om berichten uit \u00e9\u00e9n cluster te lezen en deze naar een ander cluster te verzenden.<\/p>\n<p>MirrorMaker moet de sleutels van het te repliceren topic begrijpen om de relatieve volgorde tussen de berichten tijdens de replicatie tussen clusters te behouden, aangezien het aantal partities voor dit topic niet noodzakelijkerwijs in beide clusters overeenkomt.<\/p>\n<p>Aangepaste partitioneringsstrategie\u00ebn komen relatief zelden voor, omdat het standaard hash- of cyclisch algoritme in de meeste scenario's goed werkt. Echter, als u strikte garanties voor ordening nodig heeft of als u metadata uit de payloads moet extraheren, dan is partitionering iets waar u beter naar moet kijken.<\/p>\n<p>De voordelen van schaalbaarheid en prestaties van Kafka zijn te danken aan het overdragen van enkele verantwoordelijkheden van de traditionele broker naar de client. In dit geval wordt besloten om potentieel gerelateerde berichten over verschillende consumenten, die parallel werken, te verdelen.<\/p>\n<blockquote><p>JMS-brokers moeten ook met dergelijke vereisten omgaan. Interessant is dat het mechanisme om gerelateerde berichten naar dezelfde consument te sturen, dat is ge\u00efmplementeerd via JMS Message Groups (een soort sticky load balancing (SLB)-strategie), ook vereist dat de afzender berichten als gerelateerd markeert. In het geval van JMS is de broker verantwoordelijk voor het verzenden van deze groep gerelateerde berichten naar \u00e9\u00e9n consument van de velen en voor het overdragen van het eigendom van de groep als de consument uitvalt.<\/p><\/blockquote>\n<p><\/p>\n<h2>Producentovereenkomsten<\/h2>\n<p>\nPartitionering is niet het enige dat in overweging moet worden genomen bij het verzenden van berichten. Laten we de send() methoden van de Producer klasse in de Java API bekijken:<\/p>\n<pre><code class=\"java\">Future  send(ProducerRecord  record);\nFuture  send(ProducerRecord  record, Callback callback);<\/code><\/pre>\n<p>\nHet is belangrijk op te merken dat beide methoden een Future teruggeven, wat aangeeft dat de verzendoperatie niet onmiddellijk wordt uitgevoerd. Dit betekent dat het bericht (ProducerRecord) wordt opgeslagen in de verzendbuffer voor elke actieve partitie en in de achtergrond naar de broker wordt verzonden via de Kafka-clientbibliotheek. Hoewel dit de uitvoering ongelooflijk snel maakt, betekent het dat een onervaren geschreven applicatie berichten kan verliezen als het proces wordt gestopt.<\/p>\n<p>Zoals altijd is er een manier om de verzendoperatie betrouwbaarder te maken ten koste van de prestaties. De grootte van deze buffer kan op 0 worden ingesteld, en de verzendende applicatie zal gedwongen worden te wachten tot de overdracht van het bericht naar de broker is voltooid, als volgt:<\/p>\n<pre><code class=\"java\">RecordMetadata metadata = producer.send(record).get();<\/code><\/pre>\n<p><\/p>\n<h2>Nogmaals over het lezen van berichten<\/h2>\n<p>\nHet lezen van berichten heeft extra complicaties waarover nagedacht moet worden. In tegenstelling tot de JMS-API, die een berichtlistener kan starten als reactie op het binnenkomen van een bericht, is de interface <i>Consumer <\/i>Kafka alleen maar polling. Laten we de methode <i>poll ()<\/i>diezelfde doel nader bekijken:<\/p>\n<pre><code class=\"java\">ConsumerRecords  poll(long timeout);<\/code><\/pre>\n<p>\nDe retourwaarde van de methode is een containerstructuur die meerdere objecten bevat <i>ConsumerRecord <\/i>van mogelijk meerdere partities. <i>ConsumerRecord <\/i>Zelf is het een houder-object voor een sleutel-waarde paar met bijbehorende metadata, zoals de partitie waaruit het is gehaald.<\/p>\n<p>Zoals besproken in Hoofdstuk 2, moeten we altijd in gedachten houden wat er met de berichten gebeurt na succesvolle of onsuccesvolle verwerking, bijvoorbeeld als de client het bericht niet kan verwerken of als deze crasht. In JMS werd dit behandeld via de bevestigingsmodus (acknowledgement mode). De broker verwijdert ofwel het succesvol verwerkte bericht, of levert het onverwerkte of gefaalde opnieuw (op voorwaarde dat transacties zijn gebruikt). <br \/>\nKafka werkt heel anders. Berichten worden niet verwijderd in de broker na uitlezing en de verantwoordelijkheid voor wat er gebeurt bij een fout ligt bij de uitlezende code.<\/p>\n<p>Zoals we al zeiden, is een groep consumenten gekoppeld aan de offset in het log. De positie in het log, die aan deze offset is gekoppeld, komt overeen met het volgende bericht dat zal worden uitgegeven in reactie op <i>poll ()<\/i>Het tijdstip waarop deze offset toeneemt, is cruciaal bij het lezen.<\/p>\n<p>Als we terugkijken naar het eerder besproken leermodel, bestaat de verwerking van een bericht uit drie fasen:<\/p>\n<ol>\n<li>Het bericht voor lezen ophalen.<\/li>\n<li>Het bericht verwerken.<\/li>\n<li>Het bericht bevestigen.<\/li>\n<\/ol>\n<p>\nDe Kafka-consumer komt met een configuratieoptie <i>enable.auto.commit<\/i>. Dit is een veelgebruikte standaardinstelling, zoals vaak het geval is met instellingen die het woord \"auto\" bevatten.<\/p>\n<p>Tot Kafka 0.10 stuurde een client die deze parameter gebruikte de offset van het laatst gelezen bericht bij de volgende aanroep <i>poll ()<\/i> na verwerking. Dit betekende dat eventuele berichten die al waren opgehaald (fetched), opnieuw konden worden verwerkt als de client deze al had verwerkt maar onverwacht was neergestort v\u00f3\u00f3r de aanroep. <i>poll ()<\/i>. Aangezien de broker geen staat bijhoudt over hoe vaak een bericht is gelezen, zal de volgende consument die dit bericht ophaalt, niet weten dat er iets fout is gegaan. Dit gedrag was pseudo-transactief. De offset werd alleen gecommitteerd bij een succesvolle verwerking van het bericht, maar als de client werd onderbroken, verzond de broker hetzelfde bericht opnieuw naar een andere client. Dit gedrag voldeed aan de verzendgarantie van berichten \u00ab<i>ten minste \u00e9\u00e9n keer<\/i>&#171;.<\/p>\n<p>. In Kafka 0.10 werd de clientcode zodanig gewijzigd dat de commit regelmatig werd uitgevoerd door de clientbibliotheek, in overeenstemming met de instelling <i>auto.commit.interval.ms<\/i>. Dit gedrag bevindt zich ergens tussen de JMS AUTO_ACKNOWLEDGE en DUPS_OK_ACKNOWLEDGE modi. Bij het gebruik van auto-commit konden berichten worden bevestigd, ongeacht of ze daadwerkelijk waren verwerkt \u2014 dit kon gebeuren bij een trage consumer. Als de consumer crashte, werden berichten door de volgende consumer opgehaald, beginnend vanaf de gecommitteerde positie, wat kan leiden tot het overslaan van een bericht. In dit geval verloor Kafka geen berichten, de leescode verwerkte ze gewoon niet.<\/p>\n<p>Deze modus heeft dezelfde perspectieven als in versie 0.9: berichten kunnen worden verwerkt, maar in het geval van een storing kan de offset mogelijk niet zijn gecommitteerd, wat potentieel kan leiden tot dubbele afleveringen. Hoe meer berichten je ophaalt bij het uitvoeren <i>poll ()<\/i>, hoe groter dit probleem.<\/p>\n<p>Zoals besproken in de sectie 'Berichten lezen uit de wachtrij' op pagina 21, bestaat er binnen het berichtenuitwisselingssysteem geen concept van een eenmalige levering van berichten, rekening houdend met de foutmodus.<\/p>\n<p>In Kafka zijn er twee manieren om een offset vast te leggen (committen): automatisch en handmatig. In beide gevallen kunnen berichten meerdere keren worden verwerkt als het bericht wel is verwerkt, maar er een fout is opgetreden v\u00f3\u00f3r de commit. U kunt ook besluiten om een bericht helemaal niet te verwerken, als de commit op de achtergrond heeft plaatsgevonden en uw code is be\u00ebindigd voordat deze met de verwerking is begonnen (mogelijk in Kafka 0.9 en eerdere versies).<\/p>\n<p>U kunt het proces van handmatig committen van offsets beheren in de Kafka-consumenten-API door de parameter <i>enable.auto.commit<\/i> in te stellen op false en expliciet een van de volgende methoden aan te roepen:<\/p>\n<pre><code class=\"java\">void commitSync();\nvoid commitAsync();<\/code><\/pre>\n<p>\nAls u een bericht 'ten minste \u00e9\u00e9n keer' wilt verwerken, moet u de offset handmatig committen met <i>commitSync ()<\/i>, door deze opdracht meteen na de verwerking van berichten uit te voeren.<\/p>\n<p>Deze methoden maken het niet mogelijk om bevestigde (acknowledged) berichten te bevestigen voordat ze zijn verwerkt, maar ze doen niets om dubbele verwerking te voorkomen, terwijl ze tegelijkertijd de indruk van transactionaliteit wekken. In Kafka zijn er geen transacties. De client kan het volgende niet doen:<\/p>\n<ul>\n<li>Automatisch een mislukt bericht terugdraaien (roll back). Consumenten moeten zelf de uitzonderingen afhandelen die voortvloeien uit problematische payloads en backend-onderbrekingen, aangezien ze niet kunnen rekenen op de herlevering van berichten door de broker.<\/li>\n<li>Berichten naar meerdere topics verzenden als onderdeel van \u00e9\u00e9n atomische operatie. Zoals we binnenkort zullen zien, kan de controle over verschillende topics en partijen zich op verschillende machines in het Kafka-cluster bevinden, die geen transacties co\u00f6rdineren bij verzending. Op het moment van schrijven van dit artikel is er werk verricht om dit mogelijk te maken met KIP-98.<\/li>\n<li>Het lezen van een bericht uit \u00e9\u00e9n topic koppelen aan het verzenden van een ander bericht naar een ander topic. Nogmaals, de architectuur van Kafka hangt af van veel onafhankelijke machines die als \u00e9\u00e9n bus fungeren en er wordt geen enkele poging gedaan om dit te verbergen. Bijvoorbeeld, er zijn geen API-componenten die het mogelijk maken om <i>Consument <\/i>en <i>Producent <\/i>in de transactie. In JMS wordt dit gegarandeerd door het object <i>Session<\/i>, waaruit de <i>MessageProducers <\/i>en <i>MessageConsumers<\/i>.<\/li>\n<\/ul>\n<p>\nAls we niet op transacties kunnen vertrouwen, hoe kunnen we dan semantiek garanderen die dichter ligt bij wat traditionele berichtenuitwisselingssystemen bieden?<\/p>\n<p>Als er een kans bestaat dat de offset van de consument kan toenemen voordat het bericht is verwerkt, bijvoorbeeld tijdens een storing van de consument, heeft de consument geen manier om te weten of zijn consumentengroep berichten heeft gemist wanneer hem een partitie wordt toegewezen. Een van de strategie\u00ebn is daarom om de offset terug te spoelen naar de vorige positie. De Kafka-consumenten-API biedt de volgende methoden hiervoor:<\/p>\n<pre><code class=\"java\">void seek(TopicPartition partition, long offset);\nvoid seekToBeginning(Collection  partitions);<\/code><\/pre>\n<p>\nMethode <i>seek ()<\/i> kan worden gebruikt met de methode <br \/>\n<i>offsetsForTimes (Map timestampsToSearch)<\/i> om terug te spoelen naar een bepaalde staat op een bepaald moment in het verleden.<\/p>\n<p>Impliciet betekent het gebruik van deze aanpak dat het zeer waarschijnlijk is dat enkele berichten die eerder zijn verwerkt, opnieuw worden gelezen en verwerkt. Om dit te voorkomen, kunnen we idempotente leesmethoden gebruiken, zoals beschreven in Hoofdstuk 4, om eerder bekeken berichten bij te houden en duplicaten uit te sluiten.<\/p>\n<p>Als alternatief kan de code van uw consument eenvoudig zijn, als verlies of duplicatie van berichten acceptabel is. Wanneer we gebruiksscenario's overwegen waarvoor Kafka meestal wordt gebruikt, zoals het verwerken van logboeken, statistieken, kliktracking, enz., begrijpen we dat het verlies van individuele berichten waarschijnlijk een verwaarloosbare impact zal hebben op de omringende applicaties. In dergelijke gevallen zijn de standaardwaarden volkomen acceptabel. Aan de andere kant, als uw applicatie betalingen moet verwerken, moet u zorgvuldig omgaan met elk afzonderlijk bericht. Het komt allemaal neer op de context.<\/p>\n<p>Persoonlijke observaties laten zien dat naarmate de intensiteit van berichten toeneemt, de waarde van elk afzonderlijk bericht afneemt. Berichten van grote omvang worden doorgaans waardevol als ze in geaggregeerde vorm worden beschouwd.<\/p>\n<h2>Hoge beschikbaarheid (High Availability)<\/h2>\n<p>\nDe aanpak van Kafka met betrekking tot hoge beschikbaarheid verschilt wezenlijk van die van ActiveMQ. Kafka is ontworpen op basis van horizontaal schaalbare clusters, waarin alle brokerinstellingen gelijktijdig berichten ontvangen en verzenden.<\/p>\n<p>Een Kafka-cluster bestaat uit meerdere brokerinstellingen die op verschillende servers draaien. Kafka is ontwikkeld voor gebruik op reguliere autonome hardware, waarbij elke node zijn eigen toegewezen opslag heeft. Het gebruik van netwerkopslag (SAN) wordt niet aanbevolen, omdat meerdere rekenknopen kunnen concurreren voor de tijdsintervallen van de opslag en conflicten kunnen cre\u00ebren.<i>Z<\/i>Deze.<\/p>\n<p>Kafka is een <i>altijd ingeschakelde<\/i> systeem. Veel grote gebruikers van Kafka schakelen hun clusters nooit uit en de software zorgt altijd voor updates door middel van gestructureerde herstarts. Dit wordt bereikt door compatibiliteit met eerdere versies voor berichten en interacties tussen brokers te garanderen.<\/p>\n<p>Brokers zijn verbonden met het cluster van servers <noindex><a rel=\"nofollow\" href=\"http:\/\/zookeeper.apache.org\">ZooKeeper<\/a><\/noindex>, dat fungeert als een configuratieregister en wordt gebruikt voor de co\u00f6rdinatie van de rollen van elke broker. ZooKeeper zelf is een gedistribueerd systeem dat hoge beschikbaarheid biedt door informatie te repliceren door het vestigen van een <i>quorum.<\/i>.<\/p>\n<p>In de basisconfiguratie wordt een topic in het Kafka-cluster aangemaakt met de volgende eigenschappen:<\/p>\n<ul>\n<li>Aantal partities. Zoals eerder besproken, is de exacte waarde die hier wordt gebruikt afhankelijk van het gewenste niveau van parallele lezing.<\/li>\n<li>De replicatiefactor bepaalt hoeveel brokerinstellingen binnen het cluster de logs voor deze partitie moeten bevatten.<\/li>\n<\/ul>\n<p>\nDoor gebruik te maken van ZooKeeper voor co\u00f6rdinatie, probeert Kafka nieuwe partities eerlijk te verdelen over de brokers in het cluster. Dit wordt gedaan door \u00e9\u00e9n instantie, die de rol van Controller vervult.<\/p>\n<p>Tijdens de runtime <i>toewijst voor elke partitie van het topic<\/i> <i>Controller <\/i>de rollen aan brokers <i>leider <\/i>(leader, master, hoofd) en <i>volgers. <\/i>(followers, slaves, subordinates). De broker die optreedt als leider voor deze partition is verantwoordelijk voor het ontvangen van alle berichten die door producenten naar hem zijn gestuurd, en voor het verspreiden van de berichten naar de consumenten. Bij het verzenden van berichten naar de partition van het topic worden deze gerepliceerd naar alle broker knooppunten die optreden als volgers voor deze partition. Elk knooppunt dat logs voor de partition bevat, wordt genoemd <i>replica<\/i>. De broker kan als leider fungeren voor sommige partitions en als volger voor andere.<\/p>\n<p>De volger die alle berichten bevat die bij de leider zijn opgeslagen, wordt genoemd <i>gesynchroniseerde replica<\/i> (replica in gesynchroniseerde staat, in-sync replica). Als de broker die als leider voor de partition fungeert, uitvalt, kan elke broker die in de actuele of gesynchroniseerde staat voor deze partition verkeert, de rol van leider overnemen. Dit is een ongelooflijk robuust ontwerp.<\/p>\n<p>Een onderdeel van de producentconfiguratie is de parameter <i>acks<\/i>, die bepaalt hoeveel replica's de ontvangst van een bericht moeten bevestigen (acknowledge) voordat de datastroom van de applicatie doorgaat: 0, 1 of allemaal. Als de waarde wordt ingesteld op <i>all<\/i>, zal de leider bij ontvangst van het bericht een bevestiging (confirmation) terugsturen naar de producent, zodra hij bevestigingen (acknowledgements) van meerdere replica's (inclusief zichzelf) heeft ontvangen, zoals ingesteld door de topicconfiguratie <i>min.insync.replicas<\/i> (standaard 1). Als een bericht niet met succes kan worden gerepliceerd, zal de producent een uitzondering voor de applicatie oproepen (<i>NotEnoughReplicas<\/i> of <i>NotEnoughReplicasAfterAppend<\/i>).<\/p>\n<p>In een typische configuratie wordt een topic met een replicatiefactor van 3 (1 leider, 2 volgers voor elke partition) gemaakt en de parameter <i>min.insync.replicas<\/i> wordt ingesteld op 2. In dit geval staat het cluster toe dat een van de brokers die de partition van het topic beheert, kan uitvallen zonder invloed op de clientapplicaties.<\/p>\n<p>Dit leidt ons terug naar de al bekende compromissen tussen prestaties en betrouwbaarheid. Replicatie gaat ten koste van extra wachttijd voor bevestigingen (acknowledgments) van volgers. Hoewel, omdat het parallel wordt uitgevoerd, heeft replicatie, op zijn minst op drie knooppunten, dezelfde prestaties als op twee (de verhoogde netwerkbandbreedte gebruik negerend).<\/p>\n<p>Met behulp van dit replicatieschema ontwijkt Kafka handig de noodzaak om elke boodschap fysiek op schijf te schrijven met een actie <i>sync ()<\/i>. Elke boodschap die door de producent wordt verzonden, wordt opgeslagen in het partition journal, maar zoals besproken in Hoofdstuk 2, wordt de schrijfactie aanvankelijk uitgevoerd in de buffer van het besturingssysteem. Als deze boodschap wordt gerepliceerd naar een andere Kafka-instantie en zich in zijn geheugen bevindt, betekent het verlies van de leider niet dat de boodschap zelf verloren is gegaan \u2014 deze kan worden overgenomen door een gesynchroniseerde replica.<br \/>\nDe noodzaak om de actie uit te voeren <i>sync ()<\/i> betekent dat Kafka boodschappen kan accepteren met de snelheid waarmee het ze in het geheugen kan schrijven. En omgekeerd, hoe langer de flush (spoelen) van het geheugen naar schijf kan worden uitgesteld, hoe beter. Om deze reden is het niet ongebruikelijk dat Kafka-brokers meer dan 64 GB geheugen toegewezen krijgen. Dit geheugengebruik betekent dat \u00e9\u00e9n Kafka-instantie gemakkelijk snelheden kan bereiken die duizenden keren sneller zijn dan die van een traditionele berichtbroker.<\/p>\n<p>Kafka kan ook worden ingesteld om de actie toe te passen <i>sync ()<\/i> op boodschappenpakketten. Aangezien alles in Kafka gericht is op het werken met pakketten, werkt dit in werkelijkheid behoorlijk goed voor veel gebruiksscenario's en is het een nuttig hulpmiddel voor gebruikers die sterke garanties vereisen. Een groot deel van de pure prestaties van Kafka is gerelateerd aan de boodschappen die in de vorm van pakketten naar de broker worden verzonden, en aan het feit dat deze boodschappen sequentieel uit de broker worden gelezen met behulp van <noindex><a rel=\"nofollow\" href=\"http:\/\/www.linuxjournal.com\/article\/6345\">zero-copy<\/a><\/noindex> operaties (operaties waarin geen kopietaak van gegevens van het ene geheugen naar het andere wordt uitgevoerd). Het laatste is een grote winst op het gebied van prestaties en middelen en is alleen mogelijk dankzij de onderliggende datastructuur van het logboek die het partition schema bepaalt.<\/p>\n<p>In een Kafka-cluster is het mogelijk om veel hogere prestaties te bereiken dan bij het gebruik van een enkele Kafka-broker, omdat de partitions van het topic horizontaal kunnen worden geschaald over meerdere afzonderlijke machines.<\/p>\n<h2>Conclusies<\/h2>\n<p>\nIn dit hoofdstuk hebben we gekeken naar hoe de architectuur van Kafka de relaties tussen clients en brokers heroverweegt om een ongelooflijk veerkrachtige berichtenuitwisselingspijplijn te bieden, met een doorvoercapaciteit die vele malen hoger is dan die van een standaard berichtenbroker. We hebben de functionaliteiten besproken die het gebruikt om dit doel te bereiken en kort de architectuur van de toepassingen die deze functionaliteit mogelijk maken. In het volgende hoofdstuk zullen we de algemene problemen onderzoeken waarmee berichtgebaseerde toepassingen te maken krijgen en bespreken we strategie\u00ebn voor het oplossen daarvan. We sluiten het hoofdstuk af door te schetsen hoe je over berichttechnologie\u00ebn in het algemeen kunt redeneren, zodat je hun geschiktheid voor jouw gebruiksscenario's kunt beoordelen.<\/p>\n<p>Vorige vertaalde deel: <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/post\/466385\/\">Begrijpen van berichtenbrokers. Bestuderen van de mechanica van berichtenoverdracht via ActiveMQ en Kafka. Hoofdstuk 1<\/a><\/noindex><\/p>\n<p><b> Vertaling uitgevoerd: <noindex><a rel=\"nofollow\" href=\"http:\/\/tele.gg\/middle_java\">tele.gg\/middle_java<\/a><\/noindex><\/b><\/p>\n<p><i>Vervolg volgt\u2026<\/i><\/p>\n<p class=\"for_users_only_msg\">Alleen geregistreerde gebruikers kunnen deelnemen aan de enqu\u00eate. <noindex><a rel=\"nofollow\" href=\"https:\/\/habr.com\/ru\/auth\/login\/\">Log in<\/a><\/noindex>, alstublieft.<\/p>\n<h2 class=\"default-block__polling-title\">Wordt Kafka in uw organisatie gebruikt?<\/h2>\n<ul class=\"content-list content-list_polling\">\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Yes<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    No<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    Vroeger wel, nu niet<\/p>\n<\/li>\n<li class=\"content-list__item content-list__item_polling\">\n<p>                    We zijn van plan het te gebruiken<\/p>\n<\/li>\n<\/ul>\n<p>    38 gebruikers hebben gestemd. 8 gebruikers hebben zich onthouden.<br \/>\n<br \/>Bron: <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.3 - 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\/nl\/blog\/administrirovanie\/ponimanie-brokerov-soobshhenij-izuchenie-mehaniki-obmena-soobshheniyami-posredstvom-activemq-i-kafka-glava-3-kafka\" \/>\n\t\t<meta name=\"generator\" content=\"All in One SEO (AIOSEO) 5.0.3\" \/>\n\t\t<meta property=\"og:locale\" content=\"nl_NL\" \/>\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\/nl\/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 Begrip van berichtenbrokers. De mechanica van berichtenuitwisseling leren via ActiveMQ en Kafka. Hoofdstuk 3. Kafka | ProHoster","description":"Vervolg vertaling van het boek: 'Understanding Message Brokers', auteur: Jakub Korab, uitgeverij: O'Reilly Media, Inc., publicatiedatum: juni 2017, ISBN: 9781492049296. Een eerdere vertaling.","canonical_url":"https:\/\/prohoster.info\/nl\/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":"nl_NL","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\/nl\/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\/nl\/wp-json\/wp\/v2\/posts\/38172","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/comments?post=38172"}],"version-history":[{"count":0,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/posts\/38172\/revisions"}],"wp:attachment":[{"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/media?parent=38172"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/categories?post=38172"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/prohoster.info\/nl\/wp-json\/wp\/v2\/tags?post=38172"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}