本文档将指导您在 2 台服务器上手动搭建一个高可用的 ClickHouse 单分片、双副本集群,并使用独立的 Apache ZooKeeper 集群作为协调服务。与集成 Keeper 版本的核心区别在于:协调服务(ZooKeeper)与数据服务(ClickHouse Server)是独立部署和维护的。

1. 集群规划与架构 📊

  • 集群模式:单分片(Shard 1)、双副本(Replica 2)

  • 服务器(与之前相同):

    • 172.21.204.200 (ClickHouse 副本 1 + ZooKeeper 节点1、节点3)

    • 172.21.204.201 (ClickHouse 副本 2 + ZooKeeper 节点2)

  • 协调服务:Apache ZooKeeper 独立集群(3个节点)

  • 网络访问:开启 0.0.0.0 监听,支持跨节点与远程访问

  • 架构核心变化:每台服务器运行 clickhouse-server,并在两台服务器上分布3个ZooKeeper进程以实现奇数节点集群。

2. 系统环境准备

2.1 设置主机名与 hosts 解析(两台服务器)

# 在 172.21.204.200 和 172.21.204.201 上分别执行
# 设置主机名(如果未设置)
sudo hostnamectl set-hostname zb-yunweitest-mysql-204-200  # 在200上
sudo hostnamectl set-hostname zb-yunweitest-mysql-204-201  # 在201上

# 编辑 /etc/hosts,在两台服务器上添加相同内容
sudo vim /etc/hosts

添加以下行:

127.0.0.1   localhost localhost.localdomain localhost4 localhost4.localdomain4
172.21.204.200 zb-yunweitest-mysql-204-200 zk1 ch1
172.21.204.201 zb-yunweitest-mysql-204-201 zk2 ch2

2.2 关闭 SELinux(可选,生产环境请按需配置)

# 临时关闭
sudo setenforce 0
# 永久关闭(需要重启)
sudo sed -i ‘s/^SELINUX=enforcing/SELINUX=disabled/’ /etc/selinux/config

2.3 配置防火墙规则

# 在两台服务器上执行,开放所有必需端口
sudo firewall-cmd --permanent --add-port=9000/tcp  # ClickHouse TCP 端口
sudo firewall-cmd --permanent --add-port=8123/tcp  # ClickHouse HTTP 端口
sudo firewall-cmd --permanent --add-port=9009/tcp  # ClickHouse 内部通信
# ZooKeeper 基础端口 (每个实例需要一组)
sudo firewall-cmd --permanent --add-port=2181/tcp  # ZK节点1客户端端口
sudo firewall-cmd --permanent --add-port=2182/tcp  # ZK节点3客户端端口
sudo firewall-cmd --permanent --add-port=2183/tcp  # ZK节点2客户端端口
sudo firewall-cmd --permanent --add-port=2888/tcp  # ZK对等通信基础端口
sudo firewall-cmd --permanent --add-port=3888/tcp  # ZK选举基础端口
sudo firewall-cmd --reload

2.4 系统参数优化

# 调整内核参数
sudo tee -a /etc/sysctl.conf << EOF
# 增加最大文件描述符
fs.file-max = 1000000
# 增加虚拟内存映射区域,对Java应用(ZooKeeper)很重要
vm.max_map_count = 262144
# 优化网络
net.core.somaxconn = 65535
net.ipv4.tcp_max_syn_backlog = 65535
EOF
sudo sysctl -p

# 为用户设置资源限制
sudo tee /etc/security/limits.d/clickhouse-zookeeper.conf << EOF
# 为 clickhouse 用户设置
clickhouse soft nofile 262144
clickhouse hard nofile 262144
clickhouse soft nproc 131072
clickhouse hard nproc 131072
# 为 zookeeper 用户设置
zookeeper soft nofile 65535
zookeeper hard nofile 65535
zookeeper soft nproc 65535
zookeeper hard nproc 65535
EOF

3. 软件安装

3.1 安装 ClickHouse(与之前相同)

# 在两台服务器上执行
cd /path/to/clickhouse-packages/
sudo rpm -ivh clickhouse-common-static-*.x86_64.rpm
sudo rpm -ivh clickhouse-server-*.x86_64.rpm
sudo rpm -ivh clickhouse-client-*.x86_64.rpm

3.2 安装 Java 环境(ZooKeeper 依赖)

# 安装 OpenJDK(ZooKeeper 3.8.x 需要 JDK 8 或 11)
sudo yum install -y java-11-openjdk-devel

# 验证安装
java -version

3.3 安装 ZooKeeper

