clickhouse 写入数据失败重试会发生什么

2,188 阅读3分钟

用户写入 ClickHouse 一般有两种选择:分布式表(i.e. Distributed),MergeTree 表

数据写入分布式表时,它会将数据先放入本地磁盘的缓冲区,再异步分发给所有节点上的 MergeTree 表。如果数据在同步给 MergeTree 里面之前这个节点宕机了,数据就可能会丢失;此时如果在失败后再重试,数据就可能会写重。因而,直接将数据写入用分布式表时,不太好保证数据准确性的和一致性。

当然这个分布式表还有其他问题,一般来说一个 ClickHouse 集群会配置多个 shard,每个 shard 都会建立 MergeTree 表和对应的分布式表。如果直接把数据写入分布式表,数据就可能会分发给每个 shard。假设有 N 个节点,每个节点每秒收到一个 INSERT Query,分发 N 次之后,一共就是每秒生成 NxN 个 part 目录。集群 shard 数越多,分发产生的小文件也会越多,最后会导致你写入到 MergeTree 的 Part 的数会特别多,最后会拖垮整个文件的系统。

直接写入 MergeTree 表可以解决数据分发的问题,但是依然抗不住高频写入,如果业务方写入频次控制不好,仍然有可能导致 ClickHouse 后台合并的速度跟不上写入的速度,最后会使得文件系统压力过大。

所以对于万亿数据的公司,可以采取禁止用户用 INSERT Query 把数据直接写入到 ClickHouse的方法。

如果写入过程中,发生写入数据失败呢,往往策略是数据重试再发送。重发数据对于clickhouse有啥影响。 我觉得,完整的思考,是得看你用的啥表引擎。

默认mergetree表引擎不是幂等的,不能去重,但是有些表引擎ReplacingMergeTree是可以局部自动去重,ReplacingMergeTree仅是在“一定程度”上解决了重复数据的问题。(ReplacingMergeTree是以分区为单位进行合并,并在此时删除重复数据。如果这个重复数据跨越了分区,那么并不会删除。

所以你需要结合你的业务建表情况,综合判断,重发数据到底是不是有“幂等”的效果。 如果你重复数据肯定会被归纳到一个分区内,那么使用ReplacingMergeTree其实是有“幂等”的效果的。 如果你用mergetree表引擎,那么肯定不会去重,数据重发肯定是有影响。

MergeTree的主键(PRIMARY KEY)只是用来生成一级索引(primary.idx)的,并没有唯一性约束这样的语义。

ReplacingMergeTree通过ORDER BY,表示判断唯一约束的条件。当分区合并之时,根据ORDER BY排序后,相邻重复的数据会被排除。

只有你使用了“去重”功能的mergetree,比如ReplacingMergeTree,才会根据order by的联合条件来去重。

比如ReplacingMergeTree建表语法参考:(根据 id + code 分组去重)


create table replace_test(
        id String,
        code String,
        create_time DateTime
)ENGINE = ReplacingMergeTree()
PARTITION BY toYYYYMM(create_time)
ORDER BY (id,code)
PRIMARY key id;