Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka

Pokračování překladu útlé knížky:
Porozumění zprostředkovatelům zpráv
autor: Jakub Korab, vydavatel: O'Reilly Media, Inc., datum vydání: červen 2017, ISBN: 9781492049296.

Předchozí přeložená část: Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. kapitola 1 Úvod

KAPITOLA 3

Kafka

Kafka byl vyvinut společností LinkedIn, aby obešel některá omezení tradičních zprostředkovatelů zpráv a nemusel nastavovat více zprostředkovatelů zpráv pro různé interakce point-to-point, což je popsáno v této knize v části „Zvětšení a zmenšení“ na straně 28. Příklady použití LinkedIn se do značné míry spoléhal na jednosměrné přijímání velmi velkého množství dat, jako jsou kliknutí na stránky a protokoly přístupu, přičemž stále umožňuje, aby tato data byla používána více systémy bez dopadu na produktivitu výrobců nebo jiných spotřebitelů. Důvodem, proč Kafka existuje, je ve skutečnosti získat takovou architekturu zpráv, kterou popisuje Universal Data Pipeline.

Vzhledem k tomuto konečnému cíli přirozeně vyvstaly další požadavky. Kafka by měl:

  • Buďte extrémně rychlí
  • Poskytněte větší šířku pásma při práci se zprávami
  • Podpora modelů Publisher-Subscriber a Point-to-Point
  • Nezpomalujte s přidáváním spotřebitelů. Například výkon fronty i tématu v ActiveMQ klesá s rostoucím počtem spotřebitelů v cíli.
  • Být horizontálně škálovatelný; pokud jeden zprostředkovatel, který přetrvává zprávy, to dokáže pouze při maximální rychlosti disku, pak má smysl jít nad rámec jedné instance zprostředkovatele a zvýšit výkon
  • Omezte přístup k ukládání a opětovnému načítání zpráv

Aby toho všeho dosáhl, Kafka přijal architekturu, která nově definovala role a odpovědnosti klientů a zprostředkovatelů zpráv. Model JMS je velmi orientovaný na brokera, kde broker odpovídá za distribuci zpráv a klienti se musí starat pouze o odesílání a přijímání zpráv. Kafka je naproti tomu orientován na klienta, kdy klient přebírá mnoho funkcí tradičního brokera, jako je spravedlivá distribuce relevantních zpráv spotřebitelům, výměnou za extrémně rychlého a škálovatelného brokera. Pro lidi, kteří pracovali s tradičními systémy zasílání zpráv, vyžaduje práce s Kafkou zásadní změnu myšlení.
Tento inženýrský směr vedl k vytvoření infrastruktury pro zasílání zpráv schopné zvýšit propustnost o mnoho řádů ve srovnání s konvenčním brokerem. Jak uvidíme, tento přístup přichází s kompromisy, což znamená, že Kafka není vhodný pro určité typy úloh a nainstalovaný software.

Jednotný model destinace

Aby Kafka splnil výše popsané požadavky, zkombinoval publikovat-předplatit a zasílání zpráv point-to-point pod jedním druhem cíle − téma. To je matoucí pro lidi, kteří pracovali se systémy zasílání zpráv, kde slovo „téma“ odkazuje na vysílací mechanismus, z něhož je čtení (z tématu) netrvanlivé. Kafkova témata by měla být považována za hybridní typ destinace, jak je definováno v úvodu této knihy.

Po zbytek této kapitoly, pokud výslovně neuvedeme jinak, bude pojem „téma“ odkazovat na Kafkovo téma.

Abychom plně pochopili, jak se témata chovají a jaké záruky poskytují, musíme se nejprve podívat na to, jak jsou v Kafce implementována.
Každé téma v Kafkovi má svůj vlastní log.
Producenti odesílající zprávy Kafkovi zapisují do tohoto protokolu a spotřebitelé z něj čtou pomocí ukazatelů, které se neustále pohybují vpřed. Kafka pravidelně maže nejstarší části protokolu, ať už byly zprávy v těchto částech přečteny nebo ne. Ústřední součástí Kafkova návrhu je, že brokerovi je jedno, jestli jsou zprávy čteny nebo ne – to je odpovědnost klienta.

Výrazy „log“ a „ukazatel“ se v něm nevyskytují Kafkova dokumentace. Tyto dobře známé termíny jsou zde použity pro usnadnění porozumění.

