Clickhouse分区与副本

一、表分区(Partition)概念

表中的数据可以按照指定的字段分区存储,每个分区在文件系统中都是都以目录的形式存在。常用时间字段作为分区字段,数据量大的表可以按照小时分区,数据量小的表可以在按照天分区或者月分区,查询时,使用分区字段作为Where条件,可以有效的过滤掉大量非结果集数据。

ClickHouse 分区的目的是为了尽可能地减少读取的数据量,那么它有哪些特点呢?

  • 创建分区的方法比较简单,只需要在建表时通过partition by语法指定即可;
  • 不止可以按某个字段做partition by,还可以支持按任意合法的表达式进行分区操作,比如toYYYYMM()按月做分区;
  • 支持对partition进行TTL管理,淘汰过期的分区数据;
  • 插入数据到分区表中时,先会将数据写入到分区目录下的segment文件中,后台程序会自动进行合并,当然也可以通过optimize命令手动触发合并。

在ClickHouse中有专门一张表对partition进行管理,那就是system.parts。

select database,table,partition,name,path,engine from system.parts WHERE table = ‘ontime’;

img

常见的一些字段说明:

  • database:数据库名称
  • table:表名
  • partition:分区键
  • name:分区名称
  • path:分区对应的目录
  • disk_name:分区所在的磁盘
  • engine:该数据表的引擎

二、分片(Shard)概念

一个分片本身就是ClickHouse一个实例节点,分片的本质就是为了提高查询效率,将一份全量的数据分成多份(片),从而降低单节点的数据扫描数量,提高查询性能。

img

上图中,除了分片(Shard)之外,还同时引入了副本(Replica)概念。

副本(Replica)简单理解就是相同的数据备份,在ClickHouse中通过复制集,我们实现了保障数据可靠性外,也通过多副本的方式,增加了ClickHouse查询的并发能力。这里一般有2种方式:1.基于ZooKeeper的表复制方式;2.基于Cluster的复制方式。由于我们推荐的数据写入方式本地表写入,禁止分布式表写入,所以我们的复制表只考虑ZooKeeper的表复制方案。

在集群配置中,Shard标签里面配置的replica互为副本,将internal_replication设置成true,此时写入同一个Shard内的任意一个节点的本地表,ZooKeeper会自动异步的将数据同步到互为副本的另一个节点。

img

三. 分区目录合并过程

如图:

img


向表中插入新数据时,此数据存储为按主键排序的单独部分(块)。插入后10-15分钟,同一分区的部分合并为整个部分。

🍉 !!!合并仅适用于分区表达式具有相同值的数据部分。这意味着不应该制作过于精细的分区(超过大约一千个分区)。否则,SELECT由于文件系统中的文件数量过多以及打开的文件描述符,查询性能会很差。

使用system.parts表查看表部分和分区。例如,假设我们有一个visits按月分区的表。让我们对表执行SELECT查询system.parts

1
2
3
4
5
6
SELECT
  partition,
  name,
  active
FROM system.parts
WHERE table = 'visits' and database ='test';
1
2
3
4
5
6
7
8
9
┌─partition─┬─name──────────────┬─active─┐
│ 202201   │ 202201_1_3_1     │      0 │
│ 202201   │ 202201_1_9_2_11   │      1 │
│ 202201   │ 202201_8_8_0     │      0 │
│ 202201   │ 202201_9_9_0     │      0 │
│ 202202   │ 202202_4_6_1_11   │      1 │
│ 202202   │ 202202_10_10_0_11 │      1 │
│ 202202   │ 202202_11_11_0_11 │      1 │
└───────────┴───────────────────┴────────┘

active列显示部件的状态。1活跃; 0处于非活动状态。例如,非活动部分是合并到较大部分后剩余的源部分。损坏的数据部分也被指示为非活动的。

同一分区有多个独立的部分(例如,202201_1_3_1202201_1_9_2)。这意味着这些部分尚未合并。ClickHouse 会定期合并插入的部分数据,大约在插入后 15 分钟。此外,可以使用OPTIMIZE查询执行非计划合并。

合并后大约 10 分钟将删除不活动的部分。

分区合并

  1. 首先只有当插入数据的时候才会创建新的分区。
  2. 创建的分区也不是一成不变的,会在一定时间之后做自动合并(写入的 10-15 分钟)。
  3. 每一次 Insert 都会生成新的分区数据。这个不像其他数据库,会自动 insert 到相同的分区。也就是说,对于相同分区,也会生成不同的分区目录。
  4. 合并分区之后的旧分区不会立即删除。旧的分区会被设置 active=0 ,查询的时候会过滤掉这些分区记录,并会在一定时间之后自动删除(默认 8 分钟)。

image.png

分区设计

分区选择考虑merge (写入放大)、查询(slelect part数量)、启动等方面考虑。在实际生产中选择时间作为分区键,根据表数据的大小按天或者按周进行了分区。

如图

img

四、分区优化

1)分区粒度根据业务特点决定,不宜过粗或过细。一般选择按天分区,也可以指定为Tuple(),以单表一亿数据为例,分区大小控制在10-30个为最佳。
2)那些有相同分区表达式值的数据片段才会合并。这意味着 你不应该用太精细的分区方案(超过一千个分区)。否则,会因为文件系统中的文件数量过多和需要打开的文件描述符过多,导致 SELECT 查询效率不佳。
3)还有就是一般我们都是使用的是日期作为分区键,同一分区内有序,不同分区不能保证有序。

资料来源:(clickhouse分区设计操作以及优化 - 渐逝的星光 - 博客园 (cnblogs.com))