ClickHouse高可用集群的安装与部署

前言

ClickHouse是“俄罗斯Google”——Yandex公司在2016年开源的面向OLAP的列式存储数据库,近来发展非常迅猛,国内很多大厂都在生产环境中广泛使用。随着业务体量的扩张,我们的业务人员逐渐有了分析海量用户行为和点击流数据的需求,经过各种调研,最终敲定ClickHouse为最佳方案(成功挤掉了之前有丰富实操经验的Kudu哈哈)。

本文就来记录一个ClickHouse开发测试集群的安装与部署过程。

前置条件

  • 7台阿里云ECS,每台52 vCPU,192GB内存,3TB * 4云盘(测试业务都是混布的,所以请不要太在意节点规格=。=)
  • 操作系统CentOS 7.5
  • 配置SSH互信,修改ulimit,关闭防火墙和虚拟内存等等,不再赘述
  • ClickHouse版本19.16.14.65

下载并安装RPM包

先安装依赖项。

yum -y install libicu perl-JSON-XS

ClickHouse的RPM包由Altinity提供,可以直接wget到服务器上。

wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-server-common-19.16.14.65-1.el7.x86_64.rpm/download.rpm
wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-common-static-19.16.14.65-1.el7.x86_64.rpm/download.rpm
wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-server-19.16.14.65-1.el7.x86_64.rpm/download.rpm
wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-debuginfo-19.16.14.65-1.el7.x86_64.rpm/download.rpm
wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-test-19.16.14.65-1.el7.x86_64.rpm/download.rpm
wget --content-disposition https://packagecloud.io/Altinity/clickhouse/packages/el/7/clickhouse-client-19.16.14.65-1.el7.x86_64.rpm/download.rpm

然后安装之。

rpm -ivh clickhouse-server-common-19.16.14.65-1.el7.x86_64.rpm
rpm -ivh clickhouse-common-static-19.16.14.65-1.el7.x86_64.rpm
rpm -ivh clickhouse-server-19.16.14.65-1.el7.x86_64.rpm
rpm -ivh clickhouse-debuginfo-19.16.14.65-1.el7.x86_64.rpm
rpm -ivh clickhouse-test-19.16.14.65-1.el7.x86_64.rpm
rpm -ivh clickhouse-client-19.16.14.65-1.el7.x86_64.rpm

安装完毕后,启动脚本clickhouse-server位于/etc/init.d目录下,而主要的配置文件config.xml、users.xml位于/etc/clickhouse-server目录下。

高可用拓扑

ClickHouse与ElasticSearch类似,也有数据分片(shard)和副本(replica)的概念。但是ClickHouse只允许一个实例持有一个分片,所以在生产环境中,一般采用两个甚至多个对等的集群互相复制和热备(依靠ReplicatedMergeTree引擎族实现复制表),当某集群上的某节点挂掉后,可以由其他集群上持有对应分片的节点顶上,实现高可用。

但是,我们现在手上只有一个7节点的小集群,并且尚处在试运行阶段,没有必要大动干戈,所以可以采用每个节点启动两个ClickHouse实例,且每个分片的两个副本都位于相邻节点上的“环形副本”(circular replication)拓扑方案,如下图所示,很容易理解。

当然,在实际生产环境中,还是强烈推荐使用对等集群实现高可用。

配置config.xml

config.xml包含了除用户、配额设置之外的所有与ClickHouse服务相关的配置项。首先将它复制一份出来并命名为config2.xml,作为节点上另一个实例的配置。

cp config.xml config2.xml

注意,config.xml中可以使用<include_from>标签引入外部XML文件的配置(ClickHouse习惯上将其命名为metrika.xml),如集群、ZooKeeper配置等,并在其他标签中使用incl属性直接引用之。但这并非强制的规范,因此我们没有新建metrika.xml文件,全部直接在config.xml里写了。

config.xml、config2.xml相同的配置项

ClickHouse集群节点配置