Tento model je zcela odlišný od ActiveMQ, kde se zprávy ze všech front ukládají do stejného logu a broker po přečtení označí zprávy jako smazané.
Pojďme se nyní ponořit trochu hlouběji a podívat se na log tématu podrobněji.
Protokol Kafka se skládá z několika oddílů (Obrázek 3 1-). Kafka garantuje přísné řazení v každém oddílu. To znamená, že zprávy zapsané na diskový oddíl v určitém pořadí budou čteny ve stejném pořadí. Každý oddíl je implementován jako soubor žurnálu, který obsahuje podmnožina (podmnožina) všech zpráv zaslaných k tématu jeho producenty. Vytvořené téma obsahuje standardně jeden oddíl. Myšlenka oddílů je ústřední myšlenkou Kafky pro horizontální škálování.

Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka
Obrázek 3-1. Kafkovy příčky

Když producent pošle zprávu na téma Kafka, rozhodne se, na který oddíl zprávu pošle. Na to se podíváme podrobněji později.

Čtení zpráv

Klient, který chce číst zprávy, spravuje pojmenovaný ukazatel skupina spotřebitelů, který ukazuje na offset zprávy v oddílu. Posun je přírůstková pozice, která začíná na 0 na začátku oddílu. Tato skupina spotřebitelů, na kterou se odkazuje v rozhraní API prostřednictvím uživatelem definovaného group_id, odpovídá jeden logický spotřebitel nebo systém.

Většina systémů zasílání zpráv čte data z místa určení pomocí více instancí a vláken pro paralelní zpracování zpráv. Obvykle tedy bude mnoho instancí spotřebitelů sdílejících stejnou skupinu spotřebitelů.

Problém čtení lze znázornit takto:

  • Téma má více oddílů
  • Téma může používat více skupin spotřebitelů současně
  • Skupina spotřebitelů může mít více samostatných instancí

Toto je netriviální problém mnoho k mnoha. Abychom pochopili, jak Kafka zachází se vztahy mezi skupinami spotřebitelů, instancemi spotřebitelů a oddíly, podívejme se na řadu postupně složitějších scénářů čtení.

Spotřebitelé a spotřebitelské skupiny

Vezměme si jako výchozí bod téma s jedním oddílem (Obrázek 3 2-).

Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka
Obrázek 3-2. Zákazník čte z oddílu

Když se instance spotřebitele připojí se svým vlastním group_id k tomuto tématu, je jí přiřazen oddíl pro čtení a posun v tomto oddílu. Pozice tohoto offsetu je konfigurovatelná v klientovi jako ukazatel na nejnovější pozici (nejnovější zpráva) nebo nejstarší pozici (nejstarší zpráva). Spotřebitel požaduje (dotazuje) zprávy z tématu, což způsobí jejich postupné čtení z protokolu.
Offsetová pozice je pravidelně odesílána zpět do Kafky a ukládána jako zprávy v interním tématu _consumer_offsety. Přečtené zprávy se na rozdíl od běžného brokera stále nesmažou a klient může posun přetočit a znovu zpracovat již zobrazené zprávy.

Když se druhý logický spotřebitel připojí pomocí jiného group_id, spravuje druhý ukazatel, který je nezávislý na prvním (Obrázek 3 3-). Téma Kafka se tedy chová jako fronta, kde je jeden spotřebitel, a jako normální téma publikovat-předplatit (pub-sub), které odebírá více spotřebitelů, s další výhodou, že všechny zprávy jsou uloženy a mohou být zpracovány vícekrát.

Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka
Obrázek 3-3. Dva spotřebitelé v různých skupinách spotřebitelů čtou ze stejného oddílu

Spotřebitelé ve skupině spotřebitelů

Když jedna instance spotřebitele čte data z oddílu, má plnou kontrolu nad ukazatelem a zpracovává zprávy, jak je popsáno v předchozí části.
Pokud bylo několik instancí spotřebitelů připojeno se stejným group_id k tématu s jedním oddílem, pak instance, která se připojila jako poslední, získá kontrolu nad ukazatelem a od tohoto okamžiku bude přijímat všechny zprávy (Obrázek 3 4-).

Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka
Obrázek 3-4. Dva spotřebitelé ve stejné skupině spotřebitelů čtou ze stejného oddílu

Tento způsob zpracování, ve kterém počet instancí spotřebitelů převyšuje počet oddílů, lze považovat za druh výhradního spotřebitele. To může být užitečné, pokud potřebujete „aktivní-pasivní“ (nebo „horké-teplé“) shlukování instancí vašich spotřebitelů, ačkoli provozování více spotřebitelů paralelně („aktivní-aktivní“ nebo „horké-horké“) je mnohem typičtější než spotřebitelé. V pohotovostním režimu.

