ClickHouse 1分片3副本高可用集群:Ansible 自动化部署与 HA 测试全解析
本文基于开源项目 clickhouse_1s3r,完整拆解 ClickHouse 25.8 LTS 在「1分片3副本 + 内置 Keeper」架构下的自动化部署与高可用测试方案。从架构设计、Ansible 编排、核心配置到故障切换原理,一篇讲透。
一、为什么需要 1分片3副本?
在实际的生产场景中,ClickHouse 集群面临的核心挑战是 数据可靠性 和 服务连续性。单节点部署一旦宕机,轻则服务中断,重则数据丢失。1分片3副本(1 Shard × 3 Replicas)架构正是为此而生:
| 特性 | 单节点 | 1分片3副本 |
|---|---|---|
| 数据冗余 | ❌ 无 | ✅ 三副本 |
| 容错能力 | ❌ 0 | ✅ 容忍1节点故障 |
| 读写可用性 | 单点 | 多副本负载分担 |
| 元数据管理 | N/A | Raft 共识(3节点多数派) |
核心架构设计
┌──────────────────────────────────────────┐
│ Distributed 表 (业务入口) │
│ ENGINE = Distributed(...) │
└──────────────────┬───────────────────────┘
│
┌──────────────────┼───────────────────────┐
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Replica1 │ │ Replica2 │ │ Replica3 │
│ (node1) │ │ (node2) │ │ (node3) │
│ Replicated │────▶│ Replicated │────────▶│ Replicated │
│ MergeTree │ │ MergeTree │ │ MergeTree │
└─────┬─────┘ └─────┬─────┘ └─────┬─────┘
│ │ │
┌─────▼─────┐ ┌─────▼─────┐ ┌─────▼─────┐
│ Keeper 1 │ │ Keeper 2 │ │ Keeper 3 │
│ server_id=1│ │ server_id=2│ │ server_id=3│
└───────────┘ └───────────┘ └───────────┘
│ │ │
└────────── Raft 共识协议 ─────────────────┘
关键设计决策:
- 内置 Keeper 替代 ZooKeeper:ClickHouse 25.8 LTS 内置 Keeper 组件,无需额外维护 ZK 集群,大幅降低运维复杂度
- ReplicatedMergeTree + Distributed:本地表用 ReplicatedMergeTree 实现副本同步,分布式表作为业务统一入口
- internal_replication = true:写入只命中一个副本,由副本间自动同步,减少写入放大
- Raft 3节点多数派:容忍最多1个节点故障,保证元数据一致性
二、集群拓扑与端口规划
2.1 节点规划
| 节点 | IP | 主机名 | Keeper ID | 角色 |
|---|---|---|---|---|
| node1 | 192.168.10.201 | xt-wxqb-ck-1 | 1 | shard1-replica1 + Keeper |
| node2 | 192.168.10.202 | xt-wxqb-ck-2 | 2 | shard1-replica2 + Keeper |
| node3 | 192.168.10.203 | xt-wxqb-ck-3 | 3 | shard1-replica3 + Keeper |
2.2 端口规划
| 端口 | 协议 | 用途 |
|---|---|---|
| 9000 | TCP | ClickHouse 客户端连接 |
| 8123 | HTTP | HTTP API / Playground |
| 9009 | TCP | 集群节点间通信 |
| 9181 | TCP | Keeper 客户端 |
| 9234 | TCP | Keeper 内部同步 |
| 9235 | TCP | Keeper Raft |
| 9363 | HTTP | Prometheus 指标 |
注意:Keeper 的
server_id 三节点必须唯一(1/2/3),这是 Raft 选举的基础。配置错误会导致集群无法形成仲裁。
2.3 目录规范
/data/common/ # 程序安装根目录 /data/common/clickhouse # CK 程序目录(软链接→版本目录) /data/common/clickhouse/conf # 配置文件目录 /data/common/clickhouse/logs # 日志目录 /data/clickhouse/ # CK 数据目录 /data/clickhouse/keeper/ # Keeper 数据目录 /data/clickhouse/tmp/ # 临时目录
三、Ansible 自动化部署:项目结构全貌
整个项目采用标准 Ansible Roles 组织,结构清晰:
clickhouse_1s3r/ ├── ansible.cfg # Ansible 全局配置 ├── inventory.ini # 主机清单(节点分组、SSH) ├── group_vars/ │ └── all.yml # 全局变量(版本/端口/路径/密码/Keeper拓扑) ├── playbooks/ │ ├── site.yml # 一键部署入口 │ ├── deploy_cluster.yml # 主部署 Playbook(6个Play) │ ├── ha_test.yml # 高可用测试 Playbook │ └── cleanup_cluster.yml # 集群清理 ├── roles/ │ ├── ck_common/tasks/ # 环境初始化 │ ├── ck_install/tasks/ # 软件安装 │ │ └── templates/ # config.xml / users.xml / systemd │ └── ck_cluster/tasks/ # 集群启动(并行点火) ├── scripts/ │ ├── config.env # Shell 脚本变量 │ ├── ha_test.sh # HA 测试脚本 │ └── test_data_gen.sql # 测试数据 SQL ├── files/ # 离线安装包 └── docs/ # 部署手册 + HA 测试手册
设计亮点
- Roles 分层:
ck_common(环境)→ck_install(安装)→ck_cluster(启动),职责清晰 - Tags 分阶段:支持
--tags=common/install/start/init按需执行 - 模板化配置:
config.xml.j2、users.xml.j2、clickhouse.service.j2全部通过 Jinja2 渲染 - 离线部署:安装包预置于
files/,目标节点无需联网
四、核心配置解读
4.1 inventory.ini — 主机清单
[ck_node1] 192.168.10.201 hostname=xt-wxqb-ck-1 keeper_server_id=1 [ck_node2] 192.168.10.202 hostname=xt-wxqb-ck-2 keeper_server_id=2 [ck_node3] 192.168.10.203 hostname=xt-wxqb-ck-3 keeper_server_id=3 [ck_cluster:children] ck_node1 ck_node2 ck_node3 [all:vars] ansible_user=root ansible_password=xxxx ansible_ssh_common_args='-o StrictHostKeyChecking=no' ansible_become=true ansible_become_method=sudo
每个节点通过主机变量指定 hostname 和 keeper_server_id,Ansible 在渲染配置模板时会自动注入这些值。ck_cluster:children 将三个节点聚合为一个组,便于并行执行。
4.2 group_vars/all.yml — 全局变量
这是整个项目的"控制面板",所有可配置参数集中管理:
# ==================== 集群拓扑 ====================
ck_nodes:
- host: "192.168.10.201"
hostname: "xt-wxqb-ck-1"
shard: "01"
replica: "replica1"
- host: "192.168.10.202"
hostname: "xt-wxqb-ck-2"
shard: "01"
replica: "replica2"
- host: "192.168.10.203"
hostname: "xt-wxqb-ck-3"
shard: "01"
replica: "replica3"
ck_cluster_name: "ck_1s3r_cluster"
# ==================== Keeper 集群参数 ====================
keeper_nodes:
- server_id: 1
host: "xt-wxqb-ck-1"
ip: "192.168.10.201"
- server_id: 2
host: "xt-wxqb-ck-2"
ip: "192.168.10.202"
- server_id: 3
host: "xt-wxqb-ck-3"
ip: "192.168.10.203"
# ==================== 性能与存储参数 ====================
ck_max_memory_usage: "10G"
ck_max_server_memory: "16G"
ck_compression_method: "zstd"
ck_compression_level: 3
复用提示:修改ck_nodes和keeper_nodes的 IP/主机名,即可适配不同环境。端口、密码、路径等参数也都在此文件统一修改。
4.3 部署 Playbook — 6 个 Play 的编排逻辑
deploy_cluster.yml 是部署核心,按以下顺序执行:
# Play 1: 环境初始化 — 3节点并行
- name: 1. 环境初始化 - 所有 ClickHouse 节点
hosts: ck_cluster
roles:
- role: ck_common
tags: [common, prepare]
# Play 2: 安装 ClickHouse — 3节点并行
- name: 2. 安装 ClickHouse - 所有节点 (并行)
hosts: ck_cluster
roles:
- role: ck_install
tags: [install]
# Play 3: 启动集群 — 3节点并行点火
- name: 3. 启动 ClickHouse - 3节点并行点火
hosts: ck_cluster
roles:
- role: ck_cluster
tags: [start]
# Play 4: 等待 Keeper 仲裁 + 初始化 DDL
- name: 4. 等待 Keeper 仲裁形成并初始化 DDL
hosts: ck_node1
tags: [init]
tasks:
- name: 等待 Keeper 仲裁形成 (最多等待 5 分钟)
command: >
{{ ck_install_dir }}/bin/clickhouse-client
-u {{ ck_admin_user }} --password '{{ ck_default_password }}'
--query "SELECT 1"
register: keeper_check
until: keeper_check.rc == 0
retries: 60
delay: 5
- name: 创建 ReplicatedMergeTree 本地表
command: >
{{ ck_install_dir }}/bin/clickhouse-client
--query "
CREATE TABLE IF NOT EXISTS test.data_local ON CLUSTER {{ ck_cluster_name }}
(id UInt64, dt DateTime, msg String)
ENGINE = ReplicatedMergeTree('/clickhouse/tables/{shard}/test/data_local', '{replica}')
PARTITION BY toYYYYMM(dt)
ORDER BY id;
"
- name: 创建 Distributed 分布式表
command: >
{{ ck_install_dir }}/bin/clickhouse-client
--query "
CREATE TABLE IF NOT EXISTS test.data_dist ON CLUSTER {{ ck_cluster_name }}
(id UInt64, dt DateTime, msg String)
ENGINE = Distributed('{{ ck_cluster_name }}', 'test', 'data_local', rand());
"
编排逻辑解析:
| Play | 主机范围 | 执行方式 | 核心动作 |
|---|---|---|---|
| 1 | ck_cluster(3台) | 并行 | hosts解析、关防火墙/SELinux、创建用户/目录、内核参数优化、禁用THP |
| 2 | ck_cluster(3台) | 并行 | 上传解压安装包、创建软链接、渲染config.xml/users.xml、部署systemd |
| 3 | ck_cluster(3台) | 并行 | systemctl start --no-block 三节点同时点火 |
| 4 | ck_node1(单台) | 串行 | 等待Keeper仲裁→建库建表→插入验证数据 |
| 5 | ck_node1(单台) | 串行 | 输出集群节点/Keeper/副本状态 |
| 5.1 | ck_cluster(3台) | 并行 | 各节点查询本地表,验证数据一致性 |
| 6 | ck_node1(单台) | 串行 | 输出部署完成Banner(连接信息) |
为什么三节点并行启动? Keeper 基于 Raft 协议,需要多数派(2/3)节点在线才能形成仲裁。如果逐台启动,先启动的节点会一直等待其他节点,导致超时。并行启动让 Keeper 尽快达成 quorum。
五、一键部署实战
5.1 前置准备
# 1. 克隆项目 git clone https://github.com/eagle-qi/clickhouse_1s3r.git cd clickhouse_1s3r # 2. 放置离线安装包(约178MB) cp /path/to/clickhouse-25.8.28.1-lts-x86_64.tgz files/ # 3. 修改配置 vim inventory.ini # SSH 连接信息 vim group_vars/all.yml # 集群参数(密码等)
5.2 测试连通性
ansible -i inventory.ini ck_cluster -m ping
预期输出:
192.168.10.201 | SUCCESS => { "changed": false, "ping": "pong" }
192.168.10.202 | SUCCESS => { "changed": false, "ping": "pong" }
192.168.10.203 | SUCCESS => { "changed": false, "ping": "pong" }
5.3 一键部署
# 完整部署 ansible-playbook -i inventory.ini playbooks/site.yml # 或分阶段执行 ansible-playbook -i inventory.ini playbooks/deploy_cluster.yml --tags=common # 仅环境初始化 ansible-playbook -i inventory.ini playbooks/deploy_cluster.yml --tags=install # 仅安装软件 ansible-playbook -i inventory.ini playbooks/deploy_cluster.yml --tags=start # 仅启动集群 ansible-playbook -i inventory.ini playbooks/deploy_cluster.yml --tags=init # 仅初始化DDL
5.4 部署后验证
-- 查看集群节点 SELECT cluster, host_name, host_address, shard_num, replica_num, is_active FROM system.clusters WHERE cluster = 'ck_1s3r_cluster' FORMAT PrettyCompact; -- 查看副本状态 SELECT database, table, replica_name, is_readonly, total_replicas, active_replicas FROM system.replicas FORMAT PrettyCompact;
预期输出:3个节点全部 is_active=1,total_replicas=3,active_replicas=3。
5.5 Keeper 状态检查
# 使用内置 keeper-client 查询(25.8 LTS 推荐方式) echo mntr | /data/common/clickhouse/bin/clickhouse-keeper-client -h 127.0.0.1 -p 9181
关键指标:
zk_server_state— 应为leader或follower,有且仅有1个 leaderzk_num_alive_connections— 活跃连接数zk_approximate_data_size— 元数据大小
六、生产建表最佳实践
6.1 ReplicatedMergeTree 本地表
-- 创建数据库(所有节点)
CREATE DATABASE IF NOT EXISTS your_db ON CLUSTER ck_1s3r_cluster;
-- 创建本地副本表(所有节点)
CREATE TABLE IF NOT EXISTS your_db.your_table_local ON CLUSTER ck_1s3r_cluster
(
id UInt64,
event_time DateTime,
data String
)
ENGINE = ReplicatedMergeTree(
'/clickhouse/tables/{shard}/your_db/your_table_local',
'{replica}'
)
PARTITION BY toYYYYMM(event_time)
ORDER BY (id, event_time)
SETTINGS
compression_method = 'zstd',
compression_level = 3;
6.2 Distributed 分布式表
-- 创建分布式表(业务统一入口)
CREATE TABLE IF NOT EXISTS your_db.your_table_dist ON CLUSTER ck_1s3r_cluster
(
id UInt64,
event_time DateTime,
data String
)
ENGINE = Distributed('ck_1s3r_cluster', 'your_db', 'your_table_local', rand());
6.3 建表规范要点
| 规范 | 说明 |
|---|---|
所有 DDL 加 ON CLUSTER | 保证三节点表结构一致 |
| 业务读写统一操作 Distributed 表 | 规避副本读写不一致 |
| ReplicatedMergeTree 路径用宏 | {shard} 和 {replica} 由 config.xml 宏定义自动替换 |
| 启用 ZSTD 压缩 | compression_method='zstd', compression_level=3,压缩比高、CPU 开销低 |
| 磁盘清理用分区剥离 | ALTER TABLE ... DROP PARTITION,避免大量 DELETE 产生碎片 |
七、高可用测试:5大场景全流程
项目内置了完整的高可用测试方案,支持 Ansible Playbook 和 Shell 脚本 两种方式。
7.1 测试场景一览
| 测试 | 场景 | 验证点 |
|---|---|---|
| 0 | 准备测试数据 | 自动建表 uk.uk_price_paid_local + 插入10行 UK 房价数据 |
| 1 | 数据写入与三副本同步 | 单节点写入 → 三节点均可见 |
| 2 | 单节点宕机 | 剩余2节点读写正常,数据不丢失 |
| 3 | 宕机节点恢复 | 自动从 Keeper 追赶数据,三节点一致 |
| 4 | 双节点同时宕机 | 读可用/写拒绝(Keeper失仲裁),恢复后数据零丢失 |
| 5 | 最终一致性验证 | 全集群数据量、min/max/avg 一致 |
7.2 执行 HA 测试
# 方式一:Ansible 自动化测试 ansible-playbook -i inventory.ini playbooks/ha_test.yml # 方式二:Shell 脚本测试(无需 Ansible 环境) bash scripts/ha_test.sh
7.3 故障切换原理
理解 HA 测试的底层逻辑,核心在于 ClickHouse Keeper 的 Raft 共识 和 ReplicatedMergeTree 的副本同步:
节点宕机 ↓ Keeper 感知失联(session_timeout: 30s) ↓ Raft 多数派继续工作(2/3存活) ↓ 读写请求路由到健康节点 ↓ 宕机节点恢复启动 ↓ Keeper 重新建立会话 ↓ 副本从 Keeper 拉取缺失的 log entries ↓ 追赶上最新状态,标记为 active
关键细节:
- 3节点集群:容忍最多1个节点故障(需 2/3 多数派)
- 双节点宕机时:Keeper 失去仲裁,写入被拒绝,但读在存活节点上仍可用
- Leader 故障:剩余 Follower 自动发起选举,选出新 Leader
- 节点恢复后:自动从 Keeper 拉取缺失的操作日志完成数据追赶
7.4 测试报告
测试完成后自动输出汇总报告:
╔══════════════════════════════════════════════════════════════════╗ ║ ClickHouse 1分片3副本 高可用测试报告 ║ ╠══════════════════════════════════════════════════════════════════╣ ║ 测试1: 数据写入与三副本同步验证 ✓ PASS ║ ║ 测试2: 节点3单独宕机 + 剩余节点读写 ✓ PASS ║ ║ 测试3: 节点3恢复 + 数据自动追同步 ✓ PASS ║ ║ 测试4: 节点1+2同时宕机(双节点) ✓ PASS ║ ║ - 节点3独立读验证 ✓ ║ ║ - 写入预期失败(Keeper失仲裁) ✓ ║ ║ - 双节点恢复 + 全量同步 ✓ ║ ║ 测试5: 全集群最终一致性验证 ✓ PASS ║ ╠══════════════════════════════════════════════════════════════════╣ ║ 结论: 1S3R集群在单节点故障时完全可用, 读写不中断 ║ ║ 双节点宕机时Keeper失去仲裁导致写失败, 读仍可用 ║ ║ 所有节点恢复后数据完整同步零丢失 ║ ╚══════════════════════════════════════════════════════════════════╝
Shell 脚本方式还会在 /tmp/clickhouse_ha_test/ 目录下生成 Markdown 格式的详细报告,包含各节点 Keeper mntr 完整输出和数据统计。
八、常见问题排查
Q1: Keeper 集群无法选举 Leader
# 查看 Keeper 日志 tail -200 /data/common/clickhouse/logs/clickhouse-server.log | grep -i keeper # 检查节点间网络连通性 telnet xt-wxqb-ck-1 9234 telnet xt-wxqb-ck-2 9234 telnet xt-wxqb-ck-3 9234
解决:确保 server_id 三台互不相同(1/2/3),确保 /etc/hosts 解析正确,三节点必须接近同时启动。
Q2: 数据不同步
-- 检查副本状态 SELECT database, table, replica_name, is_session_expired, active_replicas FROM system.replicas; -- 检查集群配置 SELECT * FROM system.clusters WHERE cluster = 'ck_1s3r_cluster';
解决:确认 internal_replication=true,确认 Keeper 集群健康。
Q3: 启动报权限错误
# 确保所有目录归属正确 chown -R zxws:zxws /data/common /data/clickhouse chmod 755 /data/common /data/clickhouse
Q4: 双节点宕机后写入失败
这是 预期行为,不是 Bug。Keeper 基于 Raft 协议,2/3 节点宕机时无法形成多数派仲裁,写入会被拒绝。读操作在存活节点上仍可用。恢复节点后 Keeper 重新形成仲裁,写入自动恢复。
九、生产环境注意事项
| 序号 | 注意事项 |
|---|---|
| 1 | 全程使用 zxws 用户,禁止 root 运行 ClickHouse 进程 |
| 2 | 修改 default 用户密码 为强密码(默认密码仅供测试) |
| 3 | 所有 DDL 加 ON CLUSTER,保证三节点表结构一致 |
| 4 | 业务读写统一操作 Distributed 表,规避副本不一致 |
| 5 | Keeper server_id 必须唯一(1/2/3),否则 Raft 选举异常 |
| 6 | 三节点尽量同时启动,Keeper 需要多数派形成 quorum |
| 7 | 磁盘清理优先用分区剥离,避免大量 DELETE 产生碎片 |
| 8 | Keeper 数据独立存放,禁止与业务数据混用 |
| 9 | 至少保持2个节点在线,运维操作时避免同时停多台 |
| 10 | 定期执行 HA 测试,验证集群高可用能力 |
十、总结
本文完整拆解了基于 ClickHouse 25.8 LTS 的 1分片3副本高可用集群方案,核心要点回顾:
- 架构选择:1分片3副本 + 内置 Keeper,无需 ZooKeeper,运维更轻量
- 自动化部署:Ansible Roles 分层编排,6个 Play 覆盖从环境初始化到验证全流程
- 配置管理:
group_vars/all.yml统一管理所有参数,修改即可适配不同环境 - 高可用验证:5大测试场景覆盖单节点/双节点故障,自动化执行 + 报告生成
- 生产规范:DDL 加 ON CLUSTER、业务走 Distributed 表、ZSTD 压缩、分区剥离清理
项目地址:https://github.com/eagle-qi/clickhouse_1s3r
如果你正在规划 ClickHouse 生产集群部署,或者想验证高可用能力,这个项目可以帮你省去大量重复工作。一键部署,一键测试,开箱即用。
版权声明:本文为原创技术博客,参考开源项目 clickhouse_1s3r 编写。转载请注明出处。
参考 clickhouse 集群部署 - 小吉猫 - 博客园
Replication + scaling | ClickHouse Docs
ClickHouse 3节点集群安装_clickhouse三节点部署-CSDN博客
更多推荐
所有评论(0)