Clickhouse-高级

Clickhouse使用场景

列式存储、数据压缩、向量化执行、支 持标准 SQL、支持 20 多张表引擎、支持多线程与分布式、多主架构、交互式查询、数据分 片与分布式查询等

ClickHouse 适合 OLAP 数据分析类的场景,数据体量越大,ClickHouse 的优势越 大。ClickHouse 不适合以下场景: 1) ClickHouse 不支持事务,事务场景不适合 2) 不适合根据主键进行行粒度查询或删除场景(支持但不建议)

ClickHouse集群安装

1)这里选择 node1、node2,node3 三台节点,上传安装包,分别在每台节点上执行如 下命令安装 ClickHouse:

rpm -ivh ./ClickHouse-common-static-21.9.4.35-2.x86_64.rpm
#注意在安装以下 rpm 包时,让输入密码,可以直接回车跳过
rpm -ivh ./ClickHouse-server-21.9.4.35-2.noarch.rpm
rpm -ivh ClickHouse-client-21.9.4.35-2.noarch.rpm

2)安装zookeeper集群并启动

搭建 ClickHouse 集群时,需要使用 Zookeeper 去实现集群副本之间的同步,所以 这里需要 zookeeper 集群,zookeeper 集群安装后可忽略此步骤

3)配置外网可以访问

在每台 ClickHouse 节点中配置/etc/ClickHouse-server/config.xml 文件第 164 行,如下:

::1
#注意每台节点监听的 host 名称配置当前节点 host
node1

4) 在每台节点创建 metrika.xml 文件,写入以下内容

在 node1、node2、node3 节点上/etc/ClickHouse-server/config.d 路径下 下配置 metrika.xml 文件,默认 ClickHouse 会在/etc 路径下查找 metrika.xml 文件,但是必须要求 metrika.xml 上级目录拥有者权限为 ClickHouse ,所以这里我们将 metrika.xml 创建在/etc/ClickHouse-server/config.d 路径下,config.d 目录 的拥有者权限为 ClickHouse。

在 metrika.xml 中我们配置后期使用的 ClickHouse 集群中创建分布式表时使用 3 个分片,每个分片有 1 个副本,配置如下:

vim /etc/ClickHouse-server/config.d/metrika.xml:





true

node1
9000



true

node2
9000



true

node3
9000






node3
2181


node4
2181


node5
2181



01
node1


::/0



10000000000
0.01
lz4



配置文件字段解释

 remote_servers: ClickHouse 集群配置标签,固定写法。注意:这里与之前版本不同,之前要求必须 以 ClickHouse 开头,新版本不再需要。

ClickHouse_cluster_3shards_1replicas: 配置 ClickHouse 的集群名称,可自由定义名称,注意集群名称中不能包含点号。这 里代表集群中有 3 个分片,每个分片有 1 个副本。 分片是指包含部分数据的服务器,要读取所有的数据,必须访问所有的分片。 副本是指存储分片备份数据的服务器,要读取所有的数据,访问任意副本上的数据即可。

shard:

分片,一个 ClickHouse 集群可以分多个分片,每个分片可以存储数据,这里分片可以理解为 ClickHouse 机器中的每个节点,1 个分片只能对应 1 服务节点。这里可以配置 一个或者任意多个分片,在每个分片中可以配置一个或任意多个副本,不同分片可配置不同 数量的副本。如果只是配置一个分片,这种情况下查询操作应该称为远程查询,而不是分布 式查询。

replica:

每个分片的副本,默认每个分片配置了一个副本。也可以配置多个,副本的数量上限是 由 ClickHouse 节点的数量决定的。如果配置了副本,读取操作可以从每个分片里选择一 个可用的副本。如果副本不可用,会依次选择下个副本进行连接。该机制利于系统的可用性。

internal_replication:

默认为 false,写数据操作会将数据写入所有的副本,设置为 true,写操作只会选择 一个正常的副本写入数据,数据的同步在后台自动进行。

zookeeper:

配 置 的 zookeeper 集 群 , 注 意 : 与 之 前 版 本 不 同 , 之 前 版 本 是 “zookeeper-servers”。

macros:

区分每台 ClickHouse 节点的宏配置,macros 中标签代表当前节点的分片 号,标签代表当前节点的副本号,这两个名称可以随意取,后期在创建副本表 时可以动态读取这两个宏变量。注意:每台 ClickHouse 节点需要配置不同名称。

networks:

这里配置 ip 为“::/0”代表任意 IP 可以访问,包含 IPv4 和 IPv6。 注意:允许外网访问还需配置/etc/ClickHouse-server/config.xml 参照第三 步骤。

ClickHouse_compression:

MergeTree 引擎表的数据压缩设置,min_part_size:代表数据部分最小大小:min_part_size_ratio:数据部分大小与表大小的比率。method:数据压缩格式。

注意:需要在每台 ClickHouse 节点上配置 metrika.xml 文件,并且修改每个节点 的 macros 配置名称

#node2 节点修改 metrika.xml 中的宏变量如下:

        02

        node2

#node3节点修改metrika.xml中的宏变量

        03

        node3

在每台节点上启动、查看、停止Clickhouse服务

首先启动 zookeeper 集群,然后分别在 node1、node2、node3 节点上启动 ClickHouse 服务,这里每台节点和单节点启动一样。启动之后,ClickHouse 集群配置 完成。

每台节点启动clickhouse服务

service clickhouse-server start

每台节点查看clickhouse服务状态

service clickhouse-server status

每台机器上重启clickhouse服务

service clickhouse-server restart

关闭每台机器上的clickhouse服务

service clickhouse-server stop

检查集群配置是否完成

在NODE1,NODE2,NODE3任意的一台节点进入clickhouse客户端,查询集群配置

#选择三台clickhouse任意一台节点,进入客户端

clickhouse-client

select * from system.clusters;

Clickhouse-高级_第1张图片

 Clickhouse目录结构

clickhouse集群安装完成之后会生成对应的目录,每个目录的介绍如下:

/etc/clickhouse-server

服务端的配置文件目录,包括全局配置config.xml和用户配置users.xml

/var/lib/clickhouse

默认的数据存储目录,通常会修改,将数据保存到大容量磁盘路径中,此路径可以通过 /etc/ClickHouse-server/config.xml 配置,配置标签对应的数据

在/usr/bin 下会有可执行文件: 1) ClickHouse:主程序可执行文件 2) ClickHouse-server:一个指向 ClickHouse 可执行文件的软连接,供服务端 启动使用。 3) ClickHouse-client:一个指向 ClickHouse 可执行文件的软连接,供客户端 启动使用。

ClickhouseMergeTree表引擎

在所有的表引擎中,最为核心的当属 MergeTree 系列表引擎,这些表引擎拥有最为强 大的性能和最广泛的使用场合。对于非 MergeTree 系列的其他引擎而言,主要用于特殊用 途,场景相对有限。而 MergeTree 系列表引擎是官方主推的存储引擎,有主键索引、数据 分区、数据副本、数据采样、删除和修改等功能,支持几乎所有 ClickHouse 核心功能。

MergeTree 系 列 表 引 擎 包 含 : MergeTree 、 ReplacingMergeTree 、 SummingMergeTree(汇总求和功能)、AggregatingMergeTree(聚合功能)、 CollapsingMergeTree(折叠删除功能)、VersionedCollapsingMergeTree(版 本折叠功能)引擎,在这些的基础上还可以叠加 Replicated 和 Distributed。

MergeTree 在写入一批数据时,数据总会以数据片段的形式写入磁盘,且数据片段在 磁盘上不可修改。为了避免片段过多,ClickHouse 会通过后台线程,定期合并这些数据 片段,属于相同分区的数据片段会被合成一个新的片段。这种数据片段往复合并的特点,也 正是合并树名称的由来。

MergeTree 作为家族系列最基础的表引擎:

 存储的数据按照主键排序:创建稀疏索引加快数据查询速度。

 支持数据分区,可以通过 PARTITION BY 语句指定分区字段。

 支持数据副本。

 支持数据采样。

 MergeTree 建表语句:

CREATE TABLE [IF NOT EXISTS] [db.]table_name [ON CLUSTER cluster]
(
name1 [type1] [DEFAULT|MATERIALIZED|ALIAS expr1] [TTL expr1],
name2 [type2] [DEFAULT|MATERIALIZED|ALIAS expr2] [TTL expr2],
...
INDEX index_name1 expr1 TYPE type1(...) GRANULARITY value1,
INDEX index_name2 expr2 TYPE type2(...) GRANULARITY value2
) ENGINE = MergeTree()
ORDER BY expr
[PARTITION BY expr]
[PRIMARY KEY expr]
[SAMPLE BY expr]
[TTL expr [DELETE|TO DISK 'xxx'|TO VOLUME 'xxx'], ...]
[SETTINGS name=value, ...]

 ENGINE:ENGINE = MergeTree(),MergeTree 引擎没有参数。

 ORDER BY:排序字段。比如 ORDER BY (Col1, Col2),值得注意的是,如果 没有使用 PRIMARY KEY 显式的指定主键 ORDER BY 排序字段自动作为主键。如 果不需要排序,则可以使用 ORDER BY tuple() 语法,这样的话,创建的表也 就不包含主键。这种情况下,ClickHouse 会按照插入的顺序存储数据。必选项。

 PARTITION BY : 分 区 字 段 , 例 如 要 按 月 分 区 , 可 以 使 用 表 达 式 toYYYYMM(date_column),这里的 date_column 是一个 Date 类型的列,分 区名的格式会是"YYYYMM"。可选。

 PRIMARY KEY:指定主键,如果排序字段与主键不一致,可以单独指定主键字段。 否则默认主键是排序字段。大部分情况下不需要再专门指定一个 PRIMARY KEY 子句,注意,在 MergeTree 中主键并不用于去重,而是用于索引,加快查询速度。 可选。 另外,如果指定了 PRIMARY KEY 与排序字段不一致,要保证 PRIMARY KEY 指 定的主键是 ORDER BY 指定字段的前缀,比如:允许这样设置:

ORDER BY (A,B,C) PRIMARY KEY A

不允许这样设置:

ORDER BY (A,B,C) PRIMARY KEY B

这种强制约束保障了即便在两者定义不同的情况下,主键仍然是排序键的前缀,不 会出现索引与数据顺序混乱的问题。

SAMPLE BY:采样字段,如果指定了该字段,那么主键中也必须包含该字段。比 如 SAMPLE BY intHash32(UserID) ORDER BY (CounterID, EventDate, intHash32(UserID))。可选。

TTL:数据的存活时间。在 MergeTree 中,可以为某个列字段或整张表设置 TTL。 当时间到达时,如果是列字段级别的 TTL,则会删除这一列的数据;如果是表级别 的 TTL,则会删除整张表的数据。可选。

SETTINGS:额外的参数配置。可选。

MergeTree引擎表目录解析

MergeTree 引擎表对应到磁盘的数据目录,Clikchouse 新版本与 之前版本对比,数据对应的磁盘目录略有不同。

CREATE TABLE t_mt ( `id` UInt8, `name` String, `age` UInt8, `birthday` Date, `location` String ) ENGINE = MergeTree PARTITION BY toYYYYMM(birthday) ORDER BY (id, age)

Clickhouse-高级_第2张图片

查看分区信息

select table,partition,name,active from system.parts where table= 't_mt'

进入到某一个分区目录片段“202102_2_2_0”中,我们可以看到如下目录:

Clickhouse-高级_第3张图片

checksums.txt:校验文件,使用二进制格式存储。它保存了余下各类文件(primary.idx、count.txt 等)的 size 大小及 size 的哈希值,用于快速校验文件的完整性和 正确性。

columns.txt: 存储当前分区所有列信息。使用明文格式存储。它保存了余下各类文件(primary.idx、count.txt 等)的 size 大小及 size 的哈希值,用于快速校验文件的完整性和 正确性。

columns.txt: 存储当前分区所有列信息。使用明文格式存储。

count.txt:计数文件,使用明文格式存储。用于记录当前数据分区目录下数据的总 行数。

data.bin:数据文件,使用压缩格式存储,默认为 LZ4 压缩格式,用于存储某一列 的数据。之前 clickhoue 版本是每一个列字段都拥有独立的.bin 数据文件,并以列 字段名称命名,在新版本 ClickHouse 中所有数据合并到 data.bin 中。 之前 ClickHouse 版本此目录数据如下:

 data.mrk3:列字段标记文件,使用二进制格式存储。标记文件中保存了 data.bin文件中数据的偏移量信息

