侧边栏壁纸
博主头像
船长博主等级

专注于云原生运维,致敬每个爱学习的你

  • 累计撰写 35 篇文章
  • 累计创建 10 个标签
  • 累计收到 9 条评论

ClickHouse 分片集群实战

船长
2022-01-29 / 0 评论 / 0 点赞 / 906 阅读 / 10,198 字
温馨提示:
本文最后更新于 2022-04-18,若内容或图片失效,请留言反馈。部分素材来自网络,若不小心影响到您的利益,请联系我们删除。

分片集群介绍

副本虽然能够提高数据的可用性,降低丢失风险,但是每台服务器实际上必须容纳全量数据,对数据的横向扩容没有解决。
要解决数据水平切分的问题,需要引入分片的概念。通过分片把一份完整的数据进行切分,不同的分片分布到不同的节点上,再通过 Distributed 表引擎把数据拼接起来一同使用。

Distributed 表引擎本身不存储数据,有点类似于 MyCat 之于 MySql,成为一种中间件,

通过分布式逻辑表来写入、分发、路由来操作多台节点不同分片的分布式数据

注意:Clickhouse的集群是表级别的,实际企业中,大部分做了高可用,但是没有分片,避免降低查询性能以及操作集群的复杂性。

集群写入流程

用户通过客户端进行写入操作,然后clickhouse会把写入的数据分配到各个分片存储到磁盘。

集群读取流程

读取操作副本选择机制:

  • 优先选择errors_count小的副本
  • errors_count相同的有随机、顺序、随机(优先第一顺位)、host名称近似等四种选择方式

分片集群安装

环境介绍

主机名IPOSsoftware
clickhouse-1192.168.1.104CentOS Linux release 7.7clickhouse,zookeeper
clickhouse-2192.168.1.105CentOS Linux release 7.7clickhouse,zookeeper
clickhouse-3192.168.1.106CentOS Linux release 7.7clickhouse,zookeeper
clickhouse-4192.168.1.107CentOS Linux release 7.7clickhouse
clickhouse-5192.168.1.108CentOS Linux release 7.7clickhouse
clickhouse-6192.168.1.109CentOS Linux release 7.7clickhouse

准备工作

$ cat /etc/redhat-release  # 查看系统版本
CentOS Linux release 7.7.1908 (Core)

# 关闭防火墙
$ systemctl stop firewalld.service
$ systemctl disable firewalld.service 

# 配置打开文件数限制
# 在所有节点的 /etc/security/limits.conf 文件的末尾加入以下内容
$ vim /etc/security/limits.conf
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072

# 在所有节点的 /etc/security/limits.d/20-nproc.conf 文件的末尾加入以下内容
$ vim /etc/security/limits.d/20-nproc.conf
* soft nofile 65536
* hard nofile 65536
* soft nproc 131072
* hard nproc 131072

# 安装依赖
$ yum install -y libtool
$ yum install -y *unixODBC*

# 关闭selinux:
$ sed -i 's/enforcing/disabled/' /etc/selinux/config
$ setenforce 0
 
# 关闭swap:
$ swapoff -a  # 临时
$ sed -ri 's/.*swap.*/#&/' /etc/fstab # 永久

# 根据规划设置主机名:
hostnamectl set-hostname <hostname>

# 配置hosts记录
cat <<EOF >> /etc/hosts
192.168.1.104 clickhouse-1
192.168.1.105 clickhouse-2
192.168.1.106 clickhouse-3
192.168.1.107 clickhouse-4
192.168.1.108 clickhouse-5
192.168.1.109 clickhouse-6
EOF    

zookeeper集群安装

