ClickHouse安装及集群搭建
Posted 禹鼎侯
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了ClickHouse安装及集群搭建相关的知识,希望对你有一定的参考价值。
本文介绍如何在CentOS
系统上安装ClickHouse
以及集群部署。
本文依赖的环境为CentOS-7.4.1708
, 使用clickhouse
的版本为20.9.3.45
。
单节点安装
在线yum安装
clickhouse
的安装包并不在Linux
官方yum
仓库中,所以首先需要添加clickhouse
的yum
镜像:
curl -s https://packagecloud.io/install/repositories/altinity/clickhouse/script.rpm.sh | sudo bash
检查镜像情况:
[root@master ~]# yum list | grep clickhouse
clickhouse-client.x86_64 20.8.3.18-1.el7 Altinity_clickhouse
clickhouse-common-static.x86_64 20.8.3.18-1.el7 Altinity_clickhouse
clickhouse-debuginfo.x86_64 20.1.11.73-1.el7 Altinity_clickhouse
clickhouse-odbc.x86_64 1.1.9-1.el7 Altinity_clickhouse
clickhouse-server.x86_64 20.8.3.18-1.el7 Altinity_clickhouse
clickhouse-server-common.x86_64 20.8.3.18-1.el7 Altinity_clickhouse
clickhouse-test.x86_64 20.8.3.18-1.el7 Altinity_clickhouse
clicktail.x86_64 1.0.20180401-1 Altinity_clickhouse
由此可见,使用yum
在线安装的版本最新到20.8.3.18
。但是实际上clickhouse
已经迭代了很多版本,所以我们不采用此种安装方式,而采用rpm
包的安装方式。
PS: 有了上面的信息,yum
方式安装clickhouse
就很简单了,直接yum install -y clickhouse-server-common.x86_64 clickhouse-server.x86_64 clickhouse-client.x86_64
安装即可,此处就不演示了。
rpm包离线安装
我们可以从官方rpm
镜像仓库找到各种版本的rpm
安装包,官方地址是:https://repo.yandex.ru/clickh... 。
我们选择 20.9.3.45
版本的rpm
包,主要需要以下三个包:
clickhouse-client-20.9.3.45-2.noarch.rpm
clickhouse-server-20.9.3.45-2.noarch.rpm
clickhouse-common-static-20.9.3.45-2.x86_64.rpm
安装命令如下:
rpm -ivh clickhouse-common-static-20.9.3.45-2.x86_64.rpm clickhouse-client-20.9.3.45-2.noarch.rpm clickhouse-server-20.9.3.45-2.noarch.rpm
如下图所示,我们即在node5
这台机器上安装好了clickhouse
。
[root@node5 ck]# rpm -ivh clickhouse-common-static-20.9.3.45-2.x86_64.rpm clickhouse-client-20.9.3.45-2.noarch.rpm clickhouse-server-20.9.3.45-2.noarch.rpm
警告:clickhouse-common-static-20.9.3.45-2.x86_64.rpm: 头V4 RSA/SHA1 Signature, 密钥 ID e0c56bd4: NOKEY
准备中... ################################# [100%]
正在升级/安装...
1:clickhouse-common-static-20.9.3.4################################# [ 33%]
2:clickhouse-client-20.9.3.45-2 ################################# [ 67%]
3:clickhouse-server-20.9.3.45-2 ################################# [100%]
Path to data directory in /etc/clickhouse-server/config.xml: /var/lib/clickhouse/
[root@node5 ck]#
验证是否安装成功
如果以上步骤没有报错,则可以通过如下命令开启clickhouse
的服务:
systemctl start clickhouse-server
然后通过clickhouse-client
客户端去连接:
[root@node5 ck]# clickhouse-client
ClickHouse client version 20.9.3.45 (official build).
Connecting to localhost:9000 as user default.
Connected to ClickHouse server version 20.9.3 revision 54439.
node5 :) select 1
SELECT 1
┌─1─┐
│ 1 │
└───┘
1 rows in set. Elapsed: 0.003 sec.
node5 :)
如果出现上述界面,则说明单机安装clickhouse
成功。
clickhouse-client CLI工具说明
在上面,我们用到了clickhouse-client
这样一款工具。
clickhouse-client
是一个带命令行的客户端工具,它通过TCP
的9000
端口连接clickhouse-server
,可以在该命令行工具里进行各种操作。
通过 clickhouse-client --help
可以查看工具的帮助文档,可以看到该工具支持很多参数,此处简要说一下一些常用的参数。
参数 | 用法举例 | 说明 | 备注 |
---|---|---|---|
-h [ --host ] | -h 192.168.0.1 --host=192.168.0.1 | 指定连接clickhouse 服务的host 地址,一般是远程连接其他机器上的clickhouse 服务。 | clickhouse 要想连接远程服务器,需要将配置文件中<listen_host>::</listen_host> 选项开启。 |
--port | --port=9000 | 指定远程连接clickhouse 服务的端口号,默认为9000 | 这个端口号可通过配置文件配置:<tcp_port>9000</tcp_port> |
-u [ --user ] | -u ck --user=ck | 指定登录clickhouse 的用户,默认是default | default 用户是内置的用户。可以通过users.xml 配置文件自定义用户信息。 |
--password | --password=123456 | 指定登录clickhouse 的密码 | default 用户是没有密码的。密码可配置明文密码和加密密码 |
-q [ --query ] | -q "show databases" | 通过命令行直接输入sql ,即时返回,而不需要进入客户端内部 | |
-m [ --multiline ] | 在客户端内支持多行语句操作,以分号作为结束符 | 如果不指定-m 参数,每句sql 语法后可加分号,也可不加,默认一行就是一个语句 | |
-n [ --multiquery ] | 命令行直接输入语句时支持多条sql语句,一般和-q 结合使用 | 注意-n 的位置不能在-q 和sql 语句之间 | |
-f [ --format ] | -f JSON | 设置输出的显示格式 | 支持JSON 、CSV 、TSV 等,详见https://clickhouse.tech/docs/... |
利用CLI工具导入数据
假设我们在default
数据库下有一张test
表,在/data01
目录下有一个file.csv
的文件,可通过如下方式将数据导入到test
表中。
clickhouse-client --database=test --query="INSERT INTO test FORMAT CSV" < /data01/file.csv
配置文件说明
config.xml
config.xml
文件是clickhouse
默认的配置文件,路径为/etc/clickhouse-server/config.xml
。
config.xml
中可以配置的内容有很多,下面节选一些比较重要的配置项来说明一下:
<?xml version="1.0"?>
<yandex>
<logger>
<!-- clickhouse日志相关的配置 -->
<level>trace</level>
<log>/var/log/clickhouse-server/clickhouse-server.log</log> <!--日志路径-->
<errorlog>/var/log/clickhouse-server/clickhouse-server.err.log</errorlog>
<size>1000M</size>
<count>10</count>
</logger>
<http_port>8123</http_port> <!--http 客户端连接ck的端口-->
<tcp_port>9000</tcp_port> <!--tcp 客户端连接ck的端口 -->
<mysql_port>9004</mysql_port>
<listen_host>::</listen_host> <!--ip地址,配置成::可以被任意ipv4和ipv6的客户端连接, 需要注意的是,如果机器本身不支持ipv6,这样配置是无法启动clickhouse的,这时候可以改成0.0.0.0 -->
<path>/var/lib/clickhouse/</path> <!--ck存放数据库内容的路径-->
<user_files_path>/var/lib/clickhouse/user_files/</user_files_path> <!--File 引擎文件存放的路径,一般可设置为/,这样就可以指定绝对路径-->
<users_config>users.xml</users_config> <!--指定用户配置文件-->
<default_database>default</default_database> <!--指定默认数据库-->
<!--配置prometheus信息-->
<prometheus>
<endpoint>/metrics</endpoint>
<port>9363</port>
<metrics>true</metrics>
<events>true</events>
<asynchronous_metrics>true</asynchronous_metrics>
<status_info>true</status_info>
</prometheus>
<include_from>/etc/clickhouse-server/metrika.xml</include_from> <!--指定metrika.xml配置文件-->
users.xml
<users>
<!--用户名为ck-->
<ck>
<password>123456</password> <!--明文密码-->
<!--
SHA256加密密码,可通过下面的命令生成:
PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha256sum | tr -d \'-\'
<password_sha256_hex>8d969eef6ecad3c29a3a629280e686cf0c3f5d5a86aff3ca12020c923adc6c92</password_sha256_hex>
SHA1加密方式加密的密码,可通过下面的命令生成
PASSWORD=$(base64 < /dev/urandom | head -c8); echo "$PASSWORD"; echo -n "$PASSWORD" | sha1sum | tr -d \'-\' | xxd -r -p | sha1sum | tr -d \'-\'
<password_double_sha1_hex>7c4a8d09ca3762af61e59520943dc26494f8941b</password_double_sha1_hex>
-->
<networks>
<ip>::/0</ip>
</networks>
<profile>default</profile>
<quota>default</quota>
</ck>
</users>
metrika.xml
metrika.xml
主要是用来服务于集群搭建的。它里面是关于zookeeper
、shard
以及replica
的配置,比较复杂,将在部署集群中详细说明。
部署集群
Clickhouse
的集群是依赖于zookeeper
的。所以在搭建clickhouse
集群之前,首先要有一个zookeeper
集群。
关于zookeeper
集群的搭建,此处不再展开详述,如有不清楚的请自行百度。(本文默认zookeeper
集群已经搭建好)
前面说过,clickhouse
集群的相关配置都在metrika.xml
配置文件里,所以首先我们需要配置好metrika.xml
。metrika.xml
的路径可以在config.xml
中通过<include_from>
指定。
zookeeper配置
zookeeper
不一定要和ck
的节点安装在同一台机器上,只要ck
的几点能够访问zk即可。
<zookeeper-servers>
<node index="1">
<host>192.168.0.1</host>
<port>2181</port>
</node>
<node index="2">
<host>192.168.0.2</host>
<port>2181</port>
</node>
<node index="3">
<host>192.168.0.3</host>
<port>2181</port>
</node>
</zookeeper-servers>
Shard和Replica设置
如下图所示,为一个完整的shard
和Replica
的配置,以下为test
集群配置2
分片2
副本。
<clickhouse_remote_servers>
<test> <!--集群的名字-->
<shard> <!--shard分片的配置-->
<internal_replication>true</internal_replication> <!--是否只将数据写入其中一个副本,默认为false-->
<replica> <!--shard副本的配置-->
<host>192.168.0.1</host>
<port>9000</port>
</replica>
<replica>
<host>192.168.0.2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>192.168.0.3</host>
<port>9000</port>
</replica>
<replica>
<host>192.168.0.4</host>
<port>9000</port>
</replica>
</shard>
</test>
</clickhouse_remote_servers>
一个完整的metrika.xml
如下所示:
<yandex>
<zookeeper-servers>
<node index="1">
<host>192.168.0.1</host>
<port>2181</port>
</node>
<node index="2">
<host>192.168.0.2</host>
<port>2181</port>
</node>
<node index="3">
<host>192.168.0.3</host>
<port>2181</port>
</node>
</zookeeper-servers>
<clickhouse_remote_servers>
<test> <!--集群的名字-->
<shard> <!--shard分片的配置-->
<internal_replication>true</internal_replication> <!--是否只将数据写入其中一个副本,默认为false-->
<replica> <!--replica副本的配置-->
<host>192.168.0.1</host>
<port>9000</port>
</replica>
<replica>
<host>192.168.0.2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>192.168.0.3</host>
<port>9000</port>
</replica>
<replica>
<host>192.168.0.4</host>
<port>9000</port>
</replica>
</shard>
</test>
</clickhouse_remote_servers>
</yandex>
集群搭建
首先按照单节点安装的方式,在node1
,node2
,node3
,node4
四个节点上安装好clickhouse
。
修改config.xml
,主要修改内容如下:
<!--1. 增加listen_host,允许远程访问-->
<listen_host>::</listen_host>
<!--2. 修改path路径,指定数据存放位置,我这里指定/data01/clickhouse目录-->
<!-- 需要注意的是,这个路径必须提前存在,且clickhouse用户有权限访问 -->
<path>/data01/clickhouse</path>
<tmp_path>/data01/clickhouse/tmp/</tmp_path>
<user_files_path>/data01/clickhouse/user_files/</user_files_path>
<access_control_path>/data01/clickhouse/access/</access_control_path>
<!--3.指定metrika.xml文件-->
<include_from>/etc/clickhouse-server/metrika.xml</include_from>
<!--4. 重新制定tcp_port -->
<tcp_port>19000</tcp_port>
<!--这一步不是必须的,我这里之所以重新制定,是因为发现我的机器上9000端口已经被占用了,一般情况下,默认的9000即可-->
修改users.xml
,我们增加一个用户,专门用来管理cluster
。
<!--在<users>里面新增如下内容,创建一个用户名为ck,密码为123456的用户-->
<ck>
<password>123456</password>
<networks incl="networks" replace="replace">
<ip>::/0</ip>
</networks>
<profile>default</profile>
<quota>default</quota>
</ck>
创建metrika.xml
文件。
在/etc/clickhouse-server
路径下创建metrika.xml
文件(这个路径为上面config.xml
中配置的include_from
的路径):
<yandex>
<zookeeper-servers>
<node index="1">
<host>192.168.0.1</host>
<port>2181</port>
</node>
<node index="2">
<host>192.168.0.2</host>
<port>2181</port>
</node>
<node index="3">
<host>192.168.0.3</host>
<port>2181</port>
</node>
</zookeeper-servers>
<clickhouse_remote_servers>
<test>
<shard>
<replica>
<host>192.168.0.1</host>
<port>9000</port> <!--这里的端口号要和config.xml中tcp_port保持一致,如果那里改了,这里也要对应的改-->
</replica>
<replica>
<host>192.168.0.2</host>
<port>9000</port>
</replica>
</shard>
<shard>
<replica>
<host>192.168.0.3</host>
<port>9000</port>
</replica>
<replica>
<host>192.168.0.4</host>
<port>9000</port>
</replica>
</shard>
</test>
</clickhouse_remote_servers>
</yandex>
以上配置在四台机器上同步,然后重启clickhouse
:
systemctl restart clickhouse-server
如果启动成功,就能看到clickhouse-server
的进程已经在运行了:
[root@node2 test]# ps -ef |grep clickhouse
clickho+ 17548 1 1 11:11 ? 00:00:00 /usr/bin/clickhouse-server --config=/etc/clickhouse-server/config.xml --pid-file=/run/clickhouse-server/clickhouse-server.pid
root 17738 10683 0 11:11 pts/0 00:00:00 grep --color=auto clickhouse
我们使用clickhouse-client
工具,登录到其中一台机器:
[root@node4 test]# clickhouse-client -u ck --password=123456 -m
ClickHouse client version 20.9.3.45 (official build).
Connecting to localhost:9000 as user ck.
Connected to ClickHouse server version 20.9.3 revision 54439.
node4 :)
查询system.clusters
表:
node4 :) select * from system.clusters where cluster = \'test\';
SELECT *
FROM system.clusters
WHERE cluster = \'test\'
┌─cluster─┬─shard_num─┬─shard_weight─┬─replica_num─┬─host_name─────┬─host_address──┬──port─┬─is_local─┬─user────┬─default_database─┬─errors_count─┬─estimated_recovery_time─┐
│ test │ 1 │ 1 │ 1 │ 192.168.0.1 │ 192.168.0.1 │ 9000 │ 0 │ default │ │ 0 │ 0 │
│ test │ 1 │ 1 │ 2 │ 192.168.0.2 │ 192.168.0.2 │ 9000 │ 0 │ default │ │ 0 │ 0 │
│ test │ 2 │ 1 │ 1 │ 192.168.0.3 │ 192.168.0.3 │ 9000 │ 0 │ default │ │ 0 │ 0 │
│ test │ 2 │ 1 │ 2 │ 192.168.0.4 │ 192.168.0.4 │ 9000 │ 1 │ default │ │ 0 │ 0 │
└─────────┴───────────┴──────────────┴─────────────┴───────────────┴───────────────┴───────┴──────────┴─────────┴──────────────────┴──────────────┴─────────────────────────┘
4 rows in set. Elapsed: 0.002 sec.
出现上面所示的结果,说明配置集群成功。
分布式表
接下来就可以在集群里创建分布式表了。
首先在集群的各个节点创建本地表。
CREATE TABLE t_cluster ON CLUSTER test (
id Int16,
name String,
birth Date
)ENGINE = MergeTree()
PARTITION BY toYYYYMM(birth)
ORDER BY id;
登录到任意节点,执行以上sql
,出现如下提示,说明执行成功:
node4 :) CREATE TABLE default.t_cluster ON CLUSTER test ( id Int16, name String, birth Date )ENGINE = MergeTree() PARTITION BY toYYYYMM(birth) ORDER BY id;
CREATE TABLE default.t_cluster ON CLUSTER test
(
`id` Int16,
`name` String,
`birth` Date
)
ENGINE = MergeTree()
PARTITION BY toYYYYMM(birth)
ORDER BY id
┌─host──────────┬──port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ 192.168.0.1 │ 9000 │ 0 │ │ 3 │ 0 │
│ 192.168.0.2 │ 9000 │ 0 │ │ 2 │ 0 │
│ 192.168.0.3 │ 9000 │ 0 │ │ 1 │ 0 │
│ 192.168.0.4 │ 9000 │ 0 │ │ 0 │ 0 │
└───────────────┴───────┴────────┴───────┴─────────────────────┴──────────────────┘
4 rows in set. Elapsed: 0.108 sec.
我们可以登录任意一台机器,都能查询到t_cluster
表,这就说明已经在test
集群上所有节点创建了一个t_cluster
本地表。
这个时候如果往t_cluster
表插入数据,仍然是在所在节点的本地表中操作,在其他集群中是无法看见的。
如我们在node1
节点插入如下数据:
node1 :) insert into t_cluster values(1, \'aa\', \'2021-02-01\'), (2, \'bb\', \'2021-02-02\');
INSERT INTO t_cluster VALUES
Ok.
2 rows in set. Elapsed: 0.002 sec.
在node1
节点查询:
node1 :) select * from t_cluster;
SELECT *
FROM t_cluster
┌─id─┬─name─┬──────birth─┐
│ 1 │ aa │ 2021-02-01 │
│ 2 │ bb │ 2021-02-02 │
└────┴──────┴────────────┘
2 rows in set. Elapsed: 0.002 sec.
node2
节点查询:
node2 :) select * from t_cluster;
SELECT *
FROM t_cluster
Ok.
0 rows in set. Elapsed: 0.002 sec.
node3
和node4
查询也是如此。
这就充分说明了如果直接操作t_cluster
表,操作的数据其实只是当前节点的数据。有人可能会有疑惑,我不是明明指定了node1
和node2
互为replica
吗?为什么node1
的数据也没有同步到node2
上面去?
这是因为我们的引擎指定的是MergerTree
,而不是ReplicaMergeTree
,如果指定的是ReplicaMergeTree
,的确是会同步到对应的replica
上面去的,但这里创建的仅仅是MergeTree
,这个引擎本身不具备同步副本的功能,所以node2
上并没有同步数据。
一般在实际应用中,创建分布式表指定的都是Replica
的表,这里仅仅是做一个例子说明。
那么既然如此,这个集群中的表数据不能互相关联起来,不就失去了集群的意义了吗?
为了解决上面的问题,从而引入了分布式表。
分布式表的创建是这样的:
CREATE TABLE default.dist_t_cluster ON CLUSTER test as t_cluster engine = Distributed(test, default, t_cluster,rand());
Distributed
是一个特殊的引擎,用来创建分布式表。它本身具有四个参数,第一个参数表示集群的名字,第二个参数为数据库的名字,第三个参数为表的名字,第四个参数为sharding key
,它决定最终数据落在哪一个分片上,最后一个参数可以省略,如果省略,则实用配置文件中的weight
分片权重。
上面的语句就是创建一张名为dist_t_cluster
的分布式表,该分布式表是基于test
集群中的default.t_cluster
表。as t_cluster
表示这张表的结构和t_cluster
一模一样。
分布式表本身不存储数据,数据存储其实还是由本地表t_cluster
完成的。这个dist_t_cluster
仅仅做一个代理的作用。
如下所示,表示分布式表创建成功。
node1 :) CREATE TABLE default.dist_t_cluster ON CLUSTER test as t_cluster engine = Distributed(test, default, t_cluster, rand());
CREATE TABLE default.dist_t_cluster ON CLUSTER test AS t_cluster
ENGINE = Distributed(test, default, t_cluster, rand())
┌─host──────────┬──port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ 192.168.0.1 │ 9000 │ 0 │ │ 3 │ 0 │
│ 192.168.0.2 │ 9000 │ 0 │ │ 2 │ 0 │
│ 192.168.0.3 │ 9000 │ 0 │ │ 1 │ 0 │
│ 192.168.0.4 │ 9000 │ 0 │ │ 0 │ 0 │
└───────────────┴───────┴────────┴───────┴─────────────────────┴──────────────────┘
4 rows in set. Elapsed: 0.106 sec.
接下来我们使用分布式表向集群中插入数据,观察现象:
node1 :) insert into dist_t_cluster values(1, \'aaa\', \'2021-02-01\'), (2, \'bbb\', \'2021-02-02\');
INSERT INTO dist_t_cluster VALUES
Ok.
2 rows in set. Elapsed: 0.002 sec.
这时候我们在不同节点上查询dist_t_cluster
表,得到的结果都是一模一样的:
/* node1 查询结果 */
node1 :) select * from dist_t_cluster;
SELECT *
FROM dist_t_cluster
┌─id─┬─name─┬──────birth─┐
│ 2 │ bbb │ 2021-02-02 │
└────┴──────┴────────────┘
┌─id─┬─name─┬──────birth─┐
│ 1 │ aaa │ 2021-02-01 │
└────┴──────┴────────────┘
2 rows in set. Elapsed: 0.005 sec.
/* node2 查询结果 */
node2 :) select * from dist_t_cluster;
SELECT *
FROM dist_t_cluster
┌─id─┬─name─┬──────birth─┐
│ 2 │ bbb │ 2021-02-02 │
└────┴──────┴────────────┘
┌─id─┬─name─┬──────birth─┐
│ 1 │ aaa │ 2021-02-01 │
└────┴──────┴────────────┘
2 rows in set. Elapsed: 0.005 sec.
/* node3 查询结果 */
node3 :) select * from dist_t_cluster;
SELECT *
FROM dist_t_cluster
┌─id─┬─name─┬──────birth─┐
│ 1 │ aaa │ 2021-02-01 │
└────┴──────┴────────────┘
┌─id─┬─name─┬──────birth─┐
│ 2 │ bbb │ 2021-02-02 │
└────┴──────┴────────────┘
2 rows in set. Elapsed: 0.006 sec.
/* node4 查询结果 */
node4 :) select * from dist_t_cluster;
SELECT *
FROM dist_t_cluster
┌─id─┬─name─┬──────birth─┐
│ 1 │ aaa │ 2021-02-01 │
└────┴──────┴────────────┘
┌─id─┬─name─┬──────birth─┐
│ 2 │ bbb │ 2021-02-02 │
└────┴──────┴────────────┘
2 rows in set. Elapsed: 0.005 sec.
我们再去看各个节点的本地表t_cluster
表中数据分布情况:
/* node1 查询结果 */
node1 :) select * from t_cluster;
SELECT *
FROM t_cluster
┌─id─┬─name─┬──────birth─┐
│ 2 │ bbb │ 2021-02-02 │
└────┴──────┴────────────┘
1 rows in set. Elapsed: 0.002 sec.
/* node2 查询结果 */
node2 :) select * from t_cluster;
SELECT *
FROM t_cluster
┌─id─┬─name─┬──────birth─┐
│ 2 │ bbb │ 2021-02-02 │
└────┴──────┴────────────┘
1 rows in set. Elapsed: 0.002 sec.
/* node3 查询结果 */
node3 :) select * from t_cluster;
SELECT *
FROM t_cluster
┌─id─┬─name─┬──────birth─┐
│ 1 │ aaa │ 2021-02-01 │
└────┴──────┴────────────┘
1 rows in set. Elapsed: 0.002 sec.
/* node4 查询结果 */
node4 :) select * from t_cluster;
SELECT *
FROM t_cluster
┌─id─┬─name─┬──────birth─┐
│ 1 │ aaa │ 2021-02-01 │
└────┴──────┴────────────┘
1 rows in set. Elapsed: 0.002 sec.
由以上结果可知,node1
和node2
上面存储的数据一样,node3
和node4
上面存储的数据一样,但是node1
和node3
上面的数据不一样。node1
(node2
)和node3
(node4
)的数据组成了dist_t_cluster
表中的所有数据。
这是因为node1
和node2
、node3
和 node4
互为副本,所以它们的数据会自动同步。而node1
(node2
)和node3
(node4
)属于不同的分片,所以数据按照一定的规则(sharding key
)落在了不同分片。
如果我们打开存储数据的目录,可以看到dist_t_cluster
表中仅仅有一个临时文件夹,并没有实际存储数据,因为数据是存储在t_cluster
本地表中的。
[root@node1 chenyc]# ls -l /data01/clickhouse/data/default/dist_t_cluster/
总用量 0
drwxr-x--- 3 clickhouse clickhouse 17 2月 25 13:57 default@192%2E168%2E21%2E52:9000
drwxr-x--- 3 clickhouse clickhouse 17 2月 25 13:57 default@192%2E168%2E21%2E53:9000
drwxr-x--- 2 clickhouse clickhouse 6 2月 25 13:57 default@192%2E168%2E21%2E54:9000
macros设置
macros
翻译过来是宏的意思,也就是通过它,可以使用一些宏定义在SQL
变量中进行替换,比如shard number
,replica
的名称等。这一点在需要创建Replicated
引擎表的时候特别有用。
Replicated
引擎有两个参数,其中一个为zoo_path
,表示zookeeper
中该表的路径;另一个参数为replica_name
,代表该表所在的副本名称。
ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/{cluster}/{shard}/default/dbtest\', \'{replica}\')
order by (xxxx);
如上所示,就是一个Replicated
引擎在创建表时需要指定的参数。
其中:
参数 | 说明 |
---|---|
/clickhouse/tables | clickhouse在zookeeper的官方路径 |
{cluster} | 集群名称 |
{shard} | shard number |
default | 数据库名 |
dbtest | 表名,最好跟实际的表名一致 |
{replica} | 副本名称 |
先假设我们不设置macros
,如果我们要在node1
~node4
四个节点上创建Replicated
表,其中node1
和node2
位于shard1
,node3
和node4
位于shard2
,node1
与node2
互为副本,node3
与node4
互为副本。需要怎么创建?
我们需要在node1
上创建表dbtest
,语句如下:
CREATE TABLE dbtest(
...
)ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/1/default/dbtest\', \'node1\')
order by (xxxx);
然后在node2
~node4
上分别创建dbtest
表:
/*node2执行*/
CREATE TABLE dbtest(
...
)ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/1/default/dbtest\', \'node2\')
order by (xxxx);
/*node3执行*/
CREATE TABLE dbtest(
...
)ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/2/default/dbtest\', \'node3\')
order by (xxxx);
/*node4执行*/
CREATE TABLE dbtest(
...
)ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/test/2/default/dbtest\', \'node4\')
order by (xxxx);
如果集群里节点特别多,那么这样到每个节点下去执行,实在太过累人。那么,有没有一种方式使用上面的类似 ON CLUSTER
的方式自动创建呢?
答案当然是有,这个时候就要借助macros
宏了。
我们可以在metrika.xml
文件中预先编写好一些宏,然后在SQL
变量中使用{}
括起来直接替换即可。
在metrika.xml
中配置宏如下所示:
<macros>
<cluster>test</cluster>
<shard>1</shard>
<replica>vm10140</replica>
</macros>
有了以上配置,那么在Replicated
引擎中传参的时候,就可以使用{cluster}
代替test
,使用{shard}
代替1
,用{replica}
代替vm10140
。我们只需要在不同节点上配置好对应的宏变量,那么,在创建Replicated
引擎表的时候,使用下面的语句就可以了:
CREATE TABLE dbtest ON CLUSTER test(
...
)ENGINE = ReplicatedMergeTree(\'/clickhouse/tables/{cluster}/{shard}/default/dbtest\', \'{replica}\')
order by (xxxx);
以上语句在执行的时候,在node1
下,{cluster}
、{shard}
和{replica}
取的是node1
的宏对应的值,在node2
下取的是node2
的宏设置的值,自动替换,非常方便。
只要macros
配置正确,就可以使用上述语句在集群的各个节点去创建表了,而不必到每个节点下去手动创建一遍。
此时,我们通过zookeeper
可以查看到Replicated
中zoo_path
的具体情况:
顺便一提,macros
的信息都保存在system.macros
表中:
vm10140 :) select * from system.macros;
SELECT *
FROM system.macros
┌─macro───┬─substitution─┐
│ cluster │ test │
│ replica │ vm10140 │
│ shard │ 1 │
└─────────┴──────────────┘
3 rows in set. Elapsed: 0.005 sec.
因此,可以非常方便地从这个地方看到哪些宏是可以用的。
剩下的创建Distributed
分布式表和上面的步骤一致,这里就不再赘述了。
以上是关于ClickHouse安装及集群搭建的主要内容,如果未能解决你的问题,请参考以下文章