返回首页

ClickHouse:MV 中的去重和数据丢失

本文分析了使用 ClickHouse 物化视图时由于块去重导致的数据丢失机制。描述了 INSERT 原子性的条件、block_id 的作用以及推荐设置以消除问题。适合 OLAP 系统中级/高级开发者。

ClickHouse 在物化视图中如何丢失数据
Advertisement 728x90

## ClickHouse 中的数据丢失:去重与物化视图

在 ClickHouse 中,使用物化视图时,目标表中的数据可能与源表不匹配。这是因为在 INSERT 操作期间进行块去重,尤其是在复制集群中。默认配置会导致重复插入时忽略块,从而破坏追加式存储的预期。解决方案是调整 insert_deduplicate 和 deduplicate_blocks_in_dependent_materialized_views 设置。

考虑一个典型的管道流程:

CREATE TABLE source_table (
    message     String
) engine=MergeTree()
ORDER BY (message);

CREATE TABLE final_table (
    message     String
) engine=MergeTree()
ORDER BY (message);

CREATE MATERIALIZED VIEW mv_source_table TO final_table AS
SELECT 
    message
FROM source_table;

source_table 中的数据会被复制到 final_table 中,但随着时间推移,final_table 中的记录会无缘无故消失。

Google AdInline article slot

INSERT 原子性的详细说明

ClickHouse 根据 max_insert_block_size 设置将 INSERT 数据拆分为块。在一个 MergeTree 表分区中,仅保证单个块的原子性。如果 INSERT 被中断,ClickHouse 会尝试重试插入缺失的块,而不通知用户。

重试时,去重机制启动:每个块会获得一个基于其内容的哈希值作为 block_id。如果该 block_id 已存在于去重日志中,整个块就会被跳过。结果是:

  • 原始 INSERT 的部分数据丢失。
  • 物化视图无法接收完整数据。

原子性的条件:

Google AdInline article slot
  • 插入到单个分区。
  • 没有对同一分区的并发 INSERT。
  • 数据打包到一个块中。

不符合这些条件会导致部分插入,并在重试时触发去重。

块去重机制

在复制的 MergeTree 表中,去重在块级别运作。insert_deduplicate 设置(默认为 1)启用 block_id 检查。如果发现重复,该块就会被忽略。

在非复制表中,去重被禁用(non_replicated_deduplication_window=0)。对于复制,推荐设置:

Google AdInline article slot
insert_deduplicate = 0

这可以防止重复 INSERT 时块丢失,但会允许重复。对于分析型的追加式工作负载,重复是可以接受的,并在合并过程中清理。

物化视图中的去重

物化视图基于源数据向目标表执行 INSERT。默认情况下,在源表上检查去重,并将状态传递到视图。

deduplicate_blocks_in_dependent_materialized_views 设置控制此行为:

  • 0(默认):在 source_table 上进行去重,有数据丢失风险。
  • 1:在 final_table 上进行去重,块会完整插入。

设置:

SET deduplicate_blocks_in_dependent_materialized_views = 1;

ClickHouse 文档明确警告,如果不进行调整,物化视图在重复块插入时可能会丢失数据。

推荐设置

为了消除数据丢失,请在服务器或会话配置中应用以下更改:

  • insert_deduplicate = 0 — 禁用重复 INSERT 的去重。
  • deduplicate_blocks_in_dependent_materialized_views = 1 — 在 MV 的目标表上去重。
  • 检查 max_insert_block_size:较大的值可以最小化块拆分。
  • 避免对同一分区进行并发 INSERT。

监控日志中的部分插入,并比较源表和目标表之间的 COUNT(*)。

关键要点

  • ClickHouse 仅对一个分区中的单个块保证 ACID 属性;其他一切取决于设置。
  • 基于 block_id 的块去重会导致 MV 管道中断 INSERT 时的数据丢失。
  • 禁用 insert_deduplicate 可以解决复制 MergeTree 的问题。
  • 设置 deduplicate_blocks_in_dependent_materialized_views=1 可以防止视图中的丢失。
  • 禁用去重后产生的重复会在标准合并中移除。

— Editorial Team

Advertisement 728x90

继续阅读