暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

ClickHouse 复制表引擎重复数据无法写入

ClickHouse周边 2022-09-15
2287
      关于复制表重复数据无法写入,这里进行一下演示和剖析。时候,我明明已经插入了数据,可是查询到的数据行数并没有新增,现对该情况进行分析。
    --演示说明


    CREATE TABLE try
    (
    `username` String,
    `lables.name` Array(String),
    `lables.value` Array(String),
    `day` Date
    )
    ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/try', '{replica}')
    PARTITION BY toYYYYMMDD(day)
    ORDER BY username;


    insert into try values ('张三',['os_type','version','database_name','owner'],['linux','redhat_7.6','postgres','postgres'],toDate(now()));
    insert into try values ('李四',['os_type','version','database_name','owner'],['linux','redhat_7.7','flyingdb','flyingdb'],toDate(now()));
    insert into try values ('王五',['os_type','version','database_name','owner'],['linux','Mint_17.3','test','test'],today());
    insert into try values ('赵六',['os_type','version','database_name','owner'],['linux','Mint_17.4','data','data'],today());


    select * from try;
    ┌─username─┬─lables.name───────────────────────────────────┬─lables.value────────────────────────┬────────day─┐
    │ 赵六 │ ['os_type','version','database_name','owner'] │ ['linux','Mint_17.4','data','data'] │ 2022-09-14 │
    └──────────┴───────────────────────────────────────────────┴─────────────────────────────────────┴────────────┘
    ┌─username─┬─lables.name───────────────────────────────────┬─lables.value─────────────────────────────────┬────────day─┐
    │ 李四 │ ['os_type','version','database_name','owner'] │ ['linux','redhat_7.7','flyingdb','flyingdb'] │ 2022-09-14 │
    └──────────┴───────────────────────────────────────────────┴──────────────────────────────────────────────┴────────────┘
    ┌─username─┬─lables.name───────────────────────────────────┬─lables.value────────────────────────┬────────day─┐
    │ 王五 │ ['os_type','version','database_name','owner'] │ ['linux','Mint_17.3','test','test'] │ 2022-09-14 │
    └──────────┴───────────────────────────────────────────────┴─────────────────────────────────────┴────────────┘
    ┌─username─┬─lables.name───────────────────────────────────┬─lables.value─────────────────────────────────┬────────day─┐
    │ 张三 │ ['os_type','version','database_name','owner'] │ ['linux','redhat_7.6','postgres','postgres'] │ 2022-09-14 │
    └──────────┴───────────────────────────────────────────────┴──────────────────────────────────────────────┴────────────┘
          重复执行上面insert数据,然后select数据,发现数据还是只有4行。
          分析日志,有如下日志记录:
      2022.09.14 17:01:20.725741  [ 163 ] {67719eb7-2f61-41b7-8abb-bcf2e67d6ae8} <Error> executeQuery: Code: 57, e.displayText() = DB::Exception: Table icat.try already exists. (version 20.2.1.2120 (official build)) (from 127.0.0.1:36636) (in query: CREATE TABLE icat.try (`username` String`lables.name` Array(String), `lables.value` Array(String), `day` Date) ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/try''{replica}') PARTITION BY toYYYYMMDD(day) ORDER BY username), Stack trace (when copying this message, always include the lines below):

            可以发现,新插入的数据被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,则会被过滤掉。

            针对这个问题官方有个参数:insert_deduplicate

            对于 Replicated表,启用或禁用INSERT删除重复数据。

            可能的值:

                  0 -禁用。

                  1 -启用(默认值)。

            默认情况下,通过INSERT语句插入到复制表中的块会被重复数据删除(请参阅数据复制)

      https://clickhouse.com/docs/en/engines/table-engines/mergetree-family/replication


            insert_deduplicate参数配置三种方式:

      1.在 users.xml 中的用户配置文件中

      2.SET 命令的会话


      3.在SELECT语句的 SETTINGS 子句中。


            通过设置可以让clickhouse不做此项检查,保证数据每次都能插入成功。有点需要注意的是,真正生效的窗口大小可能不止100,可能更多。因为清理线程的周期是30-40s,如果老的block_id没有及时清理掉,会导致实际的去重窗口值大于replicated_deduplication_window。


      声明
             因小编个人水平有限,专栏中难免存在错漏之处,请勿直接复制文档中的参数、命令或方法应用于线上环境中操作。



      近期文章推荐

      ClickHouse 版本升级
      PostgreSQL 逻辑复制模块(一)
      PostgreSQL 逻辑复制模块(二)
      文章转载自ClickHouse周边,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论