D. ClickHouse duplicate ingestion и delayed merges¶
Тип материала: учебный архитектурный сценарий. Не описывает систему конкретной компании. Все операции, 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¶
- Приостановить affected publication и зафиксировать input/batch identities.
- Проверить immutable partition/sort key и version contract.
- Для reads выбрать корректный latest-state protocol, учитывать tombstones и conflicts.
- Повреждённую additive MV перестроить из логически дедуплицированной истории в новую generation.
- Проверить результат до background merge и после; сверить с source.
- Не использовать 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.
Источники и версии¶
- ClickHouse insert deduplication — rolling; examples 25.8.