3. 部署与配置:单机部署、集群部署与配置项深度解析
部署 ClickHouse,说简单也简单,说复杂也复杂。单机环境几分钟就能跑起来,但真要上生产集群,坑就多了。我最早接触 ClickHouse 时,觉得它跟 MySQL 差不多,结果在 ZooKeeper 上栽了个大跟头。今天咱们就把部署这件事聊透。
3.1 单机部署:从零到可查询
单机部署是基础。我个人习惯用 RPM 包或 DEB 包,干净利落。当然,Docker 也行,但生产环境我建议走系统包管理。
核心要点:单机部署不需要 ZooKeeper,数据只存一份,没有副本概念。适合开发测试、小规模分析场景。
3.1.1 安装步骤(CentOS 为例)
# 添加官方仓库
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://packages.clickhouse.com/rpm/clickhouse.repo
# 安装服务端和客户端
sudo yum install -y clickhouse-server clickhouse-client
# 启动服务
sudo systemctl start clickhouse-server
sudo systemctl enable clickhouse-server
# 验证连接
clickhouse-client --query "SELECT version()"
安装完第一件事是什么?改密码。默认配置是空密码,这在生产环境等于裸奔。我曾经见过一个团队,上线两周才发现数据被人删了——就是因为没改默认密码。
3.1.2 关键配置文件
单机模式下,你主要关注两个文件:
| 文件路径 | 作用 |
|---|---|
/etc/clickhouse-server/config.xml |
主配置,监听端口、数据目录、内存限制等 |
/etc/clickhouse-server/users.xml |
用户权限、密码、资源配额 |
小技巧:别直接改 config.xml。在 /etc/clickhouse-server/config.d/ 下建一个 .xml 文件,覆盖你需要的配置项。这样升级时不会丢失自定义配置。
3.2 集群部署:基于 ZooKeeper / ClickHouse Keeper
集群部署才是重头戏。ClickHouse 的集群依赖一个分布式协调服务来管理副本状态、DDL 同步、分区挂载等。早期只能用 ZooKeeper,现在有了 ClickHouse Keeper——说白了就是 ClickHouse 自己重写的一个 ZooKeeper 兼容服务。
3.2.1 架构概览
先看一张整体架构图,帮你建立全局认知:
3.2.2 ZooKeeper vs ClickHouse Keeper
怎么选?我直接给结论:新项目无脑上 ClickHouse Keeper。为什么?
| 对比项 | ZooKeeper | ClickHouse Keeper |
|---|---|---|
| 部署复杂度 | 需要单独维护 Java 环境 | 随 ClickHouse 一起安装,无额外依赖 |
| 资源消耗 | 内存占用高,GC 问题多 | C++ 实现,内存可控 |
| 读写性能 | 一般,大分区下容易超时 | 快 2-3 倍,我实测过 |
| 运维成本 | 需要专人维护 ZK 集群 | 运维 ClickHouse 即可 |
避坑:如果你已经在用 ZooKeeper,迁移到 Keeper 时要小心。我曾经在迁移过程中遇到版本不兼容的问题——旧版 ClickHouse 的某些 DDL 操作依赖 ZK 的特定行为,Keeper 实现有细微差异。建议先在测试环境跑一周。
3.2.3 集群配置示例
假设你有 3 台机器,每台部署一个 ClickHouse 实例和一个 Keeper 实例。配置如下:
第一步:配置 Keeper(每个节点)
<!-- /etc/clickhouse-server/config.d/keeper.xml -->
<clickhouse>
<keeper_server>
<tcp_port>9181</tcp_port>
<server_id>1</server_id> <!-- 每个节点不同:1, 2, 3 -->
<log_storage_path>/var/lib/clickhouse/coordination/log</log_storage_path>
<snapshot_storage_path>/var/lib/clickhouse/coordination/snapshots</snapshot_storage_path>
<coordination_settings>
<operation_timeout_ms>10000</operation_timeout_ms>
<session_timeout_ms>30000</session_timeout_ms>
<raft_logs_level>trace</raft_logs_level>
</coordination_settings>
<raft_configuration>
<server>
<id>1</id>
<hostname>node1.example.com</hostname>
<port>9234</port>
</server>
<server>
<id>2</id>
<hostname>node2.example.com</hostname>
<port>9234</port>
</server>
<server>
<id>3</id>
<hostname>node3.example.com</hostname>
<port>9234</port>
</server>
</raft_configuration>
</keeper_server>
<!-- 启用 Keeper 替代 ZooKeeper -->
<zookeeper>
<node>
<host>node1.example.com</host>
<port>9181</port>
</node>
<node>
<host>node2.example.com</host>
<port>9181</port>
</node>
<node>
<host>node3.example.com</host>
<port>9181</port>
</node>
</zookeeper>
</clickhouse>
第二步:配置集群分片与副本
<!-- /etc/clickhouse-server/config.d/cluster.xml -->
<clickhouse>
<remote_servers>
<my_cluster>
<shard>
<internal_replication>true</internal_replication>
<replica>
<host>node1.example.com</host>
<port>9000</port>
</replica>
<replica>
<host>node2.example.com</host>
<port>9000</port>
</replica>
<replica>
<host>node3.example.com</host>
<port>9000</port>
</replica>
</shard>
</my_cluster>
</remote_servers>
</clickhouse>
注意:internal_replication 设为 true 表示由 ClickHouse 自己管理副本同步,不需要外部工具。这是推荐做法。
3.3 配置项深度解析
配置项太多了,我挑几个最容易踩坑的讲。
3.3.1 内存相关
| 配置项 | 默认值 | 我的建议 |
|---|---|---|
max_memory_usage |
10G | 设为物理内存的 60%-70% |
max_memory_usage_for_all_queries |
0(不限制) | 设为物理内存的 80%,防止 OOM |
max_bytes_before_external_group_by |
0 | 设为 max_memory_usage 的一半,触发磁盘排序 |
嗯,这里要注意。很多人以为内存设得越大越好。其实不是。ClickHouse 的内存管理是「尽力而为」的——它不会像 JVM 那样主动 GC。一旦内存超限,直接 OOM Kill。我遇到过最惨的一次,一个聚合查询把 128G 内存吃满,整个节点挂了,影响了所有查询。
3.3.2 磁盘与合并策略
<merge_tree>
<max_bytes_to_merge_at_max_space_in_pool>107374182400</max_bytes_to_merge> <!-- 100G -->
<max_bytes_to_merge_at_min_space_in_pool>53687091200</max_bytes_to_merge> <!-- 50G -->
<parts_to_throw_insert>300</parts_to_throw_insert>
<parts_to_delay_insert>150</parts_to_delay_insert>
</merge_tree>
这几个参数控制着分区合并的行为。说白了,ClickHouse 写入时生成小分区,后台慢慢合并成大分区。如果写入太快,分区数暴增,查询性能会断崖式下跌。
我曾经遇到一个客户,每秒写入 10 万行,分区数涨到 5000 多,查询直接超时。后来把 parts_to_throw_insert 从 300 调到 600,同时加大了合并线程数,才稳住。
3.3.3 网络与超时
| 配置项 | 说明 | 推荐值 |
|---|---|---|
connect_timeout_with_failover_ms |
节点故障时的连接超时 | 1000(1秒) |
receive_timeout |
接收数据超时 | 300(秒) |
send_timeout |
发送数据超时 | 300(秒) |
避坑:网络超时别设太大。我见过有人设 3600 秒,结果一个节点挂了,所有查询都卡在那等超时,整个集群被拖死。设个合理的值,让查询快速失败,比死等强。
3.4 部署后的验证清单
部署完别急着上线。按这个清单检查一遍:
- 节点连通性:用
clickhouse-client --host测试每个节点 - 集群状态:
SELECT * FROM system.clusters确认所有节点可见 - 副本同步:建一个复制表,写入数据,检查
system.replicas的is_readonly和future_parts - Keeper 健康:
echo ruok | nc localhost 9181返回imok - 权限验证:用非默认用户登录,确认密码生效