# 在两台服务器上执行
# 1. 创建专用用户和目录
sudo groupadd -r zookeeper
sudo useradd -r -g zookeeper -s /sbin/nologin -d /var/lib/zookeeper zookeeper

# 2. 创建数据、日志和安装目录
sudo mkdir -p /opt/zookeeper /var/lib/zookeeper /var/log/zookeeper
# 为三个实例分别创建数据目录
sudo mkdir -p /var/lib/zookeeper/{zk1,zk2,zk3}/{data,log}
sudo chown -R zookeeper:zookeeper /opt/zookeeper /var/lib/zookeeper /var/log/zookeeper

# 3. 下载并解压 ZooKeeper(以 3.8.4 稳定版为例)
cd /tmp
wget https://downloads.apache.org/zookeeper/zookeeper-3.8.4/apache-zookeeper-3.8.4-bin.tar.gz
sudo tar -xzf apache-zookeeper-3.8.4-bin.tar.gz -C /opt/zookeeper --strip-components=1
sudo chown -R zookeeper:zookeeper /opt/zookeeper

4. ZooKeeper 集群配置(3节点,部署于2台服务器)

4.1 为每个实例创建配置文件

在 172.21.204.200 上配置 (运行 zk1 和 zk3):

# 实例 zk1 (myid=1, clientPort=2181)
sudo tee /opt/zookeeper/conf/zoo1.cfg << EOF
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/lib/zookeeper/zk1/data
dataLogDir=/var/lib/zookeeper/zk1/log
clientPort=2181
maxClientCnxns=60
autopurge.snapRetainCount=3
autopurge.purgeInterval=24
server.1=172.21.204.200:2888:3888
server.2=172.21.204.201:2889:3889
server.3=172.21.204.200:2890:3890
EOF

# 实例 zk3 (myid=3, clientPort=2182)
sudo tee /opt/zookeeper/conf/zoo3.cfg << EOF
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/lib/zookeeper/zk3/data
dataLogDir=/var/lib/zookeeper/zk3/log
clientPort=2182
maxClientCnxns=60
autopurge.snapRetainCount=3
autopurge.purgeInterval=24
server.1=172.21.204.200:2888:3888
server.2=172.21.204.201:2889:3889
server.3=172.21.204.200:2890:3890
EOF

# 创建 myid 文件
echo 1 | sudo tee /var/lib/zookeeper/zk1/data/myid
echo 3 | sudo tee /var/lib/zookeeper/zk3/data/myid

在 172.21.204.201 上配置 (运行 zk2):

# 实例 zk2 (myid=2, clientPort=2183)
sudo tee /opt/zookeeper/conf/zoo2.cfg << EOF
tickTime=2000
initLimit=10
syncLimit=5
dataDir=/var/lib/zookeeper/zk2/data
dataLogDir=/var/lib/zookeeper/zk2/log
clientPort=2183
maxClientCnxns=60
autopurge.snapRetainCount=3
autopurge.purgeInterval=24
server.1=172.21.204.200:2888:3888
server.2=172.21.204.201:2889:3889
server.3=172.21.204.200:2890:3890
EOF

# 创建 myid 文件
echo 2 | sudo tee /var/lib/zookeeper/zk2/data/myid

4.2 配置 ZooKeeper 系统服务(每个实例)

在 172.21.204.200 上创建服务文件:

# 实例 zk1 服务
sudo tee /etc/systemd/system/zookeeper1.service << EOF
[Unit]
Description=Apache ZooKeeper (Instance 1)
After=network.target

[Service]
Type=forking
User=zookeeper
Group=zookeeper
Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk
ExecStart=/opt/zookeeper/bin/zkServer.sh start /opt/zookeeper/conf/zoo1.cfg
ExecStop=/opt/zookeeper/bin/zkServer.sh stop /opt/zookeeper/conf/zoo1.cfg
ExecReload=/opt/zookeeper/bin/zkServer.sh restart /opt/zookeeper/conf/zoo1.cfg
Restart=on-abnormal
RestartSec=10s
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

# 实例 zk3 服务 (仅修改 Description 和配置文件路径)
sudo tee /etc/systemd/system/zookeeper3.service << EOF
[Unit]
Description=Apache ZooKeeper (Instance 3)
After=network.target

[Service]
Type=forking
User=zookeeper
Group=zookeeper
Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk
ExecStart=/opt/zookeeper/bin/zkServer.sh start /opt/zookeeper/conf/zoo3.cfg
ExecStop=/opt/zookeeper/bin/zkServer.sh stop /opt/zookeeper/conf/zoo3.cfg
ExecReload=/opt/zookeeper/bin/zkServer.sh restart /opt/zookeeper/conf/zoo3.cfg
Restart=on-abnormal
RestartSec=10s
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

