Перейти к содержанию

D. ClickHouse duplicate ingestion и delayed merges

Раздел 04 · Failure matrix

Тип материала: учебный архитектурный сценарий. Не описывает систему конкретной компании. Все операции, IDs и числа ниже — HYPOTHETICAL.

Проверка источников: 2026-11-02. Интеграционный fault test этого сценария — NOT_RUN; documented behavior и предлагаемый recovery не считаются выполненным испытанием.

Normal flow

Kafka event содержит tenant_id, event_id, monotonic event_version и immutable partition key. В ClickHouse 25.8 raw deliveries могут храниться многократно. State projection на ReplacingMergeTree сходится по sort key/version, но запрос до merges должен явно разрешать revisions.

Для net reporting выбирайте latest state на business key; для event ledger отдельно дедуплицируйте immutable event IDs. Эти модели нельзя смешивать.

Иллюстративная схема нормального пути:

flowchart LR
 K[Versioned events] --> B[Retryable insert batches]
 B --> C[ReplacingMergeTree parts]
 C --> Q[Query resolves latest revision]
 C --> M[Background merges]

Failure timeline

sequenceDiagram
 participant I as Ingestor
 participant C as ClickHouse
 participant Q as Query
 I->>C: Insert event e1 v1
 C--xI: ACK lost
 I->>C: Retry e1 v1
 Q->>C: Raw SUM before merges
 C-->>Q: Duplicate contribution possible
 Q->>C: Resolve latest state per key
 C-->>Q: One logical state contribution

Состояние систем после отказа

Участник Durable состояние Неопределённость / проверка
Kafka/ingestor Прогресс может быть до или после insert Обнаружить batch ID и source coordinates
ClickHouse Несколько parts/версий одного key Проверить engine и query semantics до merges
Dashboard Может показать завышенный итог Не ждать merge как протокол financial correctness

Retry и replay

Block insert dedup ограничен engine/settings и окном истории. Изменение batch layout либо истечение окна может пропустить duplicate; это не вечная event_id uniqueness. ReplacingMergeTree не дедуплицирует одинаковый event_id при разном ORDER BY key/partition.

Агрегирующая MV на insert blocks может посчитать оба вклада до replacing merge; последующий merge source не откатывает автоматически уже добавленный sum в target.

Обнаружение проблемы

Считать raw rows и distinct business keys/revisions, выявлять conflicting payload на одинаковой revision, сверять final state totals с authoritative cut. system.parts/merge backlog объясняют физическое состояние, но не подтверждают semantic convergence.

Recovery protocol

  1. Приостановить affected publication и зафиксировать input/batch identities.
  2. Проверить immutable partition/sort key и version contract.
  3. Для reads выбрать корректный latest-state protocol, учитывать tombstones и conflicts.
  4. Повреждённую additive MV перестроить из логически дедуплицированной истории в новую generation.
  5. Проверить результат до background merge и после; сверить с source.
  6. Не использовать OPTIMIZE FINAL как замену permanent uniqueness protocol.

Гарантии и trade-offs

Корректность достигается query/rebuild model с явным scope, а не просто ожиданием background merges. FINAL может быть дорогим и его cross-partition поведение зависит от settings; используйте immutable partition и тестируйте целевую версию. Rolling docs могут включать новые async insert semantics, не подтверждённые для 25.8.

Практическая проверка

ClickHouse lab использует existing schema. Проверка delayed merge обязана сравнивать raw и logical result до принудительного merge. Реальный ClickHouse runtime NOT_RUN.

Источники и версии