最近用于OLAP场景的列式数据库ClickHouse挺火的,这里简单讲一下安装,部署和使用。不过阿里云都有SaaS版直接使用了,没有的才要自己搭🤡

单机版

1. 安装部署

官方文档

单机安装,怎么快怎么来,实际上就这些:

sudo apt-get install apt-transport-https ca-certificates dirmngr
sudo apt-key adv --keyserver hkp://keyserver.ubuntu.com:80 --recv E0C56BD4

echo "deb https://repo.clickhouse.tech/deb/stable/ main/" | sudo tee \
    /etc/apt/sources.list.d/clickhouse.list
sudo apt-get update

sudo apt-get install -y clickhouse-server clickhouse-client

sudo service clickhouse-server start
clickhouse-client

2. 启动命令

如果找不到service的话,debian可以直接去这目录,另外也可以看看实际启动命令是啥,

启动:

$debian /usr/sbin/service clickhouse-server start

# 启动配置见
vim /etc/systemd/system/clickhouse-server.service

3. 配置文件

存储配置

这里是参考官方文档抄的存储策略,直接写在config.d目录下的storage.xml
(默认SSD,触发条件时迁移hdd)

<yandex>
    <storage_configuration>
        <disks>
            <fast_ssd>
                <path>/data/fast_ssd/</path>
            </fast_ssd>
            <hdd1>
                <path>/home/clickhouse/hdd1/</path>
            </hdd1>
        </disks>
        <policies>
            <moving_from_ssd_to_hdd>
                <volumes>
                    <hot>
                        <disk>fast_ssd</disk>
                        <max_data_part_size_bytes>1073741824</max_data_part_size_bytes>
                    </hot>
                    <cold>
                        <disk>hdd1</disk>
                    </cold>
                </volumes>
                <move_factor>0.2</move_factor>
            </moving_from_ssd_to_hdd>
        </policies>
    </storage_configuration>
</yandex>

4. 建表

举个例子(实际使用必须确定清楚表引擎聚合函数),这里只是现场想个例子展示预聚合用法:

  • 表引擎使用: MergeTree,简单聚合函数
  • order by就是主键了
  • 按时间分区
  • 存储策略是优先SSD,上面那个
  • 存储时间两个月
create table test.user_info
(
    record_time DateTime('Asia/Shanghai'),
    user String,
    cost Float64
)ENGINE = MergeTree()
ORDER BY (record_time,user)
PARTITION BY record_time
SETTINGS storage_policy = 'moving_from_ssd_to_hdd'
TTL record_time + INTERVAL 2 MONTH

-- 创建物化视图,比如每天每个用户cost总量
CREATE MATERIALIZED VIEW user_info_daily_mv
ENGINE = SummingMergeTree()
PARTITION BY toYYYYMM(day)
SETTINGS storage_policy = 'moving_from_ssd_to_hdd'
ORDER BY (day,user)
AS SELECT
    toStartOfDay(record_time) AS day,
    user ,
    sum(cost) as cost_count
FROM test.user_info
GROUP BY (day,user)

集群版(带副本)

1. zookeeper集群部署

正式环境貌似要设置zookeeper的日志清理

测试用compose直接起

version: '3.1'

services:
  zoo1:
    image: zookeeper
    restart: always
    hostname: zoo1
    ports:
      - 2181:2181
    environment:
      ZOO_MY_ID: 1
      ZOO_SERVERS: server.1=0.0.0.0:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo2:
    image: zookeeper
    restart: always
    hostname: zoo2
    ports:
      - 2182:2181
    environment:
      ZOO_MY_ID: 2
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=0.0.0.0:2888:3888;2181 server.3=zoo3:2888:3888;2181

  zoo3:
    image: zookeeper
    restart: always
    hostname: zoo3
    ports:
      - 2183:2181
    environment:
      ZOO_MY_ID: 3
      ZOO_SERVERS: server.1=zoo1:2888:3888;2181 server.2=zoo2:2888:3888;2181 server.3=0.0.0.0:2888:3888;2181

手动安装

这部分删了,手动装挺麻烦的,这部分不大确定,虽然是能跑起来

2. 安装clickhouse

同上

3. 更新配置(2分片2副本)

不建议一个clickhouse-server拥有两个replicas来自不同shard。(除了性能问题,还会存在分布式DDL无法使用)
CIRCULAR REPLICATION CLUSTER TOPOLOGY IN CLICKHOUSE中的设计和github上issue所提的问题

即每台机器是代表某个分片的某个副本

所有配置文件

  • config.xml (主配置文件)
  • users.xml (用户及配置限制)
  • storeage.xml (存储与策略配置)
  • metrika.xml(集群配置)

config.xml (主配置文件)

<listen_host>0.0.0.0</listen_host>

