Zpět na domů

Kafka v Node.js: spolehliví konzumenti a škálování

Článek je věnován návrhu spolehlivých a výkonných Kafka-konzumentů v Node.js. Jsou probírány otázky škálování prostřednictvím partitionů, paralelního zpracování, správy offsetů a minimalizace rebalanců.

Kafka v Node.js: vyhýbáme se chybám v konzumentech
Advertisement 728x90

# Efektivní zpracování zpráv Kafka v Node.js: konzumenti, rebalancování a škálování

Správná implementace konzumentů Kafka v Node.js vyžaduje porozumění nejen základnímu API, ale i architektonickým vlastnostem distribuované fronty. Chyby v nastavení partitionů, strategii čtení nebo správě offsetů vedou k ztrátě zpráv, nadměrným rebalancům a snížení propustnosti. V tomto článku rozebíráme klíčové aspekty tvorby spolehlivých a výkonných konzumentů s využitím KafkaJS.

Partitiony jako základ škálování

Škálování spotřeby zpráv z Kafka-topiku je omezeno počtem partitionů. Bez ohledu na počet spuštěných instancí nemůže být ve skupině aktivních konzumentů více než partitionů v topiku. Formule je jednoduchá: N_konsyumerov ≤ N_partitsiy. Překročení tohoto poměru způsobí, že část instancí zůstane bez přiřazení a bude nečinná, což vytváří zbytečnou zátěž na koordinátora skupiny.

Volba počtu počátečních partitionů je strategické rozhodnutí. I když Kafka umožňuje zvyšovat počet partitionů za běhu, narušuje to záruku pořadí zpráv podle klíče: nové zprávy se stejným klíčem se mohou dostat do jiné partition než předchozí. Pro flexibilitu doporučujeme vybrat číslo s mnoha dělitele (např. 24), aby bylo zajištěno rovnoměrné rozložení při jakémkoli počtu konzumentů od 1 do 24.

Google AdInline article slot

Důležité je pamatovat: celkový počet partitionů v celém clusteru by neměl překročit 200 000. Proto u málo zatížených topiků není nadměrné členění vhodné.

Paralelní zpracování a volba replik

I při přítomnosti více partitionů je u jednoho konzumenta zpracování výchozí řadové. Pro využití paralelismu uvnitř instance se používá volba partitionsConsumedConcurrently:

consumer.run({
    partitionsConsumedConcurrently: 3,
    eachMessage: async ({ topic, partition, message }) => {
        // processing
    },
});

Tímto způsobem se záruka pořadí zachovává v rámci jedné partition, ale ne mezi nimi. To umožňuje bezpečně zvyšovat propustnost bez narušení logiky zpracování.

Google AdInline article slot

Pro geograficky distribuované clustery je kritická síťová latence. Výchozí konzumenti čtou data z leader-repliky, která zároveň obsluhuje zápis. To vytváří úzké hrdlo. Řešením je rack-aware replikace. Na brokech se nastavuje parametr broker.rack, v klientovi se uvádí rackId:

const consumer = kafka.consumer({
  groupId: 'user-service',
  rackId: 'sibir_tomsk'
});

Kafka pak směruje požadavky k replice ve stejné „rackové doméně“, čímž minimalizuje latenci. Malé zpoždění replikace je většinou přijatelné, protože Kafka není určena pro striktní real-time.

Správa offsetů a počáteční čtení

Nové konzument-skupiny se setkávají s běžnou chybou: nevidí historická data. Důvod je chování parametru auto.offset.reset, který je výchozí nastaven na latest. To znamená, že při absenci commitovaného offsetu v __consumer_offsets konzument začne číst z konce partition.

Google AdInline article slot

Alternativou je earliest, ale její použití bez kontroly je riskantní: zpracování víceleté historie může přetížit službu a závislé systémy. Bezpečnější přístup:

  • Použít fromBeginning: true při přihlášení, pokud je potřebná úplná historie:
await consumer.subscribe({ topic: 'user_events', fromBeginning: true });

Tato volba platí pouze při prvním připojení. Po prvním commitu offsetu Kafka ignoruje fromBeginning.

  • Pro bodové obnovení – ručně nastavit offset přes CLI nebo UI nástroje (KafkaUI, Kadeck) po zastavení konzumenta.

Taková kontrola zabraňuje náhodnému přepsání offsetů a zajišťuje integritu zpracování.

Strategie rebalancování a jejich pasti

Rebalancování je proces přerozdělování partitionů při změně složení skupiny. KafkaJS podporuje pouze strategii Eager, při níž všichni konzumenti zastaví zpracování („stop-the-world“), dokončí aktuální úlohy, commitnou offsety a čekají na přiřazení nových partitionů.

Časté rebalancování snižuje dostupnost a zvyšuje latenci. Hlavní příčiny:

  • Smíšená funkcionalita v jednom procesu – HTTP server, úlohy na pozadí a konzument v jedné instanci. Jakákoli fatální chyba mimo zpracování zpráv způsobí pád celého procesu a spustí rebalancování.
  • Nesprávné timeouty – hodnoty sessionTimeout a heartbeatInterval musí být sladěné. Typické pravidlo: heartbeatInterval ≤ sessionTimeout / 3.
  • Dlouhé zpracování zpráv – pokud zpracování jedné zprávy překročí rebalanceTimeout, konzument je vyloučen ze skupiny.

Pro diagnostiku je užitečné přihlásit se k události REBALANCING:

consumer.on(consumer.events.REBALANCING, ({ payload }) => {
  console.log('Rebalancing started for group:', payload.groupId);
});

To umožňuje sbírat metriky a odhalovat anomální frekvence rebalancování.

Ačkoli Kafka 2.3+ nabízí Static Membership a CooperativeStickyAssignor pro zmírnění těchto problémů, KafkaJS je zatím nepodporuje. Proto jsou architektonická opatření jedinou cestou k stabilitě.

Co je důležité

  • Počet partitionů určuje horní limit horizontálního škálování konzumentů.
  • Paralelní zpracování (partitionsConsumedConcurrently) zrychluje zpracování bez ztráty pořadí uvnitř partition.
  • Čtení z lokální repliky (rackId) snižuje síťovou latenci v geo-distribuovaných prostředích.
  • Nové konzument-skupiny výchozí přeskakují historii – použijte fromBeginning nebo ruční nastavení offsetů.
  • Izolujte konzumenty od ostatních komponent aplikace, aby se vyhnuli neopodstatněným rebalancům.

— Editorial Team

Advertisement 728x90

Číst dál