在 172.21.204.201 上创建服务文件:

# 实例 zk2 服务
sudo tee /etc/systemd/system/zookeeper2.service << EOF
[Unit]
Description=Apache ZooKeeper (Instance 2)
After=network.target

[Service]
Type=forking
User=zookeeper
Group=zookeeper
Environment=JAVA_HOME=/usr/lib/jvm/java-11-openjdk
ExecStart=/opt/zookeeper/bin/zkServer.sh start /opt/zookeeper/conf/zoo2.cfg
ExecStop=/opt/zookeeper/bin/zkServer.sh stop /opt/zookeeper/conf/zoo2.cfg
ExecReload=/opt/zookeeper/bin/zkServer.sh restart /opt/zookeeper/conf/zoo2.cfg
Restart=on-abnormal
RestartSec=10s
LimitNOFILE=65535

[Install]
WantedBy=multi-user.target
EOF

重新加载 systemd:

bash
# 在两台服务器上执行
sudo systemctl daemon-reload

5. ClickHouse 服务配置(关键调整)

5.1 主配置文件 /etc/clickhouse-server/config.xml 调整

<!-- 移除或注释掉 Keeper 配置部分 -->
<!-- 
<keeper_server> ... </keeper_server> 
-->

<!-- 确保主服务监听配置正确 -->
<listen_host>0.0.0.0</listen_host>
<listen_host>::</listen_host>

<interserver_http_host>172.21.204.200</interserver_http_host>
<!-- 注意:在 201 服务器上改为 172.21.204.201 -->

<!-- 其他配置(如路径、内存等)保持不变 -->
<path>/data/clickhouse/</path>
<tmp_path>/var/lib/clickhouse/tmp/</tmp_path>

5.2 集群配置文件 /etc/clickhouse-server/config.d/metrika.xml

<?xml version="1.0"?>
<yandex>
    <!-- ========== 集群配置(保持不变) ========== -->
    <remote_servers>
        <cluster_1s2r>
            <shard>
                <internal_replication>true</internal_replication>
                <replica>
                    <host>172.21.204.200</host>
                    <port>9000</port>
                </replica>
                <replica>
                    <host>172.21.204.201</host>
                    <port>9000</port>
                </replica>
            </shard>
        </cluster_1s2r>
    </remote_servers>

    <!-- ========== ZooKeeper 配置(指向3个节点) ========== -->
    <zookeeper>
        <!-- 节点1 (运行在 200 服务器,端口 2181) -->
        <node index="1">
            <host>172.21.204.200</host>
            <port>2181</port>
        </node>
        <!-- 节点2 (运行在 201 服务器,端口 2183) -->
        <node index="2">
            <host>172.21.204.201</host>
            <port>2183</port>
        </node>
        <!-- 节点3 (运行在 200 服务器,端口 2182) -->
        <node index="3">
            <host>172.21.204.200</host>
            <port>2182</port>
        </node>
        <!-- 超时设置 -->
        <session_timeout_ms>30000</session_timeout_ms>
        <operation_timeout_ms>10000</operation_timeout_ms>
        <enable_address_replication>true</enable_address_replication>
    </zookeeper>

    <!-- ========== 宏配置 ========== -->
    <macros>
        <cluster>cluster_1s2r</cluster>
        <shard>1</shard>
        <replica>replica_200</replica>
    </macros>
    <!-- 在 172.21.204.201 上改为:<replica>replica_201</replica> -->
</yandex>

5.3 用户配置文件 /etc/clickhouse-server/users.xml(保持不变)

6. 启动与验证服务

6.1 启动顺序:先 ZooKeeper,后 ClickHouse

# === 第一步:启动 ZooKeeper 集群(所有3个实例) ===
# 在 172.21.204.200 上执行
sudo systemctl start zookeeper1 zookeeper3
sudo systemctl enable zookeeper1 zookeeper3

# 在 172.21.204.201 上执行
sudo systemctl start zookeeper2
sudo systemctl enable zookeeper2

# 检查所有实例状态
# 在 200 上检查
sudo systemctl status zookeeper1 zookeeper3
/opt/zookeeper/bin/zkServer.sh status /opt/zookeeper/conf/zoo1.cfg
/opt/zookeeper/bin/zkServer.sh status /opt/zookeeper/conf/zoo3.cfg

