2

本文介绍如何在CentOS系统上安装ClickHouse以及集群部署。

本文依赖的环境为CentOS-7.4.1708, 使用clickhouse的版本为20.9.3.45

单节点安装

在线yum安装

clickhouse的安装包并不在Linux官方yum仓库中,所以首先需要添加clickhouseyum镜像:

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是一个带命令行的客户端工具,它通过TCP9000端口连接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的用户,默认是defaultdefault用户是内置的用户。可以通过users.xml配置文件自定义用户信息。
--password--password=123456指定登录clickhouse的密码default用户是没有密码的。密码可配置明文密码和加密密码
-q [ --query ]-q "show databases"通过命令行直接输入sql,即时返回,而不需要进入客户端内部
-m [ --multiline ] 在客户端内支持多行语句操作,以分号作为结束符如果不指定-m参数,每句sql语法后可加分号,也可不加,默认一行就是一个语句
-n [ --multiquery ] 命令行直接输入语句时支持多条sql语句,一般和-q结合使用注意-n的位置不能在-qsql语句之间
-f [ --format ]-f JSON设置输出的显示格式支持JSONCSVTSV等,详见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 主要是用来服务于集群搭建的。它里面是关于zookeepershard以及replica的配置,比较复杂,将在部署集群中详细说明。

部署集群

Clickhouse 的集群是依赖于zookeeper的。所以在搭建clickhouse集群之前,首先要有一个zookeeper集群。

关于zookeeper集群的搭建,此处不再展开详述,如有不清楚的请自行百度。(本文默认zookeeper集群已经搭建好)

前面说过,clickhouse集群的相关配置都在metrika.xml配置文件里,所以首先我们需要配置好metrika.xmlmetrika.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设置

如下图所示,为一个完整的shardReplica的配置,以下为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>

集群搭建

首先按照单节点安装的方式,在node1node2node3node4四个节点上安装好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.

node3node4查询也是如此。

这就充分说明了如果直接操作t_cluster表,操作的数据其实只是当前节点的数据。有人可能会有疑惑,我不是明明指定了node1node2互为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. 

由以上结果可知,node1node2上面存储的数据一样,node3node4上面存储的数据一样,但是node1node3上面的数据不一样。node1node2)和node3node4)的数据组成了dist_t_cluster表中的所有数据。

这是因为node1node2node3node4互为副本,所以它们的数据会自动同步。而node1node2)和node3node4)属于不同的分片,所以数据按照一定的规则(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 numberreplica的名称等。这一点在需要创建Replicated引擎表的时候特别有用。

Replicated引擎有两个参数,其中一个为zoo_path,表示zookeeper中该表的路径;另一个参数为replica_name,代表该表所在的副本名称。

ENGINE = ReplicatedMergeTree('/clickhouse/tables/{cluster}/{shard}/default/dbtest', '{replica}')
order by (xxxx);

如上所示,就是一个Replicated引擎在创建表时需要指定的参数。

其中:

参数说明
/clickhouse/tablesclickhouse在zookeeper的官方路径
{cluster}集群名称
{shard}shard number
default数据库名
dbtest表名,最好跟实际的表名一致
{replica}副本名称

先假设我们不设置macros,如果我们要在node1~node4四个节点上创建Replicated表,其中node1node2位于shard1node3node4位于shard2node1node2互为副本,node3node4互为副本。需要怎么创建?

我们需要在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可以查看到Replicatedzoo_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分布式表和上面的步骤一致,这里就不再赘述了。


禹鼎侯
176 声望466 粉丝

OLAP数据库开发。跨平台数据采集。