集群安装
为大规模工作负载配置 PlantPulse 为主节点 + 工作节点集群的方法。您可以从单节点开始,当处理量达到瓶颈时逐步扩展。
多节点配置的两种方式 — 目的不同
配置 目的 文档 ① 主/工作节点集群 水平扩展基础设施(Cassandra·Kafka·Spark) — 将同一层分散到多个节点 本文档 ② 数据湖/应用2节点分离 垂直分离存储/处理层和控制台/批处理层(分别在不同主机上) — 按节点降低内存·隔离负载 2节点分离安装 如果处理量不足需要扩展基础设施,使用 ①;如果单个主机内存不足或需要隔离批处理负载,使用 ②。两者不互斥,
PP_MODE(集群化)和PP_TIER(分层网关)是正交的。
何时扩展为集群?
| 环境规模 | 推荐配置 | 备注 |
|---|---|---|
| 标签 ~5,000 | 单主节点 | 无需集群 |
| 标签 5,000 ~ 50,000 | 主节点 + 1~2 工作节点 | 分散分析/消息 |
| 标签 50,000+ | 主节点 + 3+ 工作节点 | 完整分布式运营 |
集群拓扑
硬件要求
每个工作节点推荐配置:
| 项目 | 最低 | 标准 | 大规模 |
|---|---|---|---|
| CPU | 16 vCPU | 32 vCPU | 48 vCPU |
| 内存 | 64 GB | 128 GB | 200+ GB |
| 数据磁盘 | 200 GB NVMe | 1 TB NVMe | 4 TB NVMe |
| 网络 | 1 Gbps | 10 Gbps | 10 Gbps |
节点间网络:集群节点之间推荐 10 Gbps 或以上。Cassandra repair、Kafka 复制、Spark shuffle 流量很大。
前置条件
主节点和所有工作节点必须完成以下准备:
- 满足系统要求
- 配置主机名/固定 IP/DNS
- 时间同步 (chronyd) — 节点间时间差必须 ≤ 100ms
- OS 调优 (limits / sysctl / swap off)
- 节点间专网通信可用 (RFC 1918 或 Tailscale)
- 允许集群内部端口 (Cassandra 7000/7001/9042, Kafka 9092/9093, Spark 7077/8081 等)
/etc/hosts 配置 (所有节点相同)
# /etc/hosts — 마스터 / 워커 모든 노드에 동일하게
192.168.0.41 plantpulse-master plantpulse-master.local
192.168.0.101 plantpulse-worker-1 plantpulse-worker-1.local
192.168.0.102 plantpulse-worker-2 plantpulse-worker-2.local
192.168.0.103 plantpulse-worker-3 plantpulse-worker-3.local
Docker 集群 (推荐方案)
在 Docker/单行安装环境中,工作节点通过 compose 覆盖层启动。主节点上基本栈已启动的状态下,bin/worker-add.sh 逐个添加工作节点。密钥/证书通过以下流程作为边车文件在节点间复制,无需手工移动数值。
工作节点列表的单一真实来源 — compose/workers.roster
存在哪些工作节点的定义源头是单个 compose/workers.roster 文件。每行使用 <id> <ip> 格式,单节点安装时应为空。
# compose/workers.roster
1 10.99.0.101
| 项目 | 说明 |
|---|---|
id | PP_WORKER_ID。容器名称(plantpulse-worker-<id>)和卷名称(pw-<id>-*)的后缀 |
ip | pp-net(10.99.0.0/24)上的固定地址。.1 是网关,.100 是数据湖,所以从 .101 开始使用 |
compose/docker-compose.worker.yml 从本文件生成(bin/gen-worker-compose.sh),bin/env.sh 也从同一文件推导工作节点 IP 和节点列表。这样可以防止 compose、运维脚本、密钥轮转卫士看到不同的工作节点集合。
docker-compose.worker.yml 是生成产物。手工修改会导致 CI 的 gen-worker-compose.sh --check 失败。添加和删除工作节点不是通过在 roster 中增删行,而是使用下文的 worker-add.sh / worker-decommission.sh + worker-remove.sh — 工作节点拥有 Cassandra 令牌范围和 PostgreSQL 复制槽,仅修改列表既无法创建也无法删除。
工作节点相关环境变量 (bin/env.sh)
| 变量 | 默认值 | 说明 |
|---|---|---|
DOCKER_PW_NAME | plantpulse-worker | 工作节点容器名前缀 (plantpulse-worker-1 …) |
DOCKER_PW_MEMORY | 与 DOCKER_DATALAKE_MEMORY 相同的值(80G,主机较小时为 RAM 的 90%) | 工作节点容器内存上限 |
DOCKER_PW_IP_<n> · PP_WORKER_NODES | 从 roster 推导 | 不手工填写 |
工作节点使用与数据湖主节点相同的镜像(2026-08-31 版本合并),因此该镜像中烧录的 JVM 大小也保持不变 — Cassandra 单独需要 -Xms16G/-Xmx16G。按主机规模成比例分配的方式是错误的。所需容量由服务配置决定,不是主机。
2026-08-31 实测:旧的 12g 默认值工作节点在 Cassandra 加入环前被 OOMKilled,容器以 OOMKilled=true 状态死亡,但加入从未发生,health: starting 仍保持。
添加工作节点
cd /opt/kopens/plantpulse-platform-docker
bin/worker-add.sh # 빈 id·빈 주소 자동 선택
bin/worker-add.sh 3 # id 지정
bin/worker-add.sh 3 10.99.0.103 # id·주소 지정
worker-add.sh 依次执行。
- 在 roster 中注册 (已存在的 id 会被拒绝为「添加」)
- 重新生成覆盖层 compose
- 创建卷 → pull 镜像 →
up -d - 确认加入 — 通过主节点的
nodetool直接验证
工作节点同时拥有 Cassandra 令牌范围、Spark 工作节点注册、PostgreSQL 复制槽、Redis 复制链接。容器自身的就绪检查只查看「是否可触及主节点」,所以加入失败的工作节点与成功工作节点表现完全相同为正常。
2026-08-31 实测:Cassandra 被 OOMKilled 的工作节点保持环为 1 节点并维持 health: starting 状态。所以 worker-add.sh 查询环本身。
工作节点运维
cd /opt/kopens/plantpulse-platform-docker
# 진입 (워커는 기본 스택의 서비스가 아니라 shell.sh 로는 잡히지 않습니다)
docker exec -ti plantpulse-worker-3 /bin/bash
# 정지 — compose 동사 그대로
docker compose -f compose/docker-compose.yml -f compose/docker-compose.worker.yml \
--profile worker-3 stop plantpulse-worker-3
# 이미지 갱신 (이미 도는 워커. 추가 시점의 pull 은 worker-add.sh 안에 들어 있습니다)
docker compose -f compose/docker-compose.yml -f compose/docker-compose.worker.yml \
--profile worker-3 pull plantpulse-worker-3
docker compose -f compose/docker-compose.yml -f compose/docker-compose.worker.yml \
--profile worker-3 up -d plantpulse-worker-3
移除工作节点 — 必须按此顺序
bin/worker-decommission.sh 3 # 데이터 이관 + 링 이탈 확인 + 복제 슬롯 정리
bin/worker-remove.sh # 그 다음에 컨테이너 제거
docker rm 是遗弃而非移除Cassandra 通过 DN 持有该节点的令牌范围和 host id。当 RF=3 时,QUORUM 仍然成立,所以没有任何告警产生。主节点继续持有该工作节点的 PostgreSQL 物理复制槽,直到磁盘满之前 WAL 被固定。
worker-remove.sh 会在容器运行中拒绝操作,要求先调用 worker-decommission.sh。
worker-run.sh · worker-stop.sh · worker-update.sh · worker-bash.sh 这四个已删除。它们基于手工维护的工作节点服务列表,在切换到 roster 生成方式时,我们不仅改了名称,还完全移除了。替代方案分别为 worker-add.sh(包括 pull) · compose 动词 · compose pull + up -d · docker exec。
密钥边车复制 (禁止手工复制)
主节点生成的服务密钥位于 /etc/kopens/plantpulse-platform.env 边车文件中。将此文件复制到工作节点,工作节点即可用相同凭证加入 — 不要逐个手工移动密码(模式与 2 节点分离文档的加入包相同)。
# 마스터 노드에서 각 워커로
scp /etc/kopens/plantpulse-platform.env root@<worker-ip>:/etc/kopens/
复制共享 CA → 自动初始化
节点间 TLS 信任通过共享集群 CA 建立。将主节点的 /etc/kopens/ca/ 复制到工作节点,容器启动时会自动初始化到 pp-security 卷,无需手工部署证书。
# 마스터 노드에서 각 워커로 (컨테이너 경로 기준 자동 seed)
scp -r /etc/kopens/ca root@<worker-ip>:/etc/kopens/
platform.node.env是节点身份文件,不要复制。复制目标仅为上述两项(plantpulse-platform.env、ca/)。
集群验证 (Docker 环境)
# Cassandra 링 — 모든 노드가 UN (Up Normal) 이어야 합니다
docker exec plantpulse-datalake \
/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd node status
# Spark — 워커가 ALIVE 인지
# 브라우저에서 http://<마스터IP>:4440/ 의 Workers 탭
原生(二进制)集群流程
以下为已采用二进制安装的现有系统保留的流程。现行发行版仅支持上述 Docker Compose 方案,新部署请勿使用。
1. 主节点安装
主节点遵循单节点安装流程。
1.1 主节点安装
# 마스터 노드에서
mkdir -p /opt/kopens
cd /opt/kopens
tar -xzvf plantpulse-platform-2026.05.tgz
cd /opt/kopens/plantpulse-platform/tools
./setup.sh
# 노드 모드 입력: MASTER
# HOST IP: 192.168.0.41
# SERVICE IP: 192.168.0.41 (외부 노출 IP)
1.2 env.local.sh 调整 (集群选项)
env.sh由部署覆盖,是 SSOT(值的单一真实来源),不要直接修改。机器特定值在同目录的env.local.sh中以覆盖形式编写(env.sh在最开始优先 source,因此总是优先应用)。详见二进制安装第 4 节。
vi /opt/kopens/plantpulse-platform/plantpulse-startup/env.local.sh
# 마스터 노드
export PP_MODE=MASTER
export PP_HOST_IP=192.168.0.41
export PP_SERVICE_IP=192.168.0.41
export PP_MASTER_IP=192.168.0.41
export PP_PUBLIC_IP=192.168.0.41
# 클러스터 자원
export PP_CLUSTER_CORES=64 # 마스터 + 워커 코어 합 (Spark 사용)
export PP_CLUSTER_MEMORY_BY_CORE=2G
# TLS SAN 에 모든 노드 IP / 도메인 포함
export PP_TLS_SAN_IPS="192.168.0.41,192.168.0.101,192.168.0.102,192.168.0.103,127.0.0.1"
export PP_TLS_SAN_DNS="plantpulse-master,plantpulse-worker-1,plantpulse-worker-2,plantpulse-worker-3,localhost"
export PP_TLS_NODE_NAMES="master worker-1 worker-2 worker-3"
1.3 启动主节点
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./configure.sh
./prepare-ssl.sh
./start-daemon.sh
./status.sh
2. 添加工作节点
2.1 工作节点安装
在各工作节点上执行相同流程。
# 워커 노드 (예: 192.168.0.101) 에서
mkdir -p /opt/kopens
cd /opt/kopens
tar -xzvf plantpulse-platform-2026.05.tgz
cd /opt/kopens/plantpulse-platform/tools
./setup.sh
# 노드 모드 입력: WORKER
# HOST IP: 192.168.0.101
# SERVICE IP: 192.168.0.101
# MASTER IP: 192.168.0.41
2.2 工作节点 env.local.sh 调整 (仅节点特定值)
仅在 env.local.sh 中编写 IP 等机器特定值(env.sh 直接修改 ✗)。
vi /opt/kopens/plantpulse-platform/plantpulse-startup/env.local.sh
# 워커 노드
export PP_MODE=WORKER
export PP_HOST_IP=192.168.0.101 # 이 워커의 IP
export PP_SERVICE_IP=192.168.0.101
export PP_MASTER_IP=192.168.0.41 # 마스터의 IP
export PP_PUBLIC_IP=192.168.0.101
密码/密钥库密码不要手工移到这里 — 通过下面的密钥边车在节点间同步。
2.3 密钥边车复制
服务密钥位于主节点的 /etc/kopens/plantpulse-platform.env 边车文件中。将此文件复制到工作节点,工作节点即可用相同凭证加入(模式与 2 节点分离文档的加入包相同)。不要逐个手工移动密码。
# 마스터에서 워커로 (env.sh 보다 먼저 source 되는 사이드카)
scp /etc/kopens/plantpulse-platform.env root@192.168.0.101:/etc/kopens/
2.4 复制共享 CA → 自动初始化
节点间 TLS 信任通过共享集群 CA 建立。将主节点的 /etc/kopens/ca/ 复制到工作节点,启动时会根据容器路径自动初始化,无需手工部署证书。
# 마스터에서 워커로 (공유 CA — 크로스노드 TLS 신뢰)
scp -r /etc/kopens/ca root@192.168.0.101:/etc/kopens/
platform.node.env是节点身份文件,不要复制。
2.5 启动工作节点
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./configure.sh
./start-daemon.sh
./status.sh
查看工作节点的 status.sh 输出,以下内容显示 RUNNING 则正常:
- Cassandra (:9042)
- Kafka (:9092)
- Spark Worker (:8081)
注意:工作节点不运行 server / cep / batch 等应用模块。仅基础设施/分布式处理组件被集群化。
3. 集群验证
3.1 Cassandra 集群
# 마스터에서
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./pd node status
预期输出示例:
Datacenter: datacenter1
=======================
Status=Up/Down
|/ State=Normal/Leaving/Joining/Moving
-- Address Load Tokens Owns Host ID Rack
UN 192.168.0.41 45.2 GiB 256 ? <uuid> rack1
UN 192.168.0.101 44.8 GiB 256 ? <uuid> rack1
UN 192.168.0.102 45.5 GiB 256 ? <uuid> rack1
所有节点都显示 UN (Up Normal) 则正常。
3.2 Kafka 集群
cd /opt/kopens/plantpulse-platform/plantpulse-messaging/kafka/bin
./kafka-broker-api-versions.sh --bootstrap-server 192.168.0.41:9092 | head
显示 3 个 broker 则正常。
3.3 Spark 集群
在浏览器中访问主节点的 Spark UI:
http://192.168.0.41:4440/
在 Workers 标签页检查所有工作节点是否为 ALIVE 状态。
4. 集群运维
动态添加工作节点 (扩展)
已运营集群添加工作节点的流程:
移除工作节点
# 1. 워커를 안전하게 비우기 (Cassandra)
ssh root@192.168.0.103 \
/opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin/pd node drain
# 2. 마스터에서 노드 제거
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./pd node remove
# 호스트 ID 입력
# 3. 워커 정지 후 제거
ssh root@192.168.0.103 \
/opt/kopens/plantpulse-platform/plantpulse-startup/stop.sh
节点替换
故障节点更换新节点时,参考管理员:节点替换流程。核心是保持相同 IP/主机名,启动新节点后在 bootstrap 模式下拉取数据。
5. 集群备份
主节点的 plantpulse-backup 负责整个集群。
cd /opt/kopens/plantpulse-platform/plantpulse-backup/bin
# Cassandra: 모든 노드에서 snapshot 수집
./backup.sh --cassandra
# PostgreSQL: 마스터에서만
./backup.sh --postgres
参考备份与恢复。
常见问题
| 症状 | 原因 | 处理 |
|---|---|---|
| 工作节点无法加入 | seed 节点未设置 | 检查 cassandra.yaml 中的 seeds 是否包含主节点 IP |
| Cassandra 令牌不均 | 不当加入 | pd node cleanup + 令牌重分配 |
| Kafka 未充分复制 | broker 宕机 | kafka-topics.sh --describe + 检查复制因子 |
| Spark Worker 未注册 | 防火墙阻止 7077 | 专网允许 7077、8081 双向 |
| 证书不匹配 | keystore 同步遗漏 | 从主节点重新运行 prepare-ssl.sh + 工作节点重新部署 |
| 时间不同步 | NTP 未设置 | 检查 chronyc tracking,保持 ≤ 100ms |
集群卸载
# 각 워커에서
ssh root@<WORKER_IP> /opt/kopens/plantpulse-platform/plantpulse-startup/stop.sh
ssh root@<WORKER_IP> rm -rf /opt/kopens/plantpulse-platform
# 마스터에서
cd /opt/kopens/plantpulse-platform/plantpulse-datalake-cli/bin
./stop.sh
rm -rf /opt/kopens/plantpulse-platform
# 데이터 디스크는 별도 정책으로 관리 (필요 시 백업 후 삭제)