## 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 中的记录会无缘无故消失。
INSERT 原子性的详细说明
ClickHouse 根据 max_insert_block_size 设置将 INSERT 数据拆分为块。在一个 MergeTree 表分区中,仅保证单个块的原子性。如果 INSERT 被中断,ClickHouse 会尝试重试插入缺失的块,而不通知用户。
重试时,去重机制启动:每个块会获得一个基于其内容的哈希值作为 block_id。如果该 block_id 已存在于去重日志中,整个块就会被跳过。结果是:
- 原始 INSERT 的部分数据丢失。
- 物化视图无法接收完整数据。
原子性的条件:
- 插入到单个分区。
- 没有对同一分区的并发 INSERT。
- 数据打包到一个块中。
不符合这些条件会导致部分插入,并在重试时触发去重。
块去重机制
在复制的 MergeTree 表中,去重在块级别运作。insert_deduplicate 设置(默认为 1)启用 block_id 检查。如果发现重复,该块就会被忽略。
在非复制表中,去重被禁用(non_replicated_deduplication_window=0)。对于复制,推荐设置:
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
暂无评论。