# 部署JDK1.8.0_262
$ wget -P /usr/local/src https://github.com/AdoptOpenJDK/openjdk8-upstream-binaries/releases/download/jdk8u262-b10/OpenJDK8U-jdk_x64_linux_8u262b10.tar.gz  # 下载jdk安装包
$ cd /usr/local/src/
$ tar zxf OpenJDK8U-jdk_x64_linux_8u262b10.tar.gz   # 解压jdk安装包
$ mv openjdk-8u262-b10 /application/
# 添加环境变量
$ cat << EOF >> /etc/profile  
export JAVA_HOME=/application/openjdk-8u262-b10
export JRE_HOME=${JAVA_HOME}/jre
export CLASSPATH=.:${JAVA_HOME}/lib:${JRE_HOME}/lib
export PATH=${JAVA_HOME}/bin:$PATH
EOF
$ source /etc/profile
$ java -version   # 如出现如下则安装成功
openjdk version "1.8.0_262"
OpenJDK Runtime Environment (build 1.8.0_262-b10)
OpenJDK 64-Bit Server VM (build 25.262-b10, mixed mode)

### Zookeeper部署(所有节点执行)
 
 
​```shell
# Zookeeper软件包下载并解压
$ wget -P /usr/local/src https://mirror.bit.edu.cn/apache/zookeeper/zookeeper-3.6.1/apache-zookeeper-3.6.1-bin.tar.gz
$ cd /usr/local/src/
$ tar zxf apache-zookeeper-3.6.1-bin.tar.gz
$ mv apache-zookeeper-3.6.1-bin /application/zookeeper
 
 
# 创建启动用户并创建存储目录
$ useradd -s /bin/bash -U zookeeper
$ mkdir -p /application/data/zookeeper-data/
$ chown -Rf zookeeper.zookeeper /application/data/zookeeper-data/
$ chown -Rf zookeeper.zookeeper /application/zookeeper
 
 
# 创建ServerID标识
$ echo '1' > /application/data/zookeeper-data/myid     #clickhouse-1上执行
$ echo '2' > /application/data/zookeeper-data/myid     #clickhouse-2上执行
$ echo '3' > /application/data/zookeeper-data/myid     #clickhouse-3上执行
 
 
# 修改ZooKeeper配置
 
 
$ cat << EOF > /application/zookeeper/conf/zoo.cfg
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/application/data/zookeeper-data
dataLogDir=/application/zookeeper/logs
clientPort=2181
maxClientCnxns=60
autopurge.snapRetainCount=3
autopurge.purgeInterval=1
server.1=192.168.1.104:2888:3888
server.2=192.168.1.105:2888:3888
server.3=192.168.1.106:2888:3888
EOF
 
# 创建zookeeper启动文件并启动
 
 
$ cat << EOF > /usr/lib/systemd/system/zookeeper.service
[Unit]
Description=zookeeper.service
After=network.target
 
[Service]
User=zookeeper
Group=zookeeper
Type=forking
ExecStart=/application/zookeeper/bin/zkServer.sh start
ExecStop=/application/zookeeper/bin/zkServer.sh stop
ExecReload=/application/zookeeper/bin/zkServer.sh restart
[Install]
EOF
 
 
$ systemctl start zookeeper.service   # 启动zookeeper
$ systemctl enable zookeeper.service  # 添加开机自启动
$ systemctl status zookeeper.service  # 检测服务状态
​```
到此ZK集群搭建完毕

Clickhouse安装

# 安装Clickhouse
$ yum install yum-utils
$ rpm --import https://repo.clickhouse.tech/CLICKHOUSE-KEY.GPG
$ yum-config-manager --add-repo https://repo.clickhouse.tech/rpm/clickhouse.repo
$ yum install clickhouse-server clickhouse-client

Clickhouse 分片集群配置

在所有节点的的/etc/clickhouse-server/config.d 目录下创建一个名为 metrika.xml 的配置文件,内容如下:

clickhouse-1:

