3、安装与部署:从单机到集群的完整实践

部署 Pinot 这件事,说实话比我想象中要灵活得多。早期我还在用笨办法手动搭集群,后来发现官方其实给了好几条路——单机尝鲜、生产集群、容器化,各有各的玩法。这一章我就把三种模式都走一遍,顺便聊聊我踩过的坑。

本章核心脉络: 单机快速启动 → 集群架构与Helix/ZK依赖 → Docker化部署 → Kubernetes生产实践。建议按顺序阅读,但如果你赶时间,可以直接跳到对应模式。

3.1 单机模式:五分钟跑起来

我个人习惯先用单机模式验证配置。你想想看,如果单机都跑不顺,集群肯定更麻烦。

Pinot 的单机模式其实是个“all-in-one”进程,把 Controller、Broker、Server 都塞在一起。适合开发测试,千万别上生产。

3.1.1 下载与启动

# 下载二进制包(以 1.0.0 为例)
wget https://downloads.apache.org/pinot/apache-pinot-1.0.0/apache-pinot-1.0.0-bin.tar.gz
tar -xzf apache-pinot-1.0.0-bin.tar.gz
cd apache-pinot-1.0.0-bin

# 启动单机模式(自动内嵌 ZK)
./bin/pinot-admin.sh QuickStart -type MULTI_STAGE

启动后访问 http://localhost:9000 就能看到控制台。嗯,这里要注意:MULTI_STAGE 类型会启动一个内嵌的 ZooKeeper,端口 2181。如果你本地已经有 ZK 在跑,记得改端口或者用 -zkAddress 参数指定。

我的习惯: 单机模式下我经常用 -type STREAM 来测试实时摄入,省得每次都要配 Kafka 连接。不过这只是快速验证,生产环境别这么干。

3.1.2 验证部署

启动后,用 curl 检查各组件状态:

# 检查 Controller
curl http://localhost:9000/health

# 检查 Broker
curl http://localhost:8099/health

# 检查 Server
curl http://localhost:8097/health

如果都返回 OK,说明单机模式跑起来了。我曾经遇到过端口被占用的情况,尤其是 Mac 上 AirPlay 会抢 9000 端口。解决办法很简单:启动时加 -controllerPort 19000 换个端口。

3.2 集群模式:Helix 与 ZooKeeper 的依赖关系

单机模式只是开胃菜。生产环境必须上集群,而集群的核心就是 Apache Helix + ZooKeeper。说白了,Pinot 的集群管理完全建立在 Helix 之上,而 Helix 又依赖 ZK 做分布式协调。

3.2.1 架构总览

先看一张我画的架构图,理清组件关系:

Pinot 集群部署架构(Helix + ZK) ZooKeeper 集群 Helix Controller Pinot Controller Pinot Broker Pinot Server Pinot Minion 关键依赖说明: • ZooKeeper 是 Helix 的“状态存储”,所有元数据、分区分配、活节点信息都存这里 • Helix Controller 负责将 ZK 中的状态同步给 Pinot 各组件 • Pinot Controller/Broker/Server/Minion 都是 Helix 的“参与者”

3.2.2 为什么非要 ZK?

你可能会问:Pinot 自己不能管理集群状态吗?答案是:不能,也没必要。Helix 已经提供了成熟的分区管理、故障转移、负载均衡能力,Pinot 直接复用就好。ZK 在这里扮演的角色就是“可靠的配置存储 + 分布式锁”。

我记得有一次生产环境 ZK 集群挂了,Pinot 整个集群就变成了“瞎子”——Controller 不知道哪些 Server 活着,Broker 不知道路由到哪。从那以后,我部署 Pinot 之前一定会先确保 ZK 集群是高可用的。

3.2.3 集群部署步骤

假设你已经有一个 3 节点的 ZK 集群(zk1:2181,zk2:2181,zk3:2181),部署 Pinot 集群的流程如下:

  1. 启动 Controller(建议 2 台,主备模式)
  2. 启动 Broker(至少 2 台,做负载均衡)
  3. 启动 Server(根据数据量决定,建议 3 台起)
  4. (可选)启动 Minion(用于后台任务,如数据合并)
# 启动 Controller(节点1)
./bin/pinot-admin.sh StartController \
  -zkAddress zk1:2181,zk2:2181,zk3:2181/pinot \
  -controllerPort 9000

# 启动 Broker(节点2)
./bin/pinot-admin.sh StartBroker \
  -zkAddress zk1:2181,zk2:2181,zk3:2181/pinot \
  -brokerPort 8099

# 启动 Server(节点3)
./bin/pinot-admin.sh StartServer \
  -zkAddress zk1:2181,zk2:2181,zk3:2181/pinot \
  -serverPort 8097
注意: ZK 路径 /pinot 是命名空间。如果你在同一套 ZK 上跑多个 Pinot 集群(比如测试和生产),一定要用不同的路径,否则会互相干扰。我曾经因为忘了改路径,导致测试集群把生产集群的配置覆盖了……嗯,血的教训。

3.2.4 组件配置对比

组件 默认端口 核心配置项 高可用建议
Controller 9000 controller.helix.cluster.name 至少 2 台,主备切换
Broker 8099 pinot.broker.enable.query.limit.override 至少 2 台,前端加负载均衡
Server 8097 pinot.server.instance.dataDir 3 台起,副本数=2
Minion 9514 pinot.minion.port 按需部署,非必须