Toto chování distribuce zpráv popsané výše může být překvapivé ve srovnání s tím, jak se chová běžná fronta JMS. V tomto modelu budou zprávy odeslané do fronty rovnoměrně rozděleny mezi dva spotřebitele.

Nejčastěji, když vytváříme více instancí spotřebitelů, děláme to buď pro paralelní zpracování zpráv, nebo pro zvýšení rychlosti čtení nebo pro zvýšení stability procesu čtení. Vzhledem k tomu, že pouze jedna instance spotřebitele může číst data z oddílu najednou, jak je toho v Kafka dosaženo?

Jedním ze způsobů, jak toho dosáhnout, je použít jedinou instanci spotřebitele ke čtení všech zpráv a jejich předání do fondu vláken. I když tento přístup zvyšuje propustnost zpracování, zvyšuje složitost spotřebitelské logiky a nijak nezvyšuje robustnost čtecího systému. Pokud jedna kopie spotřebiče vypadne kvůli výpadku napájení nebo podobné události, odečítání se zastaví.

Kanonický způsob, jak vyřešit tento problém v Kafkovi, je použít bОvíce oddílů.

Dělení oddílů

Oddíly jsou hlavním mechanismem pro paralelizaci čtení a škálování tématu nad rámec šířky pásma jediné instance brokera. Abychom tomu lépe porozuměli, uvažujme situaci, kdy existuje téma se dvěma oddíly a jeden spotřebitel toto téma odebírá (Obrázek 3 5-).

Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka
Obrázek 3-5. Jeden spotřebitel čte z více oddílů

V tomto scénáři dostane spotřebitel kontrolu nad ukazateli odpovídajícími jeho group_id v obou oddílech a začne číst zprávy z obou oddílů.
Když je k tomuto tématu přidán další spotřebitel pro stejné group_id, Kafka přerozdělí jeden z oddílů z prvního na druhého spotřebitele. Poté bude každá instance spotřebitele číst z jednoho oddílu tématu (Obrázek 3 6-).

Abyste zajistili, že zprávy budou zpracovávány paralelně ve 20 vláknech, potřebujete alespoň 20 oddílů. Pokud je oddílů méně, zbydou vám spotřebitelé, kteří nemají na čem pracovat, jak bylo popsáno dříve v diskusi o exkluzivních spotřebitelích.

Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 3. Kafka
Obrázek 3-6. Dva spotřebitelé ve stejné skupině spotřebitelů čtou z různých oddílů

Toto schéma výrazně snižuje složitost zprostředkovatele Kafka ve srovnání s distribucí zpráv, která je potřebná k udržování fronty JMS. Zde se nemusíte starat o následující body:

  • Který spotřebitel by měl obdržet další zprávu na základě alokace mezi jednotlivými okruhy, aktuální kapacity vyrovnávacích pamětí předběžného načítání nebo předchozích zpráv (jako u skupin zpráv JMS).
  • Které zprávy jsou zasílány kterým spotřebitelům a zda by měly být znovu doručeny v případě selhání.

Vše, co musí zprostředkovatel Kafka udělat, je předávat zprávy sekvenčně spotřebiteli, když si je spotřebitel vyžádá.

Požadavky na paralelizaci korektur a přeposílání neúspěšných zpráv však nezmizí – odpovědnost za ně jednoduše přechází z makléře na klienta. To znamená, že musí být zohledněny ve vašem kódu.

Odesílání zpráv

Je na odpovědnosti výrobce této zprávy, aby rozhodl, do kterého oddílu zprávu odeslat. Abychom pochopili mechanismus, kterým se to děje, musíme nejprve zvážit, co přesně vlastně posíláme.

Zatímco v JMS používáme strukturu zprávy s metadaty (hlavičkami a vlastnostmi) a tělem obsahujícím užitečné zatížení (payload), v Kafce je zpráva pár "klíč-hodnota". Užitná zátěž zprávy je odeslána jako hodnota. Klíč se na druhou stranu používá hlavně pro rozdělení a musí obsahovat specifický klíč obchodní logikyumístit související zprávy do stejného oddílu.