# 在 201 上检查
sudo systemctl status zookeeper2
/opt/zookeeper/bin/zkServer.sh status /opt/zookeeper/conf/zoo2.cfg
# 预期:一个leader,两个follower

# === 第二步:启动 ClickHouse 服务 ===
# 在两台服务器上执行
sudo systemctl start clickhouse-server
sudo systemctl enable clickhouse-server
sudo systemctl status clickhouse-server

6.2 验证网络监听

# 在每台服务器上检查所有相关端口是否正常监听
sudo netstat -tlnp | grep -E ‘(clickhouse|java)’

# 在 172.21.204.200 上预期看到:
# ZK端口:2181(zk1), 2182(zk3), 2888, 2890, 3888, 3890
# CH端口:9000, 8123, 9009

# 在 172.21.204.201 上预期看到:
# ZK端口:2183(zk2), 2889, 3889
# CH端口:9000, 8123, 9009

6.3 验证 ClickHouse 集群功能

# 连接到任意 ClickHouse 节点
clickhouse-client

-- 1. 查看集群配置
SELECT * FROM system.clusters WHERE cluster=‘cluster_1s2r’;

-- 2. 查看 ZooKeeper 连接状态(关键验证)
SELECT * FROM system.zookeeper WHERE path = ‘/’;
-- 如果返回数据而不是错误,说明 ZooKeeper 连接成功

-- 3. 测试分布式DDL
CREATE DATABASE test_cluster_zk ON CLUSTER cluster_1s2r;

-- 4. 创建复制表(依赖 ZooKeeper)
CREATE TABLE test_cluster_zk.test_replicated ON CLUSTER cluster_1s2r
(
    id Int32,
    name String,
    event_time DateTime
) ENGINE = ReplicatedMergeTree(‘/clickhouse/tables/{shard}/test_replicated_zk’, ‘{replica}’)
PARTITION BY toYYYYMM(event_time)
ORDER BY (id);

-- 5. 插入并验证数据同步
INSERT INTO test_cluster_zk.test_replicated VALUES 
(1, ‘zk_test_data_1’, now()),
(2, ‘zk_test_data_2’, now());

-- 在另一个节点查询
SELECT * FROM test_cluster_zk.test_replicated ORDER BY id;

7. 集群管理与监控

7.1 常用管理命令

# ZooKeeper 集群管理
# 检查每个节点的状态
echo stat | nc 172.21.204.200 2181
echo stat | nc 172.21.204.201 2183
echo stat | nc 172.21.204.200 2182

# 使用四字命令获取监控指标
echo mntr | nc 172.21.204.200 2181

# ClickHouse 查看副本状态
clickhouse-client --query “SELECT database, table, is_leader, is_readonly, replica_name FROM system.replicas”

7.2 创建监控脚本 /opt/clickhouse-zk-monitor.sh

#!/bin/bash

echo “=== ClickHouse + ZooKeeper 集群健康检查 ===”
echo “检查时间: $(date)”
echo “”

# 检查 ZooKeeper 3节点集群
echo “1. ZooKeeper 集群状态 (3节点):”
declare -A zk_nodes=(
  [“节点1 (200:2181)”]=“172.21.204.200 2181”
  [“节点2 (201:2183)”]=“172.21.204.201 2183”
  [“节点3 (200:2182)”]=“172.21.204.200 2182”
)

for node_desc in “${!zk_nodes[@]}”; do
  read -r host port <<< “${zk_nodes[$node_desc]}”
  if status=$(echo stat | timeout 2 nc $host $port 2>/dev/null | grep Mode); then
    mode=$(echo $status | cut -d’:’ -f2 | tr -d ‘[:space:]’)
    echo “  $node_desc: $mode”
  else
    echo “  $node_desc: 无法连接”
  fi
done

echo “”
echo “2. ClickHouse 服务状态:”
for host in 172.21.204.200 172.21.204.201; do
  ch_status=$(ssh $host “systemctl is-active clickhouse-server 2>/dev/null || echo ‘inactive’”)
  echo “  $host - ClickHouse: $ch_status”
done

8. 故障排查指南

