ClickHouse问题分析:为什么有时候插入数据后却查询不到新增数据

ClickHouse问题分析:为什么有时候插入数据后却查询不到新增数据

问题现象

有时候,我们明明已经插入了数据,可是查询到的数据行数并没有新增。如下:

CREATE TABLE test (id String)

ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/test', '{replica}')

PARTITION BY id

ORDER BY id;

insert into test values('1'),('2');

我们多次insert数据,然后select数据,发现数据还是只有2行。

问题分析

分析日志,有如下日志记录:

default.test (87dc3f6a-eae8-4b48-bfc0-dd8fd65e5fb5) (Replicated OutputStream): Block with ID 6711e2b2592d86d18fc0f260cf33ef2b_7105010924576188663_2190907065422553159 already exists locally as part 6711e2b2592d86d18fc0f260cf33ef2b_0_0_0; ignoring it.

可以发现,新插入的数据被clickhouse过滤掉了。那么,来看下clickhouse的处理逻辑。

# 数据插入入口

InterpreterInsertQuery::execute

StorageReplicatedMergeTree::write // 构造数据流 ReplicatedMergeTreeBlockOutputStream

deduplicate = replicated_deduplication_window != 0 && insert_deduplicate // 是否去重,跟去重窗口和去重标志有关,默认窗口为100,标志为true

ReplicatedMergeTreeBlockOutputStream::write // 数据写入

block转为part

if deduplicate == true

hash // part的哈希值

block_id = partition_id + "_" + hash.words[0] + "_" + hash.words[1] // 构造block_id的字符串名称

end

commitPart // 向zk提交part

if block_id not empty

zkutil::makeCreateRequest // 如果zk上有相同的节点,则返回空block_number,否则创建该节点

end

if getActiveContainingPart

return // 该part已经被包含,则忽略它

# 复制表清理线程

ReplicatedMergeTreeCleanupThread::run

sleep_ms // 周期间隔时间,默认30s~40s随机

ReplicatedMergeTreeCleanupThread::iterate

clearOldBlocks // 清理过期block

replicated_deduplication_window_seconds

replicated_deduplication_window // 两者综合考虑,超过replicated_deduplication_window或者之间间隔超过replicated_deduplication_window_seconds

在默认情况下,如果一次插入的数据与一周内最近的100次左右(如果一次性插入的block可以分为多个part,则不到100次)成功插入的数据具有相同的block_id,则会被过滤掉。

总结

1、通过设置insert_deduplicate=false,可以让clickhouse不做此项检查,保证数据每次都能插入成功。

2、在业务上,可能会有补数据的场景。这种时候需要考虑清楚补录的数据是否会被过滤掉,否则可能导致有些数据没有补录成功。

3、有点需要注意的是,真正生效的窗口大小可能不止100,可能更多。因为清理线程的周期是30-40s,如果老的block_id没有及时清理掉,会导致实际的去重窗口值大于replicated_deduplication_window。

Copyright © 2088 世界杯欧洲预选赛_南非世界杯主题曲舞蹈 - lyzkxt.com All Rights Reserved.
友情链接