storage.xml (存储与策略配置)

见单机版,冷热数据划分,实际规则

  • part超过1G的迁移
  • ssd快不够容量时迁移

user.xml(用户配置)

metrika.xml文件(cluster配置)

  • 申请4台机器,两个分片,2个副本
  • 1和2的机器在同一个分片下,3和4在同一个分片下
<yandex>
    <remote_servers>
        <test_cluster>
            <shard>
                <!-- <secret></secret> -->
                <!-- Optional. Shard weight when writing data. Default: 1. -->
                <weight>1</weight>
                <!-- Optional. Whether to write data to just one of the replicas. Default: false (write data to all replicas). -->
                <internal_replication>true</internal_replication>
                <replica>
                    <!-- Optional. Priority of the replica for load balancing (see also load_balancing setting). Default: 1 (less value has more priority). -->
                    <!-- <priority>1</priority> -->
                    <host>xx.xxx.xx.xx1</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>xx.xxx.xx.xx2</host>
                    <port>9000</port>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>xx.xxx.xx.xx3</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>xx.xxx.xx.xx4</host>
                    <port>9000</port>
                </replica>
            </shard>
        </test_cluster>
    </remote_servers>

    <!-- 这里其实就是标记当前机器属于哪个shard,以及副本代号 -->
    <macros>
        <shard>01</shard>
        <replica>xx.xxx.xx.xx1<replica>
    </macros>

    <!-- ZK-->
    <zookeeper>
        <node index="1">
            <host>xx.xxx.xx.xx1</host>
            <port>2181</port>
        </node>
        <node index="2">
            <host>xx.xxx.xx.xx2</host>
            <port>2182</port>
        </node>
        <node index="3">
            <host>xx.xxx.xx.xx3</host>
            <port>2183</port>
        </node>
    </zookeeper>
    
</yandex>

宏定义(统一建表语句)

这里不设置layer层了,没必要

记得每个节点都必须更新这个!!!

注意同一个shard的节点的shard配置必须一致!!

<macros>
    <shard>01</shard>
    <replica>hostname</replica>
</macros>

最终配置文件

丢到config.d目录下覆盖默认配置

  • xxx.xml(合并了listen配置和storeage配置)
  • metrika.xml(单独,这部分是热更新,无需重启)

用户配置丢到user.d目录下覆盖默认配置

  • users.xml

集群样例

具体可以去查看system的cluster表,看看集群配置是否生效了

4. 每个节点启动click server(确定互通)

  • 9000端口用于clickhouse互通与clickhouse-client
  • 8123端口为http访问

5. 建表

/*分布式DDL建库*/
CREATE DATABASE test ON CLUSTER 'test_cluster'

/*分布式DDL建库,树引擎其实可以不写,就是默认值来的*/
CREATE TABLE test.test_info_local ON CLUSTER 'test_cluster'(
    ......
)ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/test/test_info_local','{replica}')
PARTITION BY record_time
ORDER BY (record_time)
TTL record_time + INTERVAL 6 MONTH
SETTINGS storage_policy = 'moving_from_ssd_to_hdd'

/*分布式DDL建立原始数据分布表*/
CREATE TABLE  test.test_info_local on CLUSTER 'test_cluster'
as test.test_info
ENGINE = Distributed(test_cluster,test,test_info_local,rand())

/*以下不写了,基本看官方文档详细点*/
/*物化视图有实际table的,只不过默认隐藏,我们也可以手动创建*/


/*分布式DDL创建物化视图*/
/*这里因为提前建好复制表了,不需要再设置engine那些*/



/**分布式DDL 创建全局视图*/

  • 分布式DDL跑一次就够了

6. 实际应用

写本地表

最好直接写本地表,因为直接写分布式表,在clickhouse上还要再同步一次,实际上相当于双写了

读分布式表

7. 测试

性能方面简单的可以看官方说明,尽量批量写,这里其实还会涉及到clickhouse里part的概念,不细说了

We recommend inserting data in packets of at least 1000 rows, or no more than a single request per second.

8. 个人经验

  • 表引擎要留意清楚,个人一般使用最多的是SummingMergeTree或者AggregatingMergeTree,分布式就加个replica前缀
  • clickhouse允许相同主键的数据存在,是否去重以及去重的规则具体看表引擎决定。
  • clickhouse不保证part merge的时机,这个是坑,某些实际应用场景时就会感受到的
  • 可以对视图再进行视图的聚合,不过要注意,本质上是insert事件触发了视图,视图并不知道原表的数据
  • 分布式用到zookeeper(这玩意还是没那么好用),这里依赖它主要是在分布式DDL执行和ReplicaMergeTree主备状态同步上(对于每个insert的数据part,clickhouse都会通过几个事务将记录添加到zookeeper上)

有问题欢迎留言~