8.1 常见问题及解决方案

 
问题可能原因解决方案
ZooKeeper 实例无法启动 1. 端口冲突
2. myid 文件不匹配
3. 数据目录权限
1. 检查端口 2181-2183, 2888-2890, 3888-3890
2. 确认每个实例的 myid 与配置文件 server.x 的 x 一致
3. sudo chown -R zookeeper:zookeeper /var/lib/zookeeper/
ClickHouse 连接 ZooKeeper 失败 1. 连接了错误的端口
2. 防火墙规则不全
1. 检查 metrika.xml 中每个节点的端口是否正确
2. 确保所有ZK实例的客户端端口(2181,2182,2183)都开放
ZooKeeper 集群选不出Leader 1. 网络不通
2. 选举端口未开放
1. 检查服务器间网络,特别是选举端口 3888-3890
2. 确保每个实例的 server.x 配置中的主机和端口正确
复制表不同步 1. 某个ZK节点连接失败
2. 副本宏配置重复
1. 检查 system.replicas 表的 zookeeper_exception 字段
2. 确认两台服务器的 metrika.xml 中 <replica> 值不同

8.2 重要日志文件位置

# ZooKeeper 日志(每个实例独立)
/var/lib/zookeeper/zk1/log/zookeeper.log  # 实例1
/var/lib/zookeeper/zk2/log/zookeeper.log  # 实例2
/var/lib/zookeeper/zk3/log/zookeeper.log  # 实例3

# 通过服务日志查看
sudo journalctl -u zookeeper1 -f
sudo journalctl -u zookeeper2 -f
sudo journalctl -u zookeeper3 -f

# ClickHouse 日志(关注 ZooKeeper 相关错误)
grep -i zookeeper /var/log/clickhouse-server/clickhouse-server.log

9. 重要注意事项与生产建议 ⚠️

9.1 关于 2 服务器部署 3 节点 ZK 集群的说明

本指南采用的 “2台物理服务器部署3个ZooKeeper节点” 方案是一种资源受限情况下的折中方案:

  • 优点:满足了ZooKeeper集群需要奇数节点的要求,避免了脑裂风险。

  • 风险:存在单点故障隐患。如果运行两个ZK实例的服务器(172.21.204.200)宕机,ZK集群将失去多数派(只剩1/3个节点),导致整个协调服务不可用,进而影响ClickHouse集群。

  • 生产建议:

    1. 最低建议:增加第3台独立服务器,将zk3迁移过去,形成真正的三节点独立部署。

    2. 监控重点:加强对 172.21.204.200 服务器的监控,确保其高可用。

    3. 备份策略:定期备份ZooKeeper数据,特别是 /var/lib/zookeeper/zk1/data/ 和 /var/lib/zookeeper/zk3/data/ 目录。

9.2 生产环境优化建议

# ZooKeeper JVM 优化(为每个实例创建启动脚本)
# 编辑 /opt/zookeeper/bin/zkEnv.sh,或为每个服务单独设置环境变量
# 在 systemd 服务文件的 [Service] 部分添加:
Environment=“SERVER_JVMFLAGS=-Xms2G -Xmx2G -XX:+UseG1GC -XX:MaxGCPauseMillis=20 -XX:+PrintGCDetails -XX:+HeapDumpOnOutOfMemoryError”

9.3 备份与恢复

# 备份关键配置和数据
# 1. 备份 ZooKeeper 配置文件
sudo tar -czf /backup/zookeeper_conf_$(date +%Y%m%d).tar.gz /opt/zookeeper/conf/*.cfg

# 2. 备份 ClickHouse 配置
sudo tar -czf /backup/clickhouse_conf_$(date +%Y%m%d).tar.gz /etc/clickhouse-server/

# 3. 重要:定期测试 ZooKeeper 集群的恢复流程

10. 架构总结

部署概览

物理服务器1 (172.21.204.200):
  - ClickHouse Server (副本1)
  - ZooKeeper 实例1 (myid=1, clientPort=2181)
  - ZooKeeper 实例3 (myid=3, clientPort=2182)

物理服务器2 (172.21.204.201):
  - ClickHouse Server (副本2)
  - ZooKeeper 实例2 (myid=2, clientPort=2183)

通信关系:
  - ClickHouse 副本间通过 9009 端口同步数据
  - ClickHouse 服务连接全部3个ZooKeeper节点 (2181,2182,2183)
  - ZooKeeper 节点间通过 2888/2889/2890 对等通信,3888/3889/3890 选举

选择建议

  • 测试/开发环境:本指南的2服务器3节点方案完全适用。

  • 小型生产环境:可短期使用,但需制定172.21.204.200服务器的应急预案。

  • 中大型生产环境:强烈建议增加第3台独立服务器部署ZK,形成真正的三节点ZK集群。

至此,你已完成在 2台服务器上部署包含3节点ZooKeeper集群 的 ClickHouse 单分片双副本集群。所有组件均监听 0.0.0.0 支持远程访问,并针对实际约束提供了可行的部署方案。

 posted on 2025-12-16 17:48  xibuhaohao  阅读(26)  评论(0)    收藏  举报