V kapitole 2 jsme diskutovali o scénáři online sázení, kdy související události musí zpracovat v pořadí jeden spotřebitel:

  1. Uživatelský účet je nakonfigurován.
  2. Peníze jsou připsány na účet.
  3. Je uzavřena sázka, která vybírá peníze z účtu.

Pokud je každá událost zprávou zaslanou k tématu, pak přirozeným klíčem bude ID účtu.
Když je zpráva odeslána pomocí rozhraní Kafka Producer API, je předána funkci oddílu, která vzhledem ke zprávě a aktuálnímu stavu clusteru Kafka vrátí ID oddílu, do kterého má být zpráva odeslána. Tato funkce je implementována v Javě prostřednictvím rozhraní Partitioner.

Toto rozhraní vypadá takto:

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

Implementace Partitioner používá výchozí obecný algoritmus hash nad klíčem k určení oddílu, nebo cyklicky, pokud není zadán žádný klíč. Tato výchozí hodnota ve většině případů funguje dobře. V budoucnu však budete chtít napsat svůj vlastní.

Psaní vlastní rozdělovací strategie

Podívejme se na příklad, kdy chcete odeslat metadata spolu s užitečným zatížením zprávy. Užitná zátěž v našem příkladu je pokyn k provedení vkladu na herní účet. Instrukce je něco, u čeho bychom chtěli mít zaručeno, že se při přenosu nezmění, a chceme mít jistotu, že tuto instrukci může iniciovat pouze důvěryhodný upstream systém. V tomto případě se odesílající a přijímající systémy dohodnou na použití podpisu k ověření zprávy.
V normálním JMS jednoduše definujeme vlastnost „podpis zprávy“ a přidáme ji do zprávy. Kafka nám však neposkytuje mechanismus pro předávání metadat, pouze klíč a hodnotu.

Vzhledem k tomu, že hodnotou je datová část bankovního převodu, jejíž integritu chceme zachovat, nezbývá nám nic jiného, ​​než definovat datovou strukturu, kterou v klíči použijeme. Za předpokladu, že potřebujeme ID účtu pro rozdělení, protože všechny zprávy související s účtem musí být zpracovány v pořádku, přijdeme s následující strukturou JSON:

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

Protože se hodnota podpisu bude lišit v závislosti na užitečné zátěži, výchozí strategie hašování rozhraní Partitioner nebude spolehlivě seskupovat související zprávy. Proto budeme muset napsat vlastní strategii, která tento klíč analyzuje a rozdělí hodnotu accountId.

Kafka obsahuje kontrolní součty pro detekci poškození zpráv v obchodě a má kompletní sadu bezpečnostních funkcí. I přesto se někdy objevují požadavky specifické pro dané odvětví, jako je ten výše.

Strategie dělení uživatele musí zajistit, aby všechny související zprávy skončily ve stejném oddílu. I když se to zdá jednoduché, požadavek může být komplikován důležitostí řazení souvisejících zpráv a tím, jak pevný je počet oddílů v tématu.

Počet oddílů v tématu se může v průběhu času měnit, protože mohou být přidány, pokud provoz překročí původní očekávání. Klíče zpráv tedy mohou být spojeny s oddílem, do kterého byly původně odeslány, což znamená, že část stavu bude sdílena mezi instancemi producenta.

Dalším faktorem, který je třeba zvážit, je rovnoměrné rozložení zpráv mezi oddíly. Klíče obvykle nejsou rozmístěny rovnoměrně mezi zprávami a hašovací funkce nezaručují spravedlivé rozdělení zpráv pro malou sadu klíčů.
Je důležité si uvědomit, že ať už se rozhodnete zprávy rozdělit jakkoli, samotný oddělovač může být nutné znovu použít.

Zvažte požadavek na replikaci dat mezi Kafka clustery v různých geografických lokalitách. Za tímto účelem přichází Kafka s nástrojem příkazového řádku MirrorMaker, který slouží ke čtení zpráv z jednoho clusteru a jejich přenosu do jiného.

MirrorMaker musí rozumět klíčům replikovaného tématu, aby zachoval relativní pořadí mezi zprávami při replikaci mezi clustery, protože počet oddílů pro toto téma nemusí být ve dvou clusterech stejný.

Vlastní rozdělovací strategie jsou relativně vzácné, protože výchozí hashování nebo kruhové zpracování funguje dobře ve většině scénářů. Pokud však požadujete silné záruky řazení nebo potřebujete extrahovat metadata z datových částí, pak je rozdělení na oddíly něco, na co byste se měli podívat blíže.

