跳到主要内容

ZooKeeper 与 Kafka 三节点部署

本章部署 3 个 ZooKeeper 节点和 3 个 Kafka Broker,分别以 zk-1 至 zk-3、kafka-1 至 kafka-3 表示。所有名称都是示例,部署前要替换为受控内网 DNS;不能向公网暴露 ZooKeeper 端口或明文 Kafka 监听器。

ZooKeeper 与 Kafka 三节点部署拓扑

1. 准备运行目录​

Kafka 3.x ZooKeeper 模式需要与该发行版兼容的 JDK。程序、配置、日志与数据目录必须分离,Broker 数据目录应挂载独立持久化磁盘。

# 创建不可登录的系统账号,避免 Kafka 与 ZooKeeper 以 root 权限运行。
sudo useradd --system --home /nonexistent --shell /usr/sbin/nologin kafka

# 创建程序、配置、日志和持久化数据目录。
sudo install -d -o kafka -g kafka /opt/kafka /etc/kafka \
/var/lib/kafka/logs /var/lib/zookeeper /var/log/kafka

# 下载已完成兼容性测试的 Kafka 3.x 包;Kafka 4.x 不含 ZooKeeper 模式。
export KAFKA_VERSION=3.9.0
curl -fLO "https://archive.apache.org/dist/kafka/${KAFKA_VERSION}/kafka_2.13-${KAFKA_VERSION}.tgz"
sudo tar -xzf "kafka_2.13-${KAFKA_VERSION}.tgz" -C /opt/kafka --strip-components=1
sudo chown -R kafka:kafka /opt/kafka /etc/kafka /var/lib/kafka /var/lib/zookeeper /var/log/kafka

2. 配置 ZooKeeper Ensemble​

在三个 ZooKeeper 节点上使用相同的配置文件。2181 是客户端端口,2888 用于节点同步,3888 用于 Leader 选举;防火墙只允许 ZooKeeper 节点相互访问 2888、3888,并仅允许 Broker 访问 2181。

# /etc/kafka/zookeeper.properties
# 数据目录必须在持久化磁盘,不能使用 /tmp。
dataDir=/var/lib/zookeeper
# 仅向 Broker 与受控运维网络开放客户端端口。
clientPort=2181
tickTime=2000
initLimit=10
syncLimit=5
# 最后的数字与各节点 myid 一一对应。
server.1=zk-1.example.internal:2888:3888
server.2=zk-2.example.internal:2888:3888
server.3=zk-3.example.internal:2888:3888
# 仅在 zk-1 执行;myid 必须与 server.1 的编号一致。
echo 1 | sudo tee /var/lib/zookeeper/myid

# 仅在 zk-2 执行;不要让多个节点使用同一 myid。
echo 2 | sudo tee /var/lib/zookeeper/myid

# 仅在 zk-3 执行;随后确保数据目录仍由 kafka 用户拥有。
echo 3 | sudo tee /var/lib/zookeeper/myid
sudo chown -R kafka:kafka /var/lib/zookeeper
# /etc/systemd/system/zookeeper.service
[Unit]
# 等待 DNS 与网络可用,避免 Ensemble 初始化时无法连接其他节点。
After=network-online.target
Wants=network-online.target

[Service]
# 以专用用户启动,并显式指定配置文件。
User=kafka
Group=kafka
ExecStart=/opt/kafka/bin/zookeeper-server-start.sh /etc/kafka/zookeeper.properties
Restart=on-failure
RestartSec=10
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

3. 配置 Kafka Broker​

以下为 kafka-1 的配置。kafka-2、kafka-3 必须分别使用不同的 broker.id、advertised.listeners 与数据卷,不能共享 log.dirs。