3.3 Docker 部署:容器化第一步

如果你不想手动装 JDK、配环境变量,Docker 是最快的方式。官方镜像在 apachepinot/pinot 下,标签对应版本号。

3.3.1 单机 Docker 启动

# 拉取镜像
docker pull apachepinot/pinot:1.0.0

# 启动单机模式(内嵌 ZK)
docker run -d --name pinot-quickstart \
  -p 9000:9000 -p 8099:8099 -p 8097:8097 \
  apachepinot/pinot:1.0.0 \
  QuickStart -type MULTI_STAGE

我个人习惯把数据目录挂载出来,方便排查:

docker run -d --name pinot-quickstart \
  -v /data/pinot:/tmp/pinot \
  -p 9000:9000 -p 8099:8099 -p 8097:8097 \
  apachepinot/pinot:1.0.0 \
  QuickStart -type MULTI_STAGE

3.3.2 集群 Docker Compose

生产环境用 Docker Compose 编排集群比较省心。下面是一个简化版示例:

version: '3.8'
services:
  zookeeper:
    image: confluentinc/cp-zookeeper:7.4.0
    environment:
      ZOOKEEPER_CLIENT_PORT: 2181

  controller:
    image: apachepinot/pinot:1.0.0
    command: StartController -zkAddress zookeeper:2181/pinot
    ports:
      - "9000:9000"
    depends_on:
      - zookeeper

  broker:
    image: apachepinot/pinot:1.0.0
    command: StartBroker -zkAddress zookeeper:2181/pinot
    ports:
      - "8099:8099"
    depends_on:
      - zookeeper

  server:
    image: apachepinot/pinot:1.0.0
    command: StartServer -zkAddress zookeeper:2181/pinot
    ports:
      - "8097:8097"
    depends_on:
      - zookeeper
避坑指南: 我曾经在 Docker 环境下遇到过 Server 注册的 IP 是容器内网 IP(比如 172.17.0.x),导致 Broker 无法路由。解决办法是在启动参数里加 -serverHost <宿主机IP>,强制指定对外通信地址。

3.4 Kubernetes 部署:生产级实践

K8s 部署是 Pinot 在云原生环境下的标准姿势。官方提供了 Helm Chart,但说实话,默认配置有很多坑。我结合自己的生产经验,给你一套靠谱的方案。

3.4.1 使用 Helm 安装

# 添加 Helm 仓库
helm repo add pinot https://raw.githubusercontent.com/apache/pinot/master/kubernetes/helm

# 安装 Pinot 集群
helm install pinot pinot/pinot \
  --set controller.replicaCount=2 \
  --set broker.replicaCount=2 \
  --set server.replicaCount=3 \
  --set zookeeper.replicaCount=3

嗯,这里要注意:Helm Chart 默认会帮你部署 ZK 集群。如果你已经有现成的 ZK(比如用 Strimzi 管理的),可以通过 --set zookeeper.enabled=false 关掉内置 ZK。

3.4.2 关键配置项

参数 默认值 生产建议 说明
controller.replicaCount 1 2 主备切换,避免单点
server.replicaCount 1 ≥3 保证数据副本数
server.persistence.size 10Gi 根据数据量评估 建议用 SSD 存储类
broker.requestMemory 512Mi 2Gi+ 查询量大时需调高

3.4.3 我遇到的 K8s 部署坑

说几个我在生产环境踩过的坑:

  • Pod 重启后 IP 变化: Pinot 的 Server 实例名默认用 IP,Pod 重启后 IP 变了,Helix 里会残留旧实例。解决办法是设置 pinot.server.instance.id 为 Pod 名称(通过 Downward API 注入)。
  • 资源限制不当: 有次我把 Server 的 CPU limit 设得太低,导致查询延迟飙升。后来改成 requests=4, limits=8 才稳定。
  • ZK 性能瓶颈: 默认 ZK 的 maxClientCnxns 是 60,如果 Pinot 节点多,很容易达到上限。建议调大到 200+。
重要提醒: K8s 环境下,Pinot 的 Controller 选举依赖 ZK 的临时节点。如果 ZK 集群不稳定,Controller 会频繁切换,导致表创建/更新操作失败。所以,先把 ZK 集群搞稳,再谈 Pinot 的稳定性。

3.5 部署模式对比总结

模式 适用场景 复杂度 生产可用 推荐指数
单机模式 开发测试、功能验证 ★☆☆☆☆ 否 ⭐⭐
集群模式(手动) 中小规模生产、定制化部署 ★★★★☆ 是 ⭐⭐⭐
Docker Compose CI/CD 环境、演示 ★★☆☆☆ 谨慎 ⭐⭐⭐
Kubernetes 大规模生产、云原生环境 ★★★★★ 是 ⭐⭐⭐⭐⭐

我个人最推荐 K8s 部署——虽然学习曲线陡,但一旦配好,扩缩容、故障恢复、资源隔离都省心很多。如果你团队没有 K8s 运维能力,手动集群模式也是稳妥的选择,至少可控性强。

一句话总结: 单机用来学,集群用来用,K8s 用来躺。选哪种,看你的运维能力和业务规模。