Škálovatelnost a výkonnostní výhody Kafky pocházejí z přesunu některých povinností tradičního makléře na klienta. V tomto případě je učiněno rozhodnutí distribuovat potenciálně související zprávy mezi několik paralelně pracujících spotřebitelů.

S takovými požadavky se musí vypořádat i JMS brokeři. Zajímavé je, že mechanismus pro odesílání souvisejících zpráv stejnému spotřebiteli, implementovaný prostřednictvím JMS Message Groups (variace na strategii lepivého vyvažování zátěže (SLB)), také vyžaduje, aby odesílatel označil zprávy jako související. V případě JMS je broker zodpovědný za zaslání této skupiny souvisejících zpráv jednomu spotřebiteli z mnoha a za převod vlastnictví skupiny, pokud spotřebitel odpadne.

Dohody s producenty

Rozdělení není jediná věc, kterou je třeba při odesílání zpráv zvážit. Podívejme se na metody send() třídy Producer v Java API:

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

Ihned je třeba poznamenat, že obě metody vracejí Future, což znamená, že operace odeslání není provedena okamžitě. Výsledkem je, že zpráva (ProducerRecord) je zapsána do vyrovnávací paměti pro odesílání pro každý aktivní oddíl a odeslána zprostředkovateli jako vlákno na pozadí v klientské knihovně Kafka. I když to dělá věci neuvěřitelně rychlé, znamená to, že nezkušená aplikace může ztratit zprávy, pokud je její proces zastaven.

Jako vždy existuje způsob, jak zvýšit spolehlivost odesílání na úkor výkonu. Velikost této vyrovnávací paměti může být nastavena na 0 a odesílající aplikační vlákno bude nuceno čekat, dokud nebude dokončen přenos zprávy do brokera, a to následovně:

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

Více o čtení zpráv

Čtení zpráv má další složitosti, o kterých je třeba spekulovat. Na rozdíl od JMS API, které může spustit posluchače zpráv v reakci na zprávu, Spotřebitel Kafka jen průzkumy. Pojďme se na metodu podívat blíže hlasování()k tomuto účelu se používá:

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

Návratovou hodnotou metody je struktura kontejneru obsahující více objektů spotřebitelský záznam z potenciálně několika oddílů. spotřebitelský záznam je sám držitelem pro pár klíč-hodnota s přidruženými metadaty, jako je oddíl, ze kterého je odvozen.

Jak je uvedeno v kapitole 2, musíme mít na paměti, co se stane se zprávami poté, co byly úspěšně nebo neúspěšně zpracovány, například pokud klient není schopen zprávu zpracovat nebo pokud se přeruší. V JMS to bylo řešeno prostřednictvím režimu potvrzení. Broker buď smaže úspěšně zpracovanou zprávu, nebo znovu doručí nezpracovanou nebo falešnou zprávu (za předpokladu, že byly použity transakce).
Kafka funguje úplně jinak. Zprávy se po korektuře v broker nesmažou a co se stane při selhání, je odpovědností samotného korekturního kódu.

Jak jsme řekli, skupina spotřebitelů je spojena s offsetem v protokolu. Pozice protokolu spojená s tímto posunem odpovídá další zprávě, která má být vydána jako odpověď hlasování(). Pro čtení je rozhodující okamžik, kdy se tento posun zvyšuje.

Vrátíme-li se k výše popsanému modelu čtení, zpracování zpráv se skládá ze tří fází:

  1. Načíst zprávu ke čtení.
  2. Zpracujte zprávu.
  3. Potvrďte zprávu.

Spotřebitel Kafka přichází s možností konfigurace povolit.auto.potvrdit. Toto je často používané výchozí nastavení, jak je běžné u nastavení obsahujících slovo „auto“.

Před verzí Kafka 0.10 klient využívající tuto možnost posílal offset poslední přečtené zprávy při příštím hovoru hlasování() po zpracování. To znamenalo, že všechny zprávy, které již byly načteny, mohly být znovu zpracovány, pokud je klient již zpracoval, ale byly před voláním neočekávaně zničeny hlasování(). Protože broker neuchovává žádný stav o tom, kolikrát byla zpráva přečtena, další spotřebitel, který tuto zprávu načte, nebude vědět, že se stalo něco špatného. Toto chování bylo pseudotransakční. Posun byl potvrzen pouze v případě, že byla zpráva úspěšně zpracována, ale pokud by se klient přerušil, zprostředkovatel by stejnou zprávu poslal znovu jinému klientovi. Toto chování bylo v souladu se zárukou doručení zprávy "alespoň jednou".

