问题现象
使用JDBC接口向Clickhouse数据库中批量写入数据,数据表使用ReplicatedMergeTree引擎,写入完成后统计条数,发现比文件实际条数少了几条,多次测试均发现有此问题,且clickhouse日志中未发现错误信息。
- clickhouse版本:
21.9.2.1.
- 写入数据量:>1000w条
原因排查
首先能想到的是数据问题,但是通过实验,发现同一批数据多次写入,每次丢失的条数还不一致,而且将数据表引擎切换为MergeTree后,数据一条没少,因此可以排除是数据本身的问题。然后在github上查找是否有人遇到过类似的问题,确实也有相关的issue:
- Data loss when using jdbc batch insert to ReplicatedMergeTree engine#5027
- Merge parts cause data loss #35704
通过评论区的只言片语中发现一点思路,那就是可能和数据去重有关,但是如何能验证呢?直到看到如下这篇文章:Insert Deduplication / Insert idempotency
总结一下要点:
- Replicated*系列的表有一个插入去重的开关,且是默认开启状态,MergeTree引擎则是默认关闭;
- 此去重是针对数据块级别的去重,即两个数据块如果有相同的记录,且顺序一致,则只会写入一次;这种设计是为了避免由于网络不稳定,导致同一批数据多次重复写入的问题;
- 发生此现象在日志中的关键字是:
Block with ID ... already exists locally as part ... ignoring it
- 避免出现此现象的方法:在服务器配置中增加
insert_deduplicate = 0
的选项,关闭插入去重。
然后我在我自己的日志中检索了一下关键字,确实发现了如上所述的“证据”:
关闭插入去重的选型后,再次进行写入测试,发现数据不再丢失。
最后,是否真的有必要关闭这个选项呢?这个就要看你实际的应用场景了,其实仔细想想也许默认开启也是合理的,毕竟大部分情况数据重复录入是我们更不希望看到的。还有需要注意的就是这个开关只是控制块级别的数据去重的,即使开着,也无法保证写入的数据中一定不存在重复的记录,比如这些重复的记录出现在不同的数据块中的时候。