# /etc/kafka/server.properties on kafka-1
# Broker ID 在集群内唯一。
broker.id=1
# 实验可使用 PLAINTEXT;生产改用 SSL 或 SASL_SSL 并分离客户端监听器。
listeners=PLAINTEXT://0.0.0.0:9092
# 必须为客户端与其他 Broker 可解析的稳定 DNS,不能填 localhost。
advertised.listeners=PLAINTEXT://kafka-1.example.internal:9092
listener.security.protocol.map=PLAINTEXT:PLAINTEXT
inter.broker.listener.name=PLAINTEXT
# 每台 Broker 独享持久化日志目录。
log.dirs=/var/lib/kafka/logs
# ZooKeeper 模式的协调后端;/kafka 是隔离的 ZooKeeper 路径。
zookeeper.connect=zk-1.example.internal:2181,zk-2.example.internal:2181,zk-3.example.internal:2181/kafka
zookeeper.connection.timeout.ms=18000
# 新 Topic 的可靠性默认值;核心 Topic 仍须显式指定。
num.partitions=3
default.replication.factor=3
min.insync.replicas=2
unclean.leader.election.enable=false
auto.create.topics.enable=false
log.retention.hours=168
# /etc/systemd/system/kafka.service
[Unit]
# Broker 在 ZooKeeper Ensemble 可用后启动;远端 Ensemble 不可达时会自动重试。
After=network-online.target zookeeper.service
Wants=network-online.target

[Service]
# 使用专用账号与受控堆内存;堆大小须基于实际负载和主机内存调优。
User=kafka
Group=kafka
Environment="KAFKA_HEAP_OPTS=-Xms2g -Xmx2g"
ExecStart=/opt/kafka/bin/kafka-server-start.sh /etc/kafka/server.properties
Restart=on-failure
RestartSec=15
LimitNOFILE=100000

[Install]
WantedBy=multi-user.target

4. 启动与验收​

先确保 ZooKeeper 形成法定人数,再启动 Broker。不能同时重启全部 ZooKeeper 节点,否则 Controller 选举和元数据操作会中断。

# 在每台 ZooKeeper 节点重载并启动服务。
sudo systemctl daemon-reload
sudo systemctl enable --now zookeeper

# 在任一 ZooKeeper 节点检查角色;预期为一个 leader、其余为 follower。
echo stat | nc -w 3 127.0.0.1 2181 | rg 'Mode: (leader|follower)'

# ZooKeeper 正常后,在每台 Broker 启动 Kafka 并查看最近日志。
sudo systemctl enable --now kafka
sudo journalctl -u kafka -n 100 --no-pager
# 通过 Broker API 验证;Kafka 3.x 管理命令使用 bootstrap-server。
/opt/kafka/bin/kafka-topics.sh --list \
--bootstrap-server kafka-1.example.internal:9092

# 创建三副本验证 Topic;失败时优先检查 Broker 注册、DNS 和 ZooKeeper 连通性。
/opt/kafka/bin/kafka-topics.sh --create --if-not-exists \
--bootstrap-server kafka-1.example.internal:9092 \
--topic platform.kafka-smoke.v1 --partitions 3 --replication-factor 3

5. 上线后验收​

# 检查每个 ZooKeeper 节点角色,预期一个 leader、两个 follower。
for host in zk-1 zk-2 zk-3; do
echo "== ${host} ==" # 打印节点名,便于审计巡检结果。
echo stat | nc -w 3 "${host}.example.internal" 2181 | rg 'Mode: (leader|follower)'
done

# 确认验证 Topic 的 Replica 和 Isr 列表均包含三个 Broker ID。
/opt/kafka/bin/kafka-topics.sh --describe \
--bootstrap-server kafka-1.example.internal:9092 \
--topic platform.kafka-smoke.v1

# 写入并读取测试消息,验证客户端 DNS、监听器和数据路径。
printf 'deployment-check\n' | /opt/kafka/bin/kafka-console-producer.sh \
--bootstrap-server kafka-1.example.internal:9092 --topic platform.kafka-smoke.v1
/opt/kafka/bin/kafka-console-consumer.sh --from-beginning --max-messages 1 \
--bootstrap-server kafka-1.example.internal:9092 --topic platform.kafka-smoke.v1

上线验收不止是服务启动。还需接入监控、备份配置与变更记录,并验证单个 Broker 重启后 ISR 恢复、生产者 acks=all 写入和消费者位点提交均符合预期。