ClickHouse多节点的安装以及分布式表和本地表的创建

目录

  1. 安装
  2. 验证集群
  3. 分布式DDL操作

安装

ClickHouse集群安装非常简单,首先重复上面步骤,分别在其他机器上安装ClickHouse,然后再分别配置一下/etc/clickhouse-server/config.xml和/etc/metrika.xml两个文件即可。值得注意的是,ClickHouse集群的依赖于Zookeeper,所以要保证先安装好Zookeeper集群,zk集群的安装步骤非常简单,本文不会涉及。本文演示三个节点的ClickHouse集群安装,具体步骤如下:

  • 首先,重复单机安装的步骤,分别在另外两台机器安装ClickHouse

  • 然后,在每台机器上修改/etc/clickhouse-server/config.xml文件

    <!-- 如果禁用了ipv6,使用下面配置-->
    <listen_host>0.0.0.0</listen_host>
    <!-- 如果没有禁用ipv6,使用下面配置
    <listen_host>::</listen_host>
    -->

    问题1: 在禁用了ipv6时,如果使用::配置,会报如下错误

    Application: DB::Exception: Listen [::]:8123 failed: Poco::Exception. Code: 1000, e.code() =0, e.displayText() = DNS error: EAI: -9

    问题2: ClickHouse默认的tcp端口号是9000,如果存在端口冲突,可以在/etc/clickhouse-server/config.xml文件中修改 端口号

    <tcp_port>9001</tcp_port>
  • 最后在/etc下创建metrika.xml文件,内容如下

    <yandex>
    <!-- 该标签与config.xml的<remote_servers incl="clickhouse_remote_servers" >保持一致
    -->
    <clickhouse_remote_servers>
    <!-- 集群名称,可以修改 -->
    <cluster_1shards_2replicas>
    <!-- 配置1个分片,2个副本-->
    <shard>
    <!-- 先写到一个副本,再同步,默认同时写多个副本 -->
    <internal_replication>true</internal_replication>
    <replica>
    <host>hadoop001</host>
    <port>9001</port>
    </replica>
    <replica>
    <host>hadoop002</host>
    <port>9001</port>
    </replica>
    </shard>
    </cluster_1shards_2replicas>
    <cluster_2shards_1replicas>
    <!-- 配置2个分片,1个副本-->
    <shard>
    <!-- 先写到一个副本,再同步,默认同时写多个副本(只有一个分区,无所谓配不配置) -->
    <internal_replication>true</internal_replication>
    <replica>
    <host>hadoop001</host>
    <port>9001</port>
    </replica>
    </shard>
    <shard>
    <!-- 先写到一个副本,再同步,默认同时写多个副本 -->
    <internal_replication>true</internal_replication>
    <replica>
    <host>hadoop002</host>
    <port>9001</port>
    </replica>
    </shard>
    </cluster_2shards_1replicas>
    </clickhouse_remote_servers>
    <!-- 该标签与config.xml的<zookeeper incl="zookeeper-servers" optional="true" />
    保持一致
    -->
    <zookeeper-servers>
    <node>
    <host>hadoop001</host>
    <port>2181</port>
    </node>
    <node>
    <host>hadoop002</host>
    <port>2181</port>
    </node>
    <node>
    <host>hadoop003</host>
    <port>2181</port>
    </node>
    </zookeeper-servers>
    <!-- 分片和副本标识,shard标签配置分片编号,<replica>配置分片副本主机名
    需要修改对应主机上的配置-->
    <macros>
    <shard>01</shard>
    <replica>hadoop002</replica>
    </macros>

    <!-- 另一节点的变量宏配置
    <macros>
    <shard>02</shard>
    <replica>hadoop002</replica>
    </macros>
    -->
    </yandex>

    注意: 可以将internal_replication参数设置为true,因为可以由ClickHouse来保证数据副本的一致性。你可以自已指定要将哪些数据写入哪些服务器,并直接在每个分片上执行写入,并且你可以使用任何分片方案。对于复杂业务特性的需求,这可能是非常重要的。官方推荐这种方案。

  • 分别在各自的机器上启动clickhouse-server

    # service clickhouse-server start
  • (可选配置)修改/etc/clickhouse-client/config.xml文件

    由于clickhouse-client默认连接的主机是localhost,默认连接的端口号是9000,由于我们修改了默认的端口号,所以需要修改客户端默认连接的端口号,在该文件里添加如下内容:

    <port>9001</port>

    当然也可以不用修改,但是记得在使用客户端连接时,加上–port 9001参数指明要连接的端口号,否则会报错:

    Connecting to localhost:9000 as user default.Code: 210. DB::NetException: Connection refused (localhost:9000)

验证集群

在完成上述配置之后,在各自机器上启动clickhouse-server,并开启clickhouse-clent