按照上文的图示来配置如下的7分片2副本方案,两个实例分别占用9000和9001端口。这两个端口也分别是同机两个ClickHouse实例的TCP端口,下文会说。

    <remote_servers>
        <sht_ck_cluster_1>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node001</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node002</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node002</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node003</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node003</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node004</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node004</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node005</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node005</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node006</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node006</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node007</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
            <shard>
                <weight>1</weight>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>ck-node007</host>
                    <port>9000</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
                <replica>
                    <host>ck-node001</host>
                    <port>9001</port>
                    <user>default</user>
                    <password>default</password>
                </replica>
            </shard>
        </sht_ck_cluster_1>
    </remote_servers>
  • sht_ck_cluster_1是集群标识,可以自行规定,在创建分布式表(引擎为Distributed)时需要用到。
  • weight表示每个分片的写入权重值,数据写入时会有较大概率落到weight值较大的分片,这里全部设为1。
  • internal_replication表示是否启用内部复制,即写入数据时只写入到一个副本,其他副本的同步工作靠复制表和ZooKeeper异步进行,显然设为true是科学的。
ZK集群节点配置

ClickHouse的复制表强依赖于ZooKeeper(作为元数据存储)。我们直接复用了原本存在的3节点ZK集群。

    <zookeeper>
        <node index="1">
            <host>zk-node001</host>
            <port>2181</port>
        </node>
        <node index="2">
            <host>zk-node002</host>
            <port>2181</port>
        </node>
        <node index="3">
            <host>zk-node003</host>
            <port>2181</port>
        </node>
    </zookeeper>
数据压缩配置

这里只是取消了原来的注释而已。

    <compression>
        <!-- Set of variants. Checked in order. Last matching case wins. If nothing matches, lz4 will be used. -->
        <case>
            <!-- Conditions. All must be satisfied. Some conditions may be omitted. -->
            <min_part_size>10000000000</min_part_size>        <!-- Min part size in bytes. -->
            <min_part_size_ratio>0.01</min_part_size_ratio>   <!-- Min size of part relative to whole table size. -->

            <!-- What compression method to use. -->
            <method>lz4</method>
        </case>
    </compression>
  • min_part_size是可被压缩的数据块的最小大小,默认值10GB。
  • min_part_size_ratio是可被压缩的数据块占全表大小的最小比例,默认值1%。
  • method是压缩算法,可选lz4和zstd。
连接、并发查询配置

由于并非真正的线上集群,并且集群里还有HDFS等服务在跑,所以设得比较小一些。

    <max_connections>128</max_connections>
    <keep_alive_timeout>3</keep_alive_timeout>
    <max_concurrent_queries>16</max_concurrent_queries>

ClickHouse本身也不是为了密集OLTP查询而设计的,所以最大并发查询数不会很大,默认值为100。

时区配置
    <timezone>Asia/Shanghai</timezone>

config.xml、config2.xml不同的配置项

为了方便对比,以下都贴截图,左侧为config.xml,右侧为config2.xml。 截图会被压糊,还是文本吧= =

日志配置

注意要写到不同的路径下。

  • config.xml
    <logger>
        <!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
        <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>
        <!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
    </logger>
  • config2.xml
    <logger>
        <!-- Possible levels: https://github.com/pocoproject/poco/blob/develop/Foundation/include/Poco/Logger.h#L105 -->
        <level>trace</level>
        <log>/var/log/clickhouse-server2/clickhouse-server2.log</log>
        <errorlog>/var/log/clickhouse-server2/clickhouse-server2.err.log</errorlog>
        <size>1000M</size>
        <count>10</count>
        <!-- <console>1</console> --> <!-- Default behavior is autodetection (log to console if not daemon mode and is tty) -->
    </logger>
端口配置

包含HTTP、TCP、节点间通信的端口。注意TCP端口分别与上文副本配置的端口号一致,HTTP和节点间通信端口不要与副本的端口冲突。

  • config.xml
    <http_port>8123</http_port>
    <tcp_port>9000</tcp_port>
    <interserver_http_port>9009</interserver_http_port>
  • config2.xml
    <http_port>8124</http_port>
    <tcp_port>9001</tcp_port>
    <interserver_http_port>9010</interserver_http_port>
目录路径配置