[root@clickhouse-1 ~]# cat /etc/clickhouse-server/config.d/metrika.xml 
<?xml version="1.0"?>
<yandex>
  <zookeeper-servers>
     <node index="1">
       <host>192.168.1.104</host>
       <port>2181</port>
     </node>
     <node index="2">
        <host>192.168.1.105</host>
        <port>2181</port>
     </node>
        <node index="3">
        <host>192.168.1.106</host>
        <port>2181</port>
     </node>
  </zookeeper-servers>
  <remote_servers>
    <gmall_cluster> <!-- 集群名称-->
     <shard> <!--集群的第一个分片-->
       <internal_replication>true</internal_replication>
       <!--该分片的第一个副本-->
       <replica> 
         <host>clickhouse-1</host>
         <port>9000</port>
       </replica>
         <!--该分片的第二个副本-->
         <replica> 
           <host>clickhouse-2</host>
           <port>9000</port>
         </replica>
     </shard>
     
     <shard> <!--集群的第二个分片-->
       <internal_replication>true</internal_replication>
       <!--该分片的第一个副本-->
       <replica>  
         <host>clickhouse-3</host>
         <port>9000</port>
       </replica>
         <!--该分片的第二个副本-->
         <replica>
           <host>clickhouse-4</host>
           <port>9000</port>
         </replica>
     </shard>

     <shard> <!--集群的第三个分片-->
       <internal_replication>true</internal_replication>
       <!--该分片的第一个副本-->
       <replica>  
         <host>clickhouse-5</host>
         <port>9000</port>
       </replica>
         <!--该分片的第二个副本-->
         <replica>
           <host>clickhouse-6</host>
           <port>9000</port>
         </replica>
     </shard>
    </gmall_cluster>
  </remote_servers>
  <macros>
    <shard>01</shard> <!--不同机器放的分片数不一样-->
    <replica>rep_1_1</replica> <!--不同机器放的副本数不一样-->
  </macros>
</yandex>

clickhouse-2:

[root@clickhouse-2 ~]# cat /etc/clickhouse-server/config.d/metrika.xml 
......
  <macros>
    <shard>01</shard> <!--不同机器放的分片数不一样-->
    <replica>rep_1_2</replica> <!--不同机器放的副本数不一样-->
  </macros>
</yandex>

clickhouse-3:

[root@clickhouse-3 ~]# cat /etc/clickhouse-server/config.d/metrika.xml 
......
  <macros>
    <shard>02</shard> <!--不同机器放的分片数不一样-->
    <replica>rep_1_3</replica> <!--不同机器放的副本数不一样-->
  </macros>
</yandex>

clickhouse-4:

[root@clickhouse-4 ~]# cat /etc/clickhouse-server/config.d/metrika.xml 
......
  <macros>
    <shard>02</shard> <!--不同机器放的分片数不一样-->
    <replica>rep_1_4</replica> <!--不同机器放的副本数不一样-->
  </macros>
</yandex>

clickhouse-5:

[root@clickhouse-5 ~]# cat /etc/clickhouse-server/config.d/metrika.xml 
......
  <macros>
    <shard>03</shard> <!--不同机器放的分片数不一样-->
    <replica>rep_1_5</replica> <!--不同机器放的副本数不一样-->
  </macros>
</yandex>

clickhouse-6:

[root@clickhouse-6 ~]# cat /etc/clickhouse-server/config.d/metrika.xml 
......
  <macros>
    <shard>03</shard> <!--不同机器放的分片数不一样-->
    <replica>rep_1_6</replica> <!--不同机器放的副本数不一样-->
  </macros>
</yandex>

在所有节点的的/etc/clickhouse-server/config.xml 中修改配置

 726 <zookeeper incl="zookeeper-servers" optional="true" />
 727 <include_from>/etc/clickhouse-server/config.d/metrika.xml</include_from>
 
  162 <listen_host>0.0.0.0</listen_host>

启动clickhouse集群在所有节点中执行:

$ /etc/init.d/clickhouse-server start   # 启动服务
$ /etc/init.d/clickhouse-server status  # 查看服务状态

Clickhouse 分片集群验证

在clickhouse集群其中一个节点上执行建表语句:

  • 会自动同步到所有节点 上

  • 集群名字要和配置文件中的一致

  • 分片和副本名称从配置文件的宏定义中获取