V Kafka 0.10 byl klientský kód změněn tak, že odevzdání je pravidelně spouštěno klientskou knihovnou, jak je nakonfigurováno auto.commit.interval.ms. Toto chování je někde mezi režimy JMS AUTO_ACKNOWLEDGE a DUPS_OK_ACKNOWLEDGE. Při použití automatického potvrzení by mohly být zprávy potvrzeny bez ohledu na to, zda byly skutečně zpracovány - k tomu může dojít v případě pomalého spotřebitele. Pokud by se spotřebitel přerušil, zprávy by byly vyzvednuty dalším spotřebitelem, počínaje od potvrzené pozice, což by mohlo mít za následek zmeškanou zprávu. V tomto případě Kafka zprávy neztratil, čtecí kód je jen nezpracoval.

Tento režim má stejný příslib jako ve verzi 0.9: zprávy lze zpracovat, ale pokud selže, posun nemusí být potvrzen, což může způsobit zdvojnásobení doručení. Čím více zpráv při provádění načtete hlasování(), tím více tohoto problému.

Jak je uvedeno v části “Čtení zpráv z fronty” na stránce 21, neexistuje nic takového jako jednorázové doručení zprávy v systému zasílání zpráv, když se berou v úvahu režimy selhání.

V Kafka existují dva způsoby, jak potvrdit (potvrdit) offset (offset): automaticky a ručně. V obou případech mohou být zprávy zpracovány vícekrát, pokud byla zpráva zpracována, ale selhala před odevzdáním. Můžete se také rozhodnout zprávu vůbec nezpracovat, pokud k potvrzení došlo na pozadí a váš kód byl dokončen dříve, než mohl být zpracován (možná v Kafka 0.9 a dřívějších).

Proces ručního potvrzení posunu v rozhraní API pro spotřebitele Kafka můžete řídit nastavením parametru povolit.auto.potvrdit na hodnotu false a explicitně volá jednu z následujících metod:

void commitSync();
void commitAsync();

Pokud chcete zprávu zpracovat "alespoň jednou", musíte offset potvrdit ručně pomocí commitSync()provedením tohoto příkazu ihned po zpracování zpráv.

Tyto metody neumožňují potvrzení zpráv před jejich zpracováním, ale nedělají nic pro to, aby eliminovaly potenciální zpoždění při zpracování a přitom působily jako transakční. V Kafce nejsou žádné transakce. Klient nemá možnost:

  • Automaticky vrátit zpět falešnou zprávu. Spotřebitelé sami musí zvládnout výjimky vyplývající z problematického zatížení a výpadků backendu, protože se nemohou spolehnout na zprostředkovatele, že zprávy doručí znovu.
  • Odesílejte zprávy na více témat v jedné atomové operaci. Jak brzy uvidíme, kontrolu nad různými tématy a oddíly mohou mít různé počítače v clusteru Kafka, které nekoordinují transakce při odesílání. V době psaní tohoto článku byla provedena určitá práce, aby to bylo možné s KIP-98.
  • Spojte čtení jedné zprávy z jednoho tématu s odesláním jiné zprávy na jiné téma. Architektura Kafky opět závisí na mnoha nezávislých strojích běžících jako jedna sběrnice a není učiněn žádný pokus to zakrýt. Neexistují například žádné komponenty API, které by umožňovaly propojení spotřebitel и Producent v transakci. V JMS to zajišťuje objekt Zasedáníze kterých jsou vytvořeny MessageProducers и MessageConsumers.

Pokud se nemůžeme spolehnout na transakce, jak můžeme poskytnout sémantiku bližší té, kterou poskytují tradiční systémy zasílání zpráv?

Pokud existuje možnost, že se offset spotřebitele může zvýšit před zpracováním zprávy, jako například během zhroucení spotřebitele, pak spotřebitel nemá žádný způsob, jak zjistit, zda jeho skupina spotřebitelů zprávu nezmeškala, když je mu přidělen oddíl. Jednou ze strategií je tedy přetočit offset na předchozí pozici. Spotřebitelské API Kafka k tomu poskytuje následující metody:

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

metoda hledat() lze použít s metodou
offsetsForTimes(Map timestampsToSearch) přetočit do stavu v určitém konkrétním bodě v minulosti.

