Zpět na domů

Kafka Engine ClickHouse: atomarita bez ztrát

Článek rozebírá problémy častých INSERT v ClickHouse MergeTree a řešení přes Kafka Engine. Demonstruje se atomarita: offset se commituje až po úspěšném zápisu. Srovnání s bufferovými tabulkami, kód pipeline a testy.

Kafka Engine chrání data v ClickHouse před ztrátami
Advertisement 728x90

Kafka Engine v ClickHouse: záruka atomarity vložení bez ztráty dat

Časté jednotlivé vložení do tabulek MergeTree (10 000 INSERT/s) vede k poklesu výkonu na 59 řádků/s, v ReplicatedMergeTree na 6 řádků/s, s kvórem na 2 řádky/s. To je způsobeno vytvářením mnoha malých částí dat, které se periodicky slučují (merge) podle nastavení max_merge_selecting_sleep_ms. Proces slučování přetěžuje CPU a I/O, čímž snižuje celkovou rychlost.

Bufferové tabulky se zdají být řešením: data se hromadí v RAM a flushují se do cílové tabulky dávkami (podle času, objemu nebo počtu řádků). To minimalizuje počet souborů a zátěž na merge. Nicméně při pádu ClickHouse se nesflushovaná data z paměti ztratí.

Bufferové tabulky: mechanismus a rizika

Bufferová tabulka používá engine Buffer, hromadí data v paměti do podmínek flush: max_time_to_flush (např. 100 s), min_time_to_flush, max_rows_to_flush (1 milion řádků), max_bytes_to_flush (1 GB). Flush probíhá atomárně do MergeTree, ale až po zápisu na disk.

Google AdInline article slot

Klíčové riziko: při krachu serveru (kill -9, OOM) obsah bufferu v RAM zmizí bez možnosti obnovy. Neexistuje replikace ani WAL pro buffery, což činí tento přístup nespolehlivým pro streamy s vysokou zátěží.

Přechod na Kafka Engine tento problém řeší: data jsou persistentní v Kafka, ClickHouse commituje offset až po úspěšném zpracování.

Nastavení pipeline Kafka Engine

Jednoduchý stack: Kafka + ZooKeeper + ClickHouse v Dockeru. Vytvoříme topic test_topic_json s JSON zprávami:

Google AdInline article slot
{"message": "qq"}
{"message": "bb"}

V ClickHouse pipeline ze tří komponent:

  • Tabulka Kafka Engine pro čtení:
drop table if exists test_kafka_json_parse;
create table test_kafka_json_parse
(
    message String
)
engine = Kafka
SETTINGS kafka_broker_list = 'kafka:29092'
    , kafka_topic_list = 'test_topic_json'
    , kafka_group_name = 'my-group4'
    , kafka_format = 'JSONEachRow'
    , kafka_max_block_size = 2097152;
  • Materializované zobrazení jako consumer:
drop view if exists test_kafka_json_parse_view;
create materialized view test_kafka_json_parse_view
TO default.message_json_parse
(
 `message` String
)
AS SELECT message FROM test_kafka_json_parse;
  • Cílová MergeTree:
create table message_json_parse
(
    message String
)
engine = MergeTree
order by message;

Demonstrace atomarity

Po odeslání zpráv je offset consumeru my-group4 roven 2 (End=2). Nyní změníme typ sloupce v message_json_parse na UInt64 – parsování JSON řetězce "gg" selže:

drop table if exists message_json_parse;
create table message_json_parse
(
    message UInt64
)
engine = MergeTree
order by message;

Odešleme {"message": "gg"}. Offset zůstane 2 (End=3), log ClickHouse: Cannot parse string 'gg' as UInt64. Offset se commituje až po úspěšném zápisu do MV → MergeTree.

Google AdInline article slot

ClickHouse načte zprávu do RAM, ale necommituje offset při chybě. Nové zprávy jsou blokovány do opravy. Po opravě typu na String:

  • Zpráva "gg" se zapíše.
  • Offset se aktualizuje na 3.
  • Žádné ztráty i po restartu ClickHouse.

Co je důležité

  • Atomarita: Kafka offset se commituje po insertu do materializovaného zobrazení a zaručuje exactly-once sémantiku.
  • Obnova: Po selhání/chybě zpracování pokračuje z posledního committed offsetu bez duplicit nebo propustů.
  • Výkon: Dávkové zpracování z Kafka minimalizuje malé části v MergeTree.
  • Spolehlivost: Kafka ukládá data persistentně, ClickHouse je stateless consumer.
  • Omezení: Vyžaduje Kafka infrastrukturu; nastavte kafka_skip_broken_messages=0 pro striktní zpracování.

Doporučení pro implementaci

  • Používejte kafka_num_consumers >1 pro paralelizmus.
  • Nastavte max_block_size=2MB+ pro batching.
  • Monitorujte offsets: SELECT * FROM system.kafka_consumers.
  • Pro JSON: JSONEachRow se striktním parsováním.

— Editorial Team

Advertisement 728x90

Číst dál