包含数据目录、临时目录、用户文件目录和输入schema目录,两个实例各使用一块硬盘(分别挂载到/data3和/data4)。

  • config.xml
    <path>/data3/clickhouse/data/</path>
    <tmp_path>/data3/clickhouse/tmp/</tmp_path>
    <user_files_path>/data3/clickhouse/user_files/</user_files_path>
    <format_schema_path>/data3/clickhouse/format_schemas/</format_schema_path>
  • config2.xml
    <path>/data4/clickhouse/data/</path>
    <tmp_path>/data4/clickhouse/tmp/</tmp_path>
    <user_files_path>/data4/clickhouse/user_files/</user_files_path>
    <format_schema_path>/data4/clickhouse/format_schemas/</format_schema_path>
复制表宏(macros)配置

该配置在每个节点的每个实例上都不同,且可以自有配置。这里可以包含3个元素:

  • layer:复制表的层级。在大型集群(比如ClickHouse的发源地Yandex.Metrica)中可能会有多级备份,不过我们自然只有1级了。
  • shard:实例所持有的分片ID。
  • replica:实例所持有的副本ID。

这样,我们在使用ReplicatedMergeTree引擎族创建表时,就不必在ZK路径里分别指定这些值,直接用{layer}、{shard}、{replica}等替代即可。通过“高可用规划”一节的图,就可以写出对应的配置。以node001节点为例:

  • config.xml
    <macros>
        <layer>01</layer>
        <shard>01</shard>
        <replica>01-01-1</replica>
    </macros>
  • config2.xml
    <macros>
        <layer>01</layer>
        <shard>07</shard>
        <replica>01-07-2</replica>
    </macros>

副本的命名采用了{layer}-{shard}-{replica序号}的方式,更易读。

配置users.xml

users.xml包含了用户、配额设置。结构比较简单,直接贴全文吧。

<?xml version="1.0"?>
<yandex>
    <!-- Profiles of settings. -->
    <profiles>
        <!-- Default settings. -->
        <default>
            <max_threads>8</max_threads>
            <!-- Maximum memory usage for processing single query, in bytes. -->
            <max_memory_usage>8000000000</max_memory_usage>

            <!-- Use cache of uncompressed blocks of data. Meaningful only for processing many of very short queries. -->
            <use_uncompressed_cache>0</use_uncompressed_cache>

            <load_balancing>random</load_balancing>
        </default>
        <!-- Profile that allows only read queries. -->
        <readonly>
            <max_threads>8</max_threads>
            <max_memory_usage>8000000000</max_memory_usage>
            <use_uncompressed_cache>0</use_uncompressed_cache>

            <load_balancing>random</load_balancing>
            <readonly>1</readonly>
        </readonly>
    </profiles>

    <!-- Users and ACL. -->
    <users>
        <!-- If user name was not specified, 'default' user is used. -->
        <default>
            <password_sha256_hex>37a8eec1ce19687d132fe29051dca629d164e2c4958ba141d5f4133a33f0688f</password_sha256_hex>

            <networks incl="networks" replace="replace">
                <ip>::/0</ip>
            </networks>

            <!-- Settings profile for user. -->
            <profile>default</profile>

            <!-- Quota for user. -->
            <quota>default</quota>
        </default>
    </users>

    <!-- Quotas. -->
    <quotas>
        <!-- Name of quota. -->
        <default>
            <!-- Limits for time interval. You could specify many intervals with different limits. -->
            <interval>
                <!-- Length of interval. -->
                <duration>3600</duration>

                <!-- No limits. Just calculate resource usage for time interval. -->
                <queries>0</queries>
                <errors>0</errors>
                <result_rows>0</result_rows>
                <read_rows>0</read_rows>
                <execution_time>0</execution_time>
            </interval>
        </default>
    </quotas>
</yandex>

这里基本上采用了默认设置,即用户名、密码、profile和配额设置均为default。注意写密码时用SHA256加密后的值:

echo -n 'default' | sha256sum | tr -d '-'

另外,需要根据集群实际情况配置max_threads(单个查询能使用的最多线程数)以及max_memory_usage(单个查询能使用的最多内存量)参数。

修改启动脚本

将原始的启动脚本clickhouse-server复制一份。

cp clickhouse-server clickhouse-server2

clickhouse-server修改数据目录:

CLICKHOUSE_DATADIR_OLD=/data3/clickhouse/data_old
CLICKHOUSE_DATADIR=/data3/clickhouse/data

clickhouse-server2除了修改数据目录之外,还得修改日志、配置、PID和cron文件:

CLICKHOUSE_LOGDIR=/var/log/clickhouse-server2
CLICKHOUSE_DATADIR_OLD=/data4/clickhouse/data_old
CLICKHOUSE_DATADIR=/data4/clickhouse/data
CLICKHOUSE_CRONFILE=/etc/cron.d/clickhouse-server2
CLICKHOUSE_CONFIG=$CLICKHOUSE_CONFDIR/config2.xml
CLICKHOUSE_PIDFILE="$CLICKHOUSE_PIDDIR/$PROGRAM-2.pid"

启动、试运行

推荐先手动把前文涉及到的各种目录(数据目录之类的)mkdir出来,然后再启动。

service clickhouse-server start
service clickhouse-server2 start

在任一节点上打开一个客户端,查询system.clusters系统表,可以得到正确的集群分片和副本信息。

~ clickhouse-client -m -h 127.0.0.1 --password default --port 9000
ClickHouse client version 19.16.14.65.
Connecting to 127.0.0.1:9000 as user default.
Connected to ClickHouse server version 19.16.14 revision 54427.

testdev1-bigdata-ck-node001 :) select * from system.clusters;

SELECT *
FROM system.clusters

┌─cluster──────────┬─shard_num─┬─shard_weight─┬─replica_num─┬─host_name───────────────────┬─host_address─┬─port─┬─is_local─┬─user────┬─default_database─┬─errors_count─┬─estimated_recovery_time─┐
│ sht_ck_cluster_1 │         1 │            1 │           1 │ testdev1-bigdata-ck-node001 │ 10.1.17.3    │ 9000 │        1 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         1 │            1 │           2 │ testdev1-bigdata-ck-node002 │ 10.1.17.4    │ 9001 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         2 │            1 │           1 │ testdev1-bigdata-ck-node002 │ 10.1.17.4    │ 9000 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         2 │            1 │           2 │ testdev1-bigdata-ck-node003 │ 10.1.17.252  │ 9001 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         3 │            1 │           1 │ testdev1-bigdata-ck-node003 │ 10.1.17.252  │ 9000 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         3 │            1 │           2 │ testdev1-bigdata-ck-node004 │ 10.1.17.251  │ 9001 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         4 │            1 │           1 │ testdev1-bigdata-ck-node004 │ 10.1.17.251  │ 9000 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         4 │            1 │           2 │ testdev1-bigdata-ck-node005 │ 10.1.17.2    │ 9001 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         5 │            1 │           1 │ testdev1-bigdata-ck-node005 │ 10.1.17.2    │ 9000 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         5 │            1 │           2 │ testdev1-bigdata-ck-node006 │ 10.1.17.1    │ 9001 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         6 │            1 │           1 │ testdev1-bigdata-ck-node006 │ 10.1.17.1    │ 9000 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         6 │            1 │           2 │ testdev1-bigdata-ck-node007 │ 10.1.17.250  │ 9001 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         7 │            1 │           1 │ testdev1-bigdata-ck-node007 │ 10.1.17.250  │ 9000 │        0 │ default │                  │            0 │                       0 │
│ sht_ck_cluster_1 │         7 │            1 │           2 │ testdev1-bigdata-ck-node001 │ 10.1.17.3    │ 9001 │        0 │ default │                  │            0 │                       0 │
└──────────────────┴───────────┴──────────────┴─────────────┴─────────────────────────────┴──────────────┴──────┴──────────┴─────────┴──────────────────┴──────────────┴─────────────────────────┘

14 rows in set. Elapsed: 0.001 sec. 

到此为止,一个高可用的ClickHouse集群就建立好了。

The End

关于复制表、分布式表的原理和演示,就留到下一篇来写吧,这篇已经够长了。

看天气好像要下雨了,春雨贵如油。

民那晚安。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,117评论 4 360
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 66,963评论 1 290
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 107,897评论 0 240
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,805评论 0 203
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,208评论 3 286
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,535评论 1 216
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,797评论 2 311
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,493评论 0 197
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,215评论 1 241
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,477评论 2 244
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 31,988评论 1 258
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,325评论 2 252
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 32,971评论 3 235
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,055评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,807评论 0 194
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,544评论 2 271
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,455评论 2 266

推荐阅读更多精彩内容