Použití tohoto přístupu implicitně znamená, že je velmi pravděpodobné, že některé zprávy, které byly dříve zpracovány, budou znovu přečteny a zpracovány. Abychom tomu zabránili, můžeme použít idempotentní čtení, jak je popsáno v kapitole 4, ke sledování dříve zobrazených zpráv a odstranění duplicit.

Alternativně může být váš spotřebitelský kód jednoduchý, pokud je ztráta zpráv nebo duplikace přijatelná. Když se podíváme na případy použití, pro které se Kafka běžně používá, jako je zpracování událostí v protokolech, metriky, sledování kliknutí atd., uvědomíme si, že ztráta jednotlivých zpráv pravděpodobně nebude mít významný dopad na okolní aplikace. V takových případech jsou výchozí hodnoty naprosto přijatelné. Na druhou stranu, pokud vaše aplikace potřebuje posílat platby, musíte se pečlivě starat o každou jednotlivou zprávu. Vše se odvíjí od kontextu.

Osobní pozorování ukazují, že s rostoucí intenzitou zpráv klesá hodnota každé jednotlivé zprávy. Velké zprávy mají tendenci být cenné, když je prohlížíte v agregované podobě.

Vysoká dostupnost

Kafkův přístup k vysoké dostupnosti je velmi odlišný od přístupu ActiveMQ. Kafka je navržena pro škálovatelné clustery, kde všechny instance brokerů přijímají a distribuují zprávy ve stejnou dobu.

Cluster Kafka se skládá z několika instancí brokerů běžících na různých serverech. Kafka byl navržen tak, aby běžel na běžném samostatném hardwaru, kde má každý uzel své vlastní vyhrazené úložiště. Použití úložiště připojeného k síti (SAN) se nedoporučuje, protože více výpočetních uzlů může soutěžit o čas.Ыe intervaly ukládání a vytvářet konflikty.

Kafka je vždy na Systém. Mnoho velkých uživatelů Kafka své clustery nikdy nevypne a software se vždy aktualizuje sekvenčním restartem. Toho je dosaženo zaručením kompatibility s předchozí verzí pro zprávy a interakce mezi brokery.

Brokeři připojeni ke clusteru serverů ZooKeeper, který funguje jako registr konfiguračních dat a slouží ke koordinaci rolí každého brokera. Samotný ZooKeeper je distribuovaný systém, který poskytuje vysokou dostupnost prostřednictvím replikace informací zřízením kvorum.

V základním případě se téma vytvoří v clusteru Kafka s následujícími vlastnostmi:

  • Počet oddílů. Jak bylo uvedeno výše, přesná hodnota zde použitá závisí na požadované úrovni paralelního čtení.
  • Replikační faktor (faktor) určuje, kolik instancí zprostředkovatele v clusteru by mělo obsahovat protokoly pro tento oddíl.

Pomocí ZooKeepers pro koordinaci se Kafka pokouší spravedlivě rozdělit nové oddíly mezi brokery v clusteru. To se provádí jedinou instancí, která funguje jako Controller.

Za běhu pro každý tématický oddíl Ovladač přidělovat role makléři vůdce (vedoucí, mistr, přednášející) a následovníci (následovníci, otroci, podřízení). Broker, který vystupuje jako vedoucí tohoto oddílu, je zodpovědný za přijímání všech zpráv, které mu posílají výrobci, a za distribuci zpráv spotřebitelům. Když jsou zprávy odesílány do tématického oddílu, jsou replikovány do všech uzlů zprostředkovatele, kteří působí jako následovníci pro daný oddíl. Je volán každý uzel obsahující protokoly pro oddíl replika. Broker může pro některé oddíly působit jako vedoucí a u jiných jako následovník.

Zavolá se následovník obsahující všechny zprávy, které má vedoucí synchronizovaná replika (replika, která je v synchronizovaném stavu, synchronizovaná replika). Pokud dojde k výpadku zprostředkovatele působícího jako vedoucí pro oddíl, může roli vedoucího převzít jakýkoli zprostředkovatel, který je aktuální nebo synchronizovaný pro daný oddíl. Je to neuvěřitelně udržitelný design.

Součástí konfigurace výrobce je parametr acks, která určuje, kolik replik musí potvrdit (potvrdit) přijetí zprávy, než vlákno aplikace bude pokračovat v odesílání: 0, 1 nebo všechny. Pokud je nastaveno na všechno, poté, když je zpráva přijata, vedoucí pošle potvrzení zpět producentovi, jakmile obdrží potvrzení (potvrzení) záznamu z několika podnětů (včetně sebe) definovaných nastavením tématu min.insync.repliky (výchozí 1). Pokud zprávu nelze úspěšně replikovat, pak výrobce vyvolá výjimku aplikace (NotEnoughReplicas nebo NotEnoughReplicasAfterAppend).

Typická konfigurace vytvoří téma s faktorem replikace 3 (1 vedoucí, 2 následovníci na oddíl) a parametr min.insync.repliky je nastavena na 2. V tomto případě klastr umožní jednomu z makléřů spravujících tématický oddíl skončit bez ovlivnění klientských aplikací.

To nás přivádí zpět k již známému kompromisu mezi výkonem a spolehlivostí. K replikaci dochází na úkor dodatečné doby čekání na potvrzení (potvrzení) od následovníků. I když, protože běží paralelně, replikace do alespoň tří uzlů má stejný výkon jako dva (ignoruje se nárůst využití šířky pásma sítě).

Použitím tohoto schématu replikace se Kafka chytře vyhýbá nutnosti fyzického zápisu každé zprávy na disk s operací sync(). Každá zpráva odeslaná výrobcem bude zapsána do logu oddílu, ale jak je uvedeno v kapitole 2, zápis do souboru se zpočátku provádí ve vyrovnávací paměti operačního systému. Pokud je tato zpráva replikována na jinou Kafkovu instanci a je v její paměti, ztráta vůdce neznamená, že zpráva samotná byla ztracena – může být převzata synchronizovanou replikou.
Odmítnutí provést operaci sync() znamená, že Kafka může přijímat zprávy tak rychle, jak je dokáže zapisovat do paměti. A naopak, čím déle se můžete vyhnout splachování paměti na disk, tím lépe. Z tohoto důvodu není neobvyklé, že brokerům Kafka je přiděleno 64 GB nebo více paměti. Toto využití paměti znamená, že jedna instance Kafka může snadno běžet rychlostí mnohotisíckrát vyšší než tradiční zprostředkovatel zpráv.

Kafka může být také nakonfigurován pro použití operace sync() do balíků zpráv. Vzhledem k tomu, že vše v Kafce je orientováno na balíčky, ve skutečnosti to funguje docela dobře pro mnoho případů použití a je to užitečný nástroj pro uživatele, kteří vyžadují velmi silné záruky. Velká část čistého výkonu Kafky pochází ze zpráv, které se odesílají zprostředkovateli jako pakety a tyto zprávy se čtou z zprostředkovatele v sekvenčních blocích pomocí nulová kopie operace (operace, během kterých není prováděna úloha kopírování dat z jedné oblasti paměti do druhé). To druhé představuje velký výkon a zisk zdrojů a je možné pouze pomocí základní datové struktury protokolu, která definuje schéma oddílů.

Mnohem lepší výkon je možný v clusteru Kafka než s jedním brokerem Kafka, protože tématické oddíly lze škálovat na mnoha samostatných počítačích.

Výsledky

V této kapitole jsme se podívali na to, jak architektura Kafka přetváří vztah mezi klienty a makléři, aby poskytovala neuvěřitelně robustní kanál pro zasílání zpráv s propustností mnohonásobně vyšší než u konvenčního zprostředkovatele zpráv. Diskutovali jsme o funkcionalitě, kterou k tomu používá, a krátce jsme se podívali na architekturu aplikací, které tuto funkcionalitu poskytují. V další kapitole se podíváme na běžné problémy, které musí aplikace založené na zprávách řešit, a probereme strategie, jak se s nimi vypořádat. Kapitolu zakončíme tím, že nastíníme, jak mluvit o technologiích zasílání zpráv obecně, abyste mohli vyhodnotit jejich vhodnost pro vaše případy použití.

Předchozí přeložená část: Porozumění zprostředkovatelům zpráv. Naučte se mechaniku zasílání zpráv pomocí ActiveMQ a Kafka. Kapitola 1

Překlad hotový: tele.gg/middle_java

Chcete-li se pokračovat ...

Průzkumu se mohou zúčastnit pouze registrovaní uživatelé. Přihlásit se, prosím.

Používá se ve vaší organizaci Kafka?

  • Ano

  • Ne

  • Dříve používané, nyní ne

  • Plánujeme použít

Hlasovalo 38 uživatelů. 8 uživatelů se zdrželo hlasování.

Zdroj: www.habr.com

Přidat komentář