# 创建本地表

CREATE TABLE st_order_mt ON CLUSTER gmall_cluster
(
    `id` UInt32,
    `sku_id` String,
    `total_amount` Decimal(16, 2),
    `create_time` Datetime
)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/st_order_mt', '{replica}')
PARTITION BY toYYYYMMDD(create_time)
PRIMARY KEY id
ORDER BY (id, sku_id)

Query id: 5c57420d-2294-43cc-8338-0383009fa934

┌─host─────────┬─port─┬─status─┬─error─┬─num_hosts_remaining─┬─num_hosts_active─┐
│ clickhouse-2 │ 9000 │      0 │       │                   5 │                0 │
│ clickhouse-6 │ 9000 │      0 │       │                   4 │                0 │
│ clickhouse-4 │ 9000 │      0 │       │                   3 │                0 │
│ clickhouse-5 │ 9000 │      0 │       │                   2 │                0 │
│ clickhouse-1 │ 9000 │      0 │       │                   1 │                0 │
│ clickhouse-3 │ 9000 │      0 │       │                   0 │                0 │
└──────────────┴──────┴────────┴───────┴─────────────────────┴──────────────────┘

6 rows in set. Elapsed: 0.272 sec. 

# 创建 Distribute 分布式表
create table st_order_mt_all2 on cluster gmall_cluster
(
 id UInt32,
 sku_id String,
 total_amount Decimal(16,2),
 create_time Datetime
)engine = Distributed(gmall_cluster,default, st_order_mt,hiveHash(sku_id));

参数含义:

Distributed(集群名称,库名,本地表名,分片键)

分片键必须是整型数字,所以用 hiveHash 函数转换,也可以 rand()

插入测试数据:

insert into st_order_mt_all2 values
(201,'sre_001',1000.00,'2021-06-01 12:00:00') ,
(202,'sre_002',2000.00,'2021-06-01 12:00:00'),
(203,'sre_004',2500.00,'2021-06-01 12:00:00'),
(204,'sre_002',2000.00,'2021-06-01 12:00:00'),
(205,'sre_003',600.00,'2021-06-02 12:00:00');

验证

  • 查询分布式表的数据是否完整
  • 相同分片的副本是否一致

如上两点验证通过则分片集群部署完毕,一切就绪!

# 查看分布式表
clickhouse-1 :) SELECT * FROM st_order_mt_all2;

SELECT *
FROM st_order_mt_all2

Query id: 503aaa31-a7bf-4388-92b5-2760d4c843bf

┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 205 │ sre_003 │       600.00 │ 2021-06-02 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘
┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 202 │ sre_002 │      2000.00 │ 2021-06-01 12:00:00 │
│ 204 │ sre_002 │      2000.00 │ 2021-06-01 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘
┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 201 │ sre_001 │      1000.00 │ 2021-06-01 12:00:00 │
│ 203 │ sre_004 │      2500.00 │ 2021-06-01 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘

5 rows in set. Elapsed: 0.013 sec. 

# 查看第一个分片的副本数据
clickhouse-1 :) SELECT * FROM st_order_mt;

SELECT *
FROM st_order_mt

Query id: 52e669b2-5e94-42f2-969d-2c8d4829b83d

┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 205 │ sre_003 │       600.00 │ 2021-06-02 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘

1 rows in set. Elapsed: 0.003 sec.

clickhouse-2 :) SELECT * FROM st_order_mt;

SELECT *
FROM st_order_mt

Query id: bfa393ef-b317-4cc7-8849-5d52dbf317e3

┌──id─┬─sku_id──┬─total_amount─┬─────────create_time─┐
│ 205 │ sre_003 │       600.00 │ 2021-06-02 12:00:00 │
└─────┴─────────┴──────────────┴─────────────────────┘

1 rows in set. Elapsed: 0.004 sec. 
0

评论区