前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >让MergeTree也具备ReplicatedMergeTree的数据去重能力

让MergeTree也具备ReplicatedMergeTree的数据去重能力

作者头像
Nauu
发布2021-08-25 15:36:25
2.9K0
发布2021-08-25 15:36:25
举报

我曾在书中介绍过,ReplicatedMergeTree 支持根据 block_id 防止重复的数据写入。ClickHouse 在写入一个 Block 块的时候,会按照当前 Block 的数据顺序、数据行和数据大小等指标,计算 Hash 并生成 block_id。

如果某个待写入的 Block 块,与先前已被写入的 Block 块,拥有相同的 block_id,则该 Block 数据块会被忽略。

这项特性主要是为了解决,由上游数据写入程序 (如 ETL 程序),因为任务失败、网络等问题引起的 retry 任务,导致数据重复写入的问题。

例如,我们用 Spark 做 ETL 向 ClickHouse 写入数据,由于一些原因 Executor上执行写入 task 的进程被杀掉了,此时 Spark 会再起一个进程重新retry执行刚才的写入 task,这就可能会造成数据的重复写入。

利用 ReplicatedMergeTree 按照 block_id 去重的功能,就可以在一定程度上避免类似问题。

在此之前,这项特性是 ReplicatedMergeTree 系列独有的,如果我们使用非副本的 MergeTree 系列,则享受不到这项功能。而在 ClickHouse 的新版本中,普通的 MergeTree 系列也支持这项功能了,是不是很 Happy 呢?接下来,就快速一览如何使用吧。

使用的方法很简单,在创建 MergeTree 的时候,

增加一项 non_replicated_deduplication_window 参数即可:

代码语言:javascript
复制
CREATE TABLE deduplication_test
(
    id UInt64,
    value String,
    part UInt8 DEFAULT 111
)
ENGINE = MergeTree()
ORDER BY id
PARTITION BY part
SETTINGS non_replicated_deduplication_window=3;

non_replicated_deduplication_window 表示,保存最后多少个 block 的 hash,默认是 0 (不开启)。

现在写入数据:

代码语言:javascript
复制
INSERT INTO deduplication_test (id, value) VALUES (1, '1');

再写入一次重复的数据:

代码语言:javascript
复制
INSERT INTO deduplication_test (id, value) VALUES (1, '1');

你会看到日志中出现如下的信息,该 Block ID 已经存在了, 忽略写入:

代码语言:javascript
复制
<Information> default.deduplication_test: Block with ID 111_5329300851986775609_11764731552300554311 already exists as part 111_1_1_0; ignoring it

查询表数据,重复的数据没有被写入,符合预期:

代码语言:javascript
复制
SELECT
    id,
    value,
    part
FROM deduplication_test

Query id: abb86e7a-ad9d-4403-819d-5b0c46776c09

┌─id─┬─value─┬─part─┐
│  1 │ 1     │  111 │
└────┴───────┴──────┘

1 rows in set. Elapsed: 0.004 sec.

如果我们写入不同的数据,则写入成功:

代码语言:javascript
复制
INSERT INTO deduplication_test (id, value) VALUES (1, '2'),(1, '3');

SELECT id, value,part FROM deduplication_test;
┌─id─┬─value─┬─part─┐
│  1 │ 1     │  111 │
│  1 │ 2     │  111 │
│  1 │ 3     │  111 │
└────┴───────┴──────┘

block_id 是按分区内去重复的,如果是不同分区,则不起作用:

代码语言:javascript
复制
INSERT INTO deduplication_test (id, value, part) VALUES (1, '1', 222);

SELECT id, value,part FROM deduplication_test;
┌─id─┬─value─┬─part─┐
│  1 │ 1     │  111 │
│  1 │ 2     │  111 │
│  1 │ 3     │  111 │
└────┴───────┴──────┘
┌─id─┬─value─┬─part─┐
│  1 │ 1     │  222 │
└────┴───────┴──────┘

功能效果通过上面的示例大家应该能够 get 到了吧?那么按照剧情的安排,接下来各位就会好奇是怎么实现的了吧?

我们都知道,ReplicatedMergeTree 是通过 ZooKeeper 记录了 block_id。那么 MergeTree 不依赖 ZooKeeper,靠什么记录呢?

也许你已经想到了,没错,是靠文件啊。进入到表的磁盘目录,我们会看到多出来了一个 deduplication_logs 文件目录:

代码语言:javascript
复制
total 8
drwxr-xr-x  11 nauu  staff  352  8 14 11:42 111_1_3_1
drwxr-xr-x  11 nauu  staff  352  8 14 11:44 222_4_4_0
drwxr-xr-x   3 nauu  staff   96  8 14 11:28 deduplication_logs
drwxr-xr-x   2 nauu  staff   64  8 14 11:28 detached
-rw-r-----   1 nauu  staff    1  8 14 11:28 format_version.txt

进入目录,会发现 log 日志:

代码语言:javascript
复制
deduplication_log_1.txt

日志按行记录了分区名称和 block_id ,作为后续去重的判断依据:

代码语言:javascript
复制
cat deduplication_log_1.txt 
1  111_1_1_0  111_5329300851986775609_11764731552300554311
1  111_3_3_0  111_16165894563003502484_10602898938383473825
1  222_4_4_0  222_15423518775339082225_1451687862585147197
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2021-08-16,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 ClickHouse的秘密基地 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档