// 启动server
# service clickhouse-server start
// 启动客户端,-m参数支持多行输入
# clickhouse-client -m

可以查询系统表验证集群配置是否已被加载:

xx :) select cluster,shard_num,replica_num,host_name,port,user from system.clusters;
┌─cluster──────────────────────────────────────┬─shard_num─┬─replica_num─┬─host_name────┬─port─┬─user────┐
│ cluster_1shards_2replicas │ 1 │ 1 │ emr-header-1 │ 9001 │ default │
│ cluster_1shards_2replicas │ 1 │ 2 │ emr-header-2 │ 9001 │ default │
│ cluster_2shards_1replicas │ 1 │ 1 │ emr-header-1 │ 9001 │ default │
│ cluster_2shards_1replicas │ 2 │ 1 │ emr-header-2 │ 9001 │ default │
│ test_cluster_two_shards │ 1 │ 1 │ 127.0.0.1 │ 9000 │ default │
│ test_cluster_two_shards │ 2 │ 1 │ 127.0.0.2 │ 9000 │ default │
│ test_cluster_two_shards_internal_replication │ 1 │ 1 │ 127.0.0.1 │ 9000 │ default │
│ test_cluster_two_shards_internal_replication │ 2 │ 1 │ 127.0.0.2 │ 9000 │ default │
│ test_cluster_two_shards_localhost │ 1 │ 1 │ localhost │ 9000 │ default │
│ test_cluster_two_shards_localhost │ 2 │ 1 │ localhost │ 9000 │ default │
│ test_shard_localhost │ 1 │ 1 │ localhost │ 9000 │ default │
│ test_shard_localhost_secure │ 1 │ 1 │ localhost │ 9440 │ default │
│ test_unavailable_shard │ 1 │ 1 │ localhost │ 9000 │ default │
│ test_unavailable_shard │ 2 │ 1 │ localhost │ 1 │ default │
└──────────────────────────────────────────────┴───────────┴─────────────┴──────────────┴──────┴─────────┘

接下来再来看一下集群的分片信息(宏变量):分别在各自机器上执行下面命令:

xx1 :) select * from system.macros;
┌─macro───┬─substitution─┐
│ replica │ cdh04 │
│ shard │ 01 │
└─────────┴──────────────┘

xx2 :) select * from system.macros;
┌─macro───┬─substitution─┐
│ replica │ cdh05 │
│ shard │ 02 │
└─────────┴──────────────┘

xx3 :) select * from system.macros;
┌─macro───┬─substitution─┐
│ replica │ cdh06 │
│ shard │ 03 │
└─────────┴──────────────┘

分布式DDL操作

默认情况下,CREATE、DROP、ALTER、RENAME操作仅仅在当前执行该命令的server上生效。在集群环境下,可以使用ON CLUSTER语句,这样就可以在整个集群发挥作用。

分布式表只是作为一个查询引擎,本身不存储任何数据,查询时将sql发送到所有集群分片,然后进行进行处理和聚合后将结果返回给客户端,因此clickhouse限制聚合结果大小不能大于分布式表节点的内存,当然这个一般条件下都不会超过;分布式表可以所有实例都创建,也可以只在一部分实例创建,这个和业务代码中查询的示例一致,建议设置多个,当某个节点挂掉时可以查询其他节点上的表,分布式表的建表语句如下:

分布式表一般用本地表加all来表示,这里distable就是上面xml配置中的标签名称,最后的rand()表示向分布式表插入数据时,将随机插入到副本,在生产环境建议插入的时候客户端可以随机分桶插入到本地表,查询的时候走分布式表,即分布式表只读,本地复制表只写.

比如创建一张分布式表:

CREATE TABLE log_test_2_all ON CLUSTER cluster_2shards_1replicas
(
`ts` DateTime,
`uid` String,
`biz` String
)
ENGINE = Distributed(cluster_2shards_1replicas,default,log_test_2_local,rand())

Distributed表引擎的定义形式如下所示:关于ClickHouse的表引擎,后续文章会做详细解释。

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

各个参数的含义分别如下:

  • cluster_name:集群名称,与集群配置中的自定义名称相对应。
  • database_name:数据库名称
  • table_name:表名称
  • sharding_key:可选的,用于分片的key值,在数据写入的过程中,分布式表会依据分片key的规则,将数据分布到各个节点的本地表。

尖叫提示:

创建分布式表是读时检查的机制,也就是说对创建分布式表和本地表的顺序并没有强制要求

同样值得注意的是,在上面的语句中使用了ON CLUSTER分布式DDL,这意味着在集群的每个分片节点上,都会创建一张Distributed表,这样便可以从其中任意一端发起对所有分片的读、写请求。

创建完成上面的分布式表时,在每台机器上查看表,发现每台机器上都存在一张刚刚创建好的表。

接下来就需要创建本地表了,使用变量宏创建本地表:

CREATE TABLE log_test_2_local ON CLUSTER cluster_2shards_1replicas  #两个分片,一个副本
(
`ts` DateTime,
`uid` String,
`biz` String
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/log_test_2', '{replica}')
PARTITION BY toYYYYMMDD(ts)
ORDER BY ts
SETTINGS index_granularity = 8192

ReplicatedMergeTree 参数

  • zoo_path — ZooKeeper 中该表的路径。
  • replica_name — ZooKeeper 中的该表的副本名称。

如上例所示,这些参数可以包含宏替换的占位符,即大括号的部分。它们会被替换为配置文件里 ‘macros’ 那部分配置的值。示例:

<macros>
<shard>01</shard>
<replica>emr-header-1</replica>
</macros>

ZooKeeper 中该表的路径»对每个可复制表都要是唯一的。不同分片上的表要有不同的路径。

/clickhouse/tables/ 是公共前缀,我们推荐使用这个。

{shard} 是分片标识部分。对于大多数情况来说,你只需保留 {shard} 占位符即可,它会替换展开为分片标识。

table_name 是该表在 ZooKeeper 中的名称。使其与 ClickHouse 中的表名相同比较好。 这里它被明确定义,跟 ClickHouse 表名不一样,它并不会被 RENAME 语句修改(你可以在前面添加一个数据库名称 table_name 也是 例如: db_name.table_name)。

添加一点数据

INSERT INTO log_test_2_all VALUES ('2019-06-07 20:01:01', 'a', 'show');
INSERT INTO log_test_2_all VALUES ('2019-06-07 20:01:02', 'b', 'show');
INSERT INTO log_test_2_local VALUES ('2019-06-07 20:01:03', 'a', 'click');
INSERT INTO log_test_2_local VALUES ('2019-06-08 20:01:04', 'c', 'show');
INSERT INTO log_test_2_local VALUES ('2019-06-08 20:01:05', 'c', 'click');

查看第一个副本服务器的本地表

xx :) SELECT hostName(),* FROM log_test_2_local;
SELECT
``hostName(),
``*
FROM log_test

┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz──┐
192.168.4.52019-06-08 20:01:04 │ c │ show
└─────────────────────────────────┴─────────────────────┴─────┴──────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz───┐
192.168.4.52019-06-07 20:01:03 │ a │ click │
└─────────────────────────────────┴─────────────────────┴─────┴───────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz───┐
192.168.4.52019-06-08 20:01:05 │ c │ click │
└─────────────────────────────────┴─────────────────────┴─────┴───────┘
3 rows in set. Elapsed: 0.002 sec.

查看第二个副本服务器的本地表

xx :) SELECT hostName(),* FROM log_test_2_local;
SELECT
``hostName(),
``*
FROM log_test

┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz──┐
192.168.4.32019-06-07 20:01:02 │ b │ show
└─────────────────────────────────┴─────────────────────┴─────┴──────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz───┐
192.168.4.32019-06-07 20:01:03 │ a │ click │
└─────────────────────────────────┴─────────────────────┴─────┴───────┘
2 rows in set. Elapsed: 0.003 sec.

查看任意服务器的分布式表

xx :) SELECT hostName(),* FROM log_test_2_all;
SELECT
``hostName(),
``*
FROM log_test

┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz──┐
192.168.4.32019-06-08 20:01:04 │ c │ show
└─────────────────────────────────┴─────────────────────┴─────┴──────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz───┐
192.168.4.32019-06-08 20:01:05 │ c │ click │
└─────────────────────────────────┴─────────────────────┴─────┴───────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz──┐
192.168.4.32019-06-07 20:01:01 │ a │ show
└─────────────────────────────────┴─────────────────────┴─────┴──────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz──┐
192.168.4.32019-06-07 20:01:02 │ b │ show
└─────────────────────────────────┴─────────────────────┴─────┴──────┘
┌─hostName()──────────────────────┬──────────────────ts─┬─uid─┬─biz───┐
192.168.4.32019-06-07 20:01:03 │ a │ click │
└─────────────────────────────────┴─────────────────────┴─────┴───────┘
5 rows in set. Elapsed: 0.003 sec.

结论: 分布式表不存储数据,而是一个全局视图,展示所有本地表的数据

集群修改字段类型

ALTER TABLE log_test ON CLUSTER cluster_2shards_1replicas MODIFY COLUMN biz LowCardinality(String) ;

集群下线分区

ALTER TABLE log_test ON CLUSTER cluster_2shards_1replicas DETACH PARTITION 20190608;

集群删除表

DROP TABLE log_test ON CLUSTER cluster_2shards_1replicas;
Author: Tunan
Link: http://yerias.github.io/2020/11/21/clickhouse/2/
Copyright Notice: All articles in this blog are licensed under CC BY-NC-SA 4.0 unless stating additionally.