default_compression_codec.txt:存储数据压缩格式

partition.dat 与 minmax_[Column].idx:如果指定了分区键,则会额外生成 partition.dat 与 minmax 索 引 文 件 , 它 们 均 使 用 二 进 制 格 式 存 储 。 partition.dat 用于保存当前分区下分区表达式最终生成的值,即分区字段值;而 minmax 索引用于记录当前分区下分区字段对应原始数据的最小和最大值。比如当使用 birthday 字段对应的原始数据为 2021-02-17、2021-02-23,分区表达式为 PARTITION BY toYYYYMM(birthday),即按月分区。partition.dat 中保存的 值将会是 202102,而 minmax 索引中保存的值将会是 2021-02-17、2021-02-23

ClickHouse MergeTree 引擎表支持分区,索引,修改,并发查询数据,当查询 MergeTree 表数据时,首先向 primary.idx 文件中获取对应的索引,根据索引找到 【data.mrk3】文件获取对应的数据块偏移量,然后再根据偏移量从【data.bin】文件 中读取块数据。

primary.idx:一级索引文件,使用二进制格式存储。用于存放稀疏索引,一张 MergeTree 表只能声明一次一级索引,即通过 ORDER BY 或者 PRIMARY KEY 指定字 段。借助稀疏索引,在数据查询的时能够排除主键条件范围之外的数据文件,从而有效 减少数据扫描范围,加速查询速度。

ClickHouse索引

一级索引

在 MergeTree 中 PRIMARY KEY 主键并不用于去重,而是用于索引,加快查询速 度,MergeTree 会根据 index_granularity 间隔(默认 8192 行),为数据表生成一级 索引并保存至 primary.idx 文件内,索引数据按照 PRIMARY KEY 排序,相对于使用 PRIMARY KEY 更常见的方式是通过 ORDER BY 方式指定主键。

稀疏索引

primary.idx 文件内的一级索引采用稀疏索引实现。有稀疏索引就有稠密索引,二者 区别如下

Clickhouse-高级_第4张图片

在稠密索引中每一行索引标记都会对应到一行具体的数据记录。而在稀疏索引中每一行 索引标记对应的是一段数据,而不是一行。 稀疏索引的优势显而易见,仅需要使用少量的索引标记就能够记录大量的数据区间位置 信息,而且数据量越大优势越明显。在 MergeTree 系列引擎表中对应的 primary.idx 文件就是稀疏索引,由于稀疏索引占用空间小,所以 primary.idx 内的索引数据常驻内 存。

索引粒度

在 ClickHouse MergeTree 引 擎 中 默 认 的 索 引 粒 度 是 8192 , 参 数 为 index_granularity,一般我们不会修改此值,按照默认 8192 即可。我们可以通过以 下 sql 语句查看每个 MergeTree 引擎表对应的 index_granulariry 的值:

 show create table t_mt;

索引粒度对于 MergeTree 表引擎非常重要,可以根据整个数据的长度,按照索引粒度 对数据进行标注,然后抽取对应的数据形成索引。

索引形成过程

表数据以 index_granularity 的粒度(默认 8192)被标记成多个小区间,其中每 个区间最多 8192 行数据,每个区间标记后形成一个 MarkRange,通过 start 和 end 表示 MarkRange 的具体范围,数据文件也会按照 index_granularity 的间隔粒度生成压缩 数据块。由于是稀疏索引,MergeTree 需要间隔 index_granularity 行数据生成一条 索引,同时对应一个索引编号,每个 MarRange 与一个索引编号对应,通过与 start 及 end 对应的索引编号的取值,可以得到对应的数值区间;索引编号对应的索引值会依据声明 的主键字段获取,最终索引编号和索引值被写入 primary.idx 文件中保存。

假设现在有一份测试数据,共 192 行记录,其中主键 ID 为 String 类型,ID 值从 A000 开始,后面依次为 A001、A002...直到 A192 为止,假设我们设置 MergeTree 的索引粒 度 index_granularity=3,根据索引的生成规则,primary.idx 文件内的索引数据如 下:

根据索引数据,MergeTree 将此数据片段划分成 192/3=64 个小的 MarkRange,其中所有 MarkRange 的最大数值区间为[A000,+inf),划分的 MarkRange 如下:

Clickhouse-高级_第5张图片

 索引查询过程 使用索引查询其实就是两个数值区间的交集判断,其中一个区间是有基于主键的查询条 件转换而来的条件区间,而另一个区间是上图中 MarkRange 对应的数值区间。 整个索引查询的过程大致分为 3 个步骤:

生成查询条件区间

查询时首先将查询条件转换为条件区间,即便是单个值的查询条件也会转换成区间的形 式,例如: 

WHERE ID='A003' ['A003','A003'] WHERE ID>'A000' ['A000',+inf] WHERE ID<'A188' (-inf,'A188'] WHERE ID like 'A006%' ('A006','A007']

递归交集判断

以递归的方式依次对 MarkRange 的数值区间与条件区间做交集判断,从最大的区间 [A000,+inf)开:

如果不存在交集,则直接忽略掉整段 MarkRange

如果存在交集,且 MarkRange 步长大于 8(end-start),则将此区间进一步拆分 成 8 个区间(由 merge_tree_coarse_index_granularity 指定,默认值为8),并重复此规则,继续做递归交集判断

如果存在交集,且MarkRange不可再分解(步长小于8),则记录MarkRange并返回

合并MarkRange区间

将最终匹配的 MarkRange 聚在一起,合并他们的范围。 当查询条件 WHERE ID ='A003'的时候,最终读取[A000,A003)和[A003,A006] 两个区间的数据即可,他们对应的 MarkRange(start:0,end:2)范围,而无其他无用的 区间都被裁剪过滤掉,因为 MarkRange 转换的数值区间是闭区间,所以会额外匹配到临近 的一个区间,完整的逻辑图如下图所示:

Clickhouse-高级_第6张图片

 二级索引(跳数索引)

除了一级索引之外,MergeTree 同样支持二级索引,二级索引又称为跳数索引,由数 据的聚合信息构建而成,根据索引类型的不同,其聚合信息的内容也不同,跳数索引的目的 与一级索引一样,也是帮助查询时减少数据扫描的范围。 跳数索引需要在 Create 语句内定义,完整语法如下:

INDEX index_name expr TYPE index_type(...) GRANULARITY granularity

对以上参数的解释如下:

index_name:定义的二级索引名称  index_type:跳数索引类型,最常用就是 minmax 索引类型。minmax 索引记录了一段数据内的最小和最大极值,其索引的作用类似分区目录,能够快速跳过无用的数据区 间。

 granularity:定义聚合信息汇总的粒度。

与 一 级 索 引 一 样 , 如 果 在 建 表 语 句 中 声 明 了 跳 数 索 引 , 则 会 在 路 径 “/var/lib/ClickHouse/data/DATABASE/TABLE/PARTITION/”目录下生成索引与 标记文件(skp_idx.idx 与 skp_idx.mrk)。 在接触跳数索引时,很容易将 index_granularity 与 granularity 概念混淆,对 于跳数索引而言,index_granularity 定义了数据的粒度,而 granularity 定义了聚 合信息汇总的粒度,也就是说,granularity 定义了一行跳数索引能够跳过多少个 index_granularity 区间的数据。

minmax 跳数索引的生成规则

minmax 跳数索引聚合信息是在一个 index_granularity 区间内数据的最小和最大 极值。首先,数据按照 index_granularity 粒度间隔将数据划分成 n 段,总共有[0~n-1] 个区间(n=total_rows/index_granularity,向上取整),接着根据跳数索引从 0 区间开始,依次按 index_granularity 粒度从数据中获取聚合信息,每次向前移动 1 步, 聚合信息逐步累加,最后当移动 granularity 次区间时,则汇总并生成一行跳数索引数 据。 以下图为例:假设 index_granularity=8192 且 granularity=3,则数据会按照 index_granularity 划分成 n 等份,MergeTree 从第 0 段分区开始,依次获取聚合信 息,当获取到第 3 个分区时(granularity=3),则汇总并生成第一行 minmax 索引(前 3 段 minmax 极值汇总后取值为[1,9])。

Clickhouse-高级_第7张图片

minmax 跳数索引案例:

#删除表 t_mt node1 :) drop table t_mt; #重新创建 t_mt 表,包含二级索引 node1 :)CREATE TABLE t_mt ( id UInt8, name String, age UInt8, birthday Date, location String, INDEX a id TYPE minmax GRANULARITY 5 ) ENGINE = MergeTree PARTITION BY toYYYYMM(birthday) ORDER BY (id, age) PRIMARY KEY id

#插入数据 insert into t_mt values (1,' 张 三 ',18,'2021-06-01',' 上 海 '), (2,' 李 四 ',19,'2021-02-10',' 北 京 '), (3,' 王 五 ',12,'2021-06-01',' 天 津 '), (1,' 马 六 ',10,'2021-06-18','上海'), (5,'田七',22,'2021-02-09','广州'); #查看数据分区路径

TTL

TTL 即 Time To Live ,表示数据存活的时间。在 MergeTree 中,可以为某个列字 段或整张表设置 TTL。当时间到达时,如果是列字段级别的 TTL,则会删除这列的数据; 如果是表级别的 TTL,则会删除整张表的数据;如果同时设置了列级别和表级别的 TTL, 则会以先到期的那个为主。 无论是列级别还是表级别的 TTL,都需要依托某个 DataTime 或 Date 类型的字段, 通过对这个时间字段的 INTERVAL 操作,来描述 TTL 的过期时间,例如:

TTL time_col + INTERVAL 3 DAY

上述语句表示数据的存活时间是 time_col 时间的 3 天之后。

TTL time_col + INTERVAL 1 MONTH

上述语句表示数据的存活时间是 time_col 时间的 1 个月之后。

INTERVAL 完整的操作包括:SECOND、MINUTE、HOUR、DAY、WEEK、MONTH、QUARTER、 YEAR。

列级别TTL

如果想要设置列级别的 TTL,在声明表字段的时候,为他们声明 TTL 表达式,主键字 段不能被声明 TTL,举例如下:

#创建表 t_mt2,指定 gender 存活时间

create table t_mt2(id UInt8,name String,age UInt8,gender String TTL create_time+INTERVAL 10 SECOND,create_time DateTime) engine=MergeTree order by id;

注意:以上 gender 字段的存活时间为 create_time 取值基础上向后延续 10 秒,此 ttl 实现借助 create_time 时间字段。

向表t_mt2中插入如下数据

insert into t_m2 values(1,'zs',18,'f',now());

#重启 ClickHouse 后,执行如下语句查看对应表中的数据

optimize table t_mt2 final

select * from t_mt2

alter table t_mt2 modify column age UInt8 ttl create_time+interval 5 second;

表级别的TTL

表级别的TTL

在 ClickHouse 中我们还可以对整张表设置 TTL,需要在建表时在表参数中指定 TTL 表达式,当 TTL 触发时,满足过期时间的数据行将被整行删除

#创建表 t_mt3,表级别指定 TTL ,数据 10s 过期

CREATE TABLE t_mt3( id UInt8, name String, age UInt8 , gender String, create_time DateTime )engine=MergeTree order by id TTL create_time+INTERVAL 10 SECOND;

#向表 t_mt3 中插入如下数据 node1 :) insert into t_mt3 values (1,'zs',18,'f',now()); #经过 10s,执行 optimize table t_mt3 final,再次查看表中数据被删除清空 node1 :) optimize table t_mt3 final;

对表级别 TTL 进行修改:

ALTER TABLE tbl MODIFY TTL create_time +INTERVAL 3 DAY

#修改表 t_mt3 数据过期时间为 1 分钟

node1 :) alter table t_mt3 modify ttl create_time + interval 1 minute;

#查看 t_mt3 表的 TTL

node1 :) show create table t_mt3;

#经过 1 分钟 执行 optimize table t_mt3 final,数据被清空

node1 :) optimize table t_mt3 final;

注意:无论是列级别 TTL,还是表级别 TTL,一旦设置后,目前没有取消的方法。

副本与分片

ClickHouse 数据存储时支持副本和分片,副本指的就是一份数据可以在不同的节点 上存储,这些节点上存储的每份数据相同,数据副本是增加数据存储冗余来防止数据丢失。 分片指的是 ClickHouse 一张表的数据可以横向切分为多份,每份中的数据不相同且存储 在不同的节点上,分片的目的主要是实现数据的水平切分,方便多线程和分布式查询数据。 这里以由 3 台 ClickHouse 节点组成的 ClickHouse 集群对应的几张图来描述 ClickHouse 中的副本与分片,方便大家理解:

 表 temp 只有一个分片,1 个副本(数据本身可看成 1 个副本)

Clickhouse-高级_第8张图片

  表 temp 只有一个分片,每个分片有 1 个副本

Clickhouse-高级_第9张图片

 表 temp 有 2 个分片,每个分片有 1 个副本

Clickhouse-高级_第10张图片

 数据副本

存储在 ClickHouse 中的数据想要有副本,创建表时需要在对应的表引擎前面加上 “Replicated”前缀组成一种新的变种引擎,并且目前只有 MergeTree 系列表引擎才支 持副本,如下图所示:

Clickhouse-高级_第11张图片

下面我们以 ReplicatedMergeTree 引擎来举例讲解 ClickHouse 中的数据副本。 创建副本表语法:

 Engine = ReplicatedMergeTree('zk_path','replica_name')

 在上述创建语法中,有 zk_path 和 replica_name 两项配置,代表意思如下:

zk_path:在 zookeeper 中创建的数据表的路径,路径名称可以自定义,用户可以自己定义成希 望 的 任 何 路 径 。 ClickHouse 提 供 了 一 些 约 定 俗 成 的 配 置 模 板 : /ClickHouse/tables/{shard}/table_name ,其中“/ClickHouse/tables”是 约定俗成的路径固定前缀,表示存放数据表的根路径;“{shard}”表示分片编号,通常 使用数值代替,例如:01,02,03,一张数据表可以有多个分片,而每个分片都拥有自己的 副本;“table_name”表示数据表的名称,通常与物理表的名字相同。

replica_name: 定义在 zookeeper 中创建的副本名称,该名称是区分不同副本实例的唯一标识,一种 约定俗成的命名方式是使用所在服务器的域名称。 创建副本表举例,我们在 node1 节点进入 ClickHouse,执行如下建表语句

Create table person_info( id UInt32, name String, age UInt32, gender String, loc String ) engine = ReplicatedMergeTree('/ClickHouse/tables/01/person_info','node1') partition by loc order by id;

在 node2 节点进入 ClickHouse,执行如下建表语句:

Create table person_info( id UInt32, name String, age UInt32, gender String, loc String ) engine = ReplicatedMergeTree('/ClickHouse/tables/01/person_info','node2') partition by loc order by id;

以 上 两 张 表 创 建 完 成 之 后 , 在 zookeeper 中 会 看 到 创 建 “/ClickHouse/tables/01/person_info”路径,对此路径下的部分重要目录解释如 下:

/metadata: 保存元数据信息,包括主键、分区键、采样表达式。

Clickhouse-高级_第12张图片

 /columns:保存列字段信息,包括列名称和数据类型。

Clickhouse-高级_第13张图片

 /replicas:保存副本名称,对应设置参数中的 replica_name。

 /leader_election:用于主副本的选举工作,主副本主要负责 merge、Alter delte 、alter update 操作。

insert into person_info values (1,'zs',18,'m','beijing'),(2,'ls',19,'f','shanghai'),(3,'ww',20,'m','beijing '),(4,'ml',21,'m','shanghai')

插入数据之后,我们在 node1 上进行查询:

Clickhouse-高级_第14张图片

由于有副本作用,在 node2 节点上我们同样也可以查询到表 person_info 中的数据:

Clickhouse-高级_第15张图片

 以上在 node1 节点或者 node2 节点上表“person_info”中插入数据时,都会通过 zookeeper 的 监 听 , 立 即 同 步 到 另 外 节 点 , 可 以 在 node1,node2 节 点 “/var/lib/ClickHouse/data/default/person_info”路径下发现相同的一份数据。

数据分片

通过数据副本我们可以降低数据丢失的风险,到现在为止每个副本上都有表全量数据, 当业务量十分庞大的场景下,依靠副本并不能解决单表的新能瓶颈,我们可以对一张表水平 分为多个分片,这些分片分别存储在不同的 ClickHouse 集群节点中。例如一个 ClickHouse 集群有 3 台节点,我们在创建表 temp 时可以分成 3 个分片,这 3 个分片内 的数据不相同,分别存储在不同的 ClickHouse 节点上,当然为了保证数据的高可用也可 以给每个分片设置副本。

特 别注 意: 在 ClickHouse 中 ,每 个节 点只 能配 置 在一 个 标 签下 的 中,不能与其他的标签下的节点名称相同。例如:配置一 个 ClickHouse 集群拥有 3 个分片,且每个分片有 2 个副本,那么 metrika.xml 配置文 件配置如下:




true

node1
9000


node2
9000



true

node3
9000


node4
9000



true

node5
9000


node6
9000




以上完成配置拥有 3 个分片,2 个副本的 ClickHouse 集群需要 6 台节点

创建分布式表

CREATE/DROP/RENAME/ALTER TABLE xxx ON CLUSTER cluste_name

其中以上“xxx”代表创建的表名称,“cluster_name”对应前面集群配置文件 metrika.xml 中的集群名称,根据配置文件,ClickHouse 会根据集群的配置信息,找 到每个节点执行 DDL 语句,“xxx”表也会在各个节点上被创建。 创建具有 3 分片和 1 副本的表“person_score”,建表语句如下:

创建具有 3 分片和 1 副本的表“person_score”,建表语句如下:

Create table person_score on cluster ClickHouse_cluster_3shards_1replicas ( id UInt32, name String,age UInt32, gender String, score Decimal(9,2) )engine = ReplicatedMergeTree('/ClickHouse/tables/{shard}/person_score','{replica}') order by id;

以 上 “ ClickHouse_cluster_3shards_1replicas ” 是 在 “ /etc/ClickHouse-server/config.d/metrika.xml ” 配 置 文 件 中 配 置 的 ClickHouse 集群的名称  {shard}与{replica}两个变量是在 metrika.xml 中宏变量标签中配置 的对应值,这样当在 ClickHouse 集群中的某台节点执行以上建表语句时, ClickHouse 会自动在各个节点创建此表,这里每台 ClickHouse 节点上的表 person_socre 是本地表。 可以在 zookeeper 中找到查看对应的分片信息:

向表person_score中插入数据,在哪台ClickHouse节点向本地表person_score 中插入数据,那么数据就存入当前本地表对应的分片中。

insert into person_score values (1,'zs',18,'m',100),(2,'ls',19,'f',200);

insert into person_score values (3,'ww',20,'m',300),(4,'ml',21,'m',400);

insert into person_score values (5,'ml',22,'f',500),(6,'tq',23,'f',600);

以上我们创建的 person_score 表在 ClickHouse 集群节点 node1、node2、node3 上都是本地表,插入数据时插入到了对应节点的分片上,查询时也只能查询对应节点上的分 片数据,如果我们想要通过一张表将各个 ClickHouse 节点上的 person_score 表进行 查询,这时就需要使用 Distribute 表引擎,所以在实际工作中 ClickHouse 的数据分片 需要结合 Distriubute 表引擎一同使用。

Distributed引擎

Distributed 引擎和 Merge 引擎类似,本身不存放数据,功能是在不同的 server 上把多张相同结构的物理表合并为一张逻辑表。

Distributed 分布式引擎语法:

Distributed(cluster_name, database_name, table_name[, sharding_key])

对以上语法解释:

 cluster_name:集群名称,与集群配置文件 metrika.xml 中的自定义名称相 对应。

 database_name:数据库名称。

 table_name:表名称。

 sharding_key:可选的,用于分片的 key 值,在数据写入的过程中,分布式表 会依据分片 key 的规则,将数据分布到各个节点的本地表。

注意:创建分布式表是读时检查的机制,也就是说对创建分布式表和本地表的顺序并没 有强制要求。 我们在 ClickHouse 集群中各个节点上创建好了本地表 person_socre,每个节点上 也有不同的数据,我们需要创建分布式表来映射当前表所有数据,方便查询数据结果,如下 图所示:

你可能感兴趣的:(CK,数据库)