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

进击的阿张 发表于 2021/12/24 16:09:50 2021/12/24
【摘要】 有时候,我们明明已经插入了数据,可是查询到的数据行数并没有新增,现对该情况进行分析。

问题现象

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

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行。

问题分析

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

<Information> 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。

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区),文章链接,文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至:cloudbbs@huaweicloud.com进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。