Kafka 4.1.1 三节点 Ubuntu 集群部署指南
概述
本指南详细介绍如何在Ubuntu环境下部署高可用的 Apache Kafka 4.1.1 三节点集群。本方案采用 KRaft 模式(Kafka Raft Metadata),无需 Zookeeper,通过三节点仲裁机制实现高可用性和数据一致性。
本部署方案基于:
- JDK 17:使用最新的LTS版本Java运行环境
- Kafka 4.1.1:最新的稳定版本,包含性能优化和安全增强
- Ubuntu 20.04+:推荐的部署操作系统
为什么选择三节点集群?
- 高可用性:任意单节点故障不影响服务连续性
- 数据安全:三副本机制保证数据不丢失
- 性能优化:负载均衡,提升整体吞吐量
- 故障自愈:自动故障检测和恢复机制
- 扩展性强:支持后续横向扩展
为什么选择 KRaft 模式?
- 架构简化:无需 Zookeeper,减少组件和故障点
- 性能提升:元数据管理更高效,延迟更低
- 运维成本降低:减少维护组件,简化部署
- 未来趋势:Kafka 官方推荐的部署方式
- 扩展性更好:支持更大规模的集群
集群架构优势
- Raft 协议:保证元数据一致性
- 控制器仲裁:三节点投票机制确保决策正确性
- 数据副本:每个分区在三个节点上都有副本
- 自动故障切换:秒级故障检测和恢复
目录
1. 架构设计
1.1 三节点高可用架构
1.2 KRaft 模式组件说明
| 组件 | 说明 | 作用 |
|---|---|---|
| Broker | Kafka 代理节点 | 处理生产者/消费者请求,存储和检索消息 |
| Controller | 控制器节点 | 管理集群元数据,协调分区副本 |
| Quorum Controller | 控制器仲裁组 | 三个 Controller 组成仲裁组,通过 Raft 协议保证元数据一致性 |
| Log Segments | 日志段 | 实际的消息数据存储单元 |
1.3 高可用机制
1.3.1 Raft 仲裁机制
- 三节点仲裁: 任意 2 个节点达成一致即可做出决策
- 故障容忍:支持 1 个节点故障不影响集群运行
- 自动选举:故障节点恢复后自动重新加入集群
1.3.2 数据副本机制
- 三副本:每个分区在三个节点上都有副本
- ISR 机制:维护 In-Sync Replicas 列表
- Leader 选举:分区 Leader 故障时自动切换
1.3.3 故障恢复机制
- 秒级检测:快速发现节点故障
- 自动切换:无需人工干预
- 数据一致性:保证故障切换过程中数据不丢失
2. 前置条件
2.1 硬件要求
| 组件 | 最低配置 | 推荐配置 |
|---|---|---|
| CPU | 2核 | 4核及以上 |
| 内存 | 4GB | 8GB及以上 |
| 存储 | 100GB | 500GB SSD |
| 网络 | 1Gbps | 10Gbps |
2.2 软件要求
- Ubuntu 20.04 LTS 或更高版本
- Java 17 LTS(推荐)或 Java 11
- 时间同步服务(chrony 或 ntp)
- Kafka 4.1.1
2.3 网络规划
| 节点 | IP 地址 | 主机名 | 角色 |
|---|---|---|---|
| 节点1 | 192.168.192.211 | ubuntu-kafka-node1 | Broker + Controller |
| 节点2 | 192.168.192.212 | ubuntu-kafka-node2 | Broker + Controller |
| 节点3 | 192.168.192.213 | ubuntu-kafka-node3 | Broker + Controller |
2.4 端口规划
| 端口 | 用途 | 协议 | 说明 |
|---|---|---|---|
| 9092 | 客户端通信 | TCP | PLAINTEXT |
| 9093 | 控制器通信 | TCP | CONTROLLER |
| 9094 | SSL通信 | TCP | 可选 |
| 9999 | JMX监控 | TCP | 监控端口 |
3. 手动部署指南
3.1 环境准备
3.1.1 系统初始化(所有节点)
# 更新系统
sudo apt update && sudo apt upgrade -y
# 安装必要工具
sudo apt install -y wget curl vim git net-tools iputils-ping
# 创建 kafka 用户
sudo useradd -m -s /bin/bash kafka
# 创建相关目录
sudo mkdir -p /opt/kafka
sudo mkdir -p /data/kafka/data
sudo mkdir -p /var/log/kafka
# 设置目录权限
sudo chown -R kafka:kafka /opt/kafka
sudo chown -R kafka:kafka /data/kafka
sudo chown -R kafka:kafka /var/log/kafka
3.1.2 配置时间同步
# 安装 chrony
sudo apt install -y chrony
# 配置时间服务器
sudo tee /etc/chrony/chrony.conf > /dev/null <<EOF
server time1.aliyun.com iburst
server time2.aliyun.com iburst
server ntp.aliyun.com iburst
makestep 1.0 3
rtcsync
EOF
# 重启 chrony 服务
sudo systemctl restart chronyd
sudo systemctl enable chronyd
# 验证时间同步
chronyc sources
3.1.3 配置防火墙
# Ubuntu/Debian (ufw) 防火墙配置
# 开放 Kafka 端口
sudo ufw allow 9092/tcp # PLAINTEXT
sudo ufw allow 9093/tcp # CONTROLLER
sudo ufw allow 9094/tcp # SSL(可选)
sudo ufw allow 9999/tcp # JMX
# 启用防火墙
sudo ufw --force enable
# 验证规则
sudo ufw status
3.1.4 配置主机名解析
在每个节点上编辑 /etc/hosts:
sudo tee -a /etc/hosts > /dev/null <<EOF
192.168.192.211 ubuntu-kafka-node1
192.168.192.212 ubuntu-kafka-node2
192.168.192.213 ubuntu-kafka-node3
EOF
3.2 安装 Java
# 安装 OpenJDK 17(推荐)
sudo apt install -y openjdk-17-jdk
# 或者安装 OpenJDK 11(兼容)
# sudo apt install -y openjdk-11-jdk
# 验证安装
java -version
# 设置 JAVA_HOME(推荐使用JDK 17)
echo 'export JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64' >> ~/.bashrc
echo 'export PATH=$JAVA_HOME/bin:$PATH' >> ~/.bashrc
source ~/.bashrc
3.3 安装 Kafka
在每个节点上执行以下操作:
# 下载 Kafka
cd /opt
wget https://downloads.apache.org/kafka/4.1.1/kafka_2.13-4.1.1.tgz
# 解压
tar -zxvf kafka_2.13-4.1.1.tgz -C /opt/kafka --strip-components=1
# 设置目录权限
sudo chown -R kafka:kafka /opt/kafka
3.4 配置 Kafka
3.4.1 节点1配置(ubuntu-kafka-node1)
创建 config/kraft/server.properties:
# 创建必要的目录
mkdir -p /opt/kafka/config/kraft
cat > /opt/kafka/config/kraft/server.properties << 'EOF'
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
############################# 服务器基础配置 #############################
# 服务器的角色设置,设置此参数使我们进入KRaft模式
process.roles=broker,controller
# 与此实例角色关联的节点ID
node.id=1
# 用于连接到控制器集群的控制器端点列表
controller.quorum.voters=1@ubuntu-kafka-node1:9093,2@ubuntu-kafka-node2:9093,3@ubuntu-kafka-node3:9093
############################# Socket服务器设置 #############################
# Socket服务器监听的地址
# 组合节点(即具有`process.roles=broker,controller`的节点)必须在此处至少列出控制器监听器
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
# 用于代理间通信的监听器名称
inter.broker.listener.name=PLAINTEXT
# 代理或控制器将向客户端通告的监听器名称、主机名和端口
advertised.listeners=PLAINTEXT://192.168.192.211:9092
# 控制器使用的监听器名称列表
controller.listener.names=CONTROLLER
# 将监听器名称映射到安全协议,默认情况下它们是相同的
listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL
# 服务器用于接收网络请求和发送响应的线程数
num.network.threads=8
# 服务器用于处理请求的线程数,可能包括磁盘I/O
num.io.threads=16
# Socket服务器使用的发送缓冲区(SO_SNDBUF)
socket.send.buffer.bytes=102400
# Socket服务器使用的接收缓冲区(SO_RCVBUF)
socket.receive.buffer.bytes=102400
# Socket服务器将接受的请求的最大大小(防止OOM保护)
socket.request.max.bytes=104857600
############################# 日志基础配置 #############################
# 存储日志文件的目录列表
log.dirs=/data/kafka/data
# 每个主题的默认日志分区数。更多的分区允许更大的消费并行性
num.partitions=6
# 每个数据目录用于启动时日志恢复和关闭时刷新的线程数
num.recovery.threads.per.data.dir=4
############################# 内部主题设置 #############################
# 组元数据内部主题"__consumer_offsets"、"__share_group_state"和"__transaction_state"的复制因子
offsets.topic.replication.factor=3
share.coordinator.state.topic.replication.factor=3
share.coordinator.state.topic.min.isr=2
transaction.state.log.replication.factor=3
transaction.state.log.min.isr=2
# 控 制器引导服务器列表
controller.quorum.bootstrap.servers=ubuntu-kafka-node1:9093,ubuntu-kafka-node2:9093,ubuntu-kafka-node3:9093
############################# 日志刷新策略 #############################
# 消息立即写入文件系统,但默认情况下我们只懒惰地fsync()同步OS缓存
# 在强制将数据刷新到磁盘之前接受的消息数
log.flush.interval.messages=10000
# 消息在日志中停留的最长时间,之后我们强制刷新
log.flush.interval.ms=1000
############################# 日志保留策略 #############################
# 以下配置控制日志段的处理。策略可以设置为在一段时间后或累积到给定大小后删除段
# 有资格因年龄而被删除的日志文件的最小年龄
log.retention.hours=168
# 日志段文件的最大大小。达到此大小时将创建新的日志段
log.segment.bytes=1073741824
# 检查日志段是否可以根据保留策略删除的间隔
log.retention.check.interval.ms=300000
# 自动创建主题
auto.create.topics.enable=true
# 删除主题
delete.topic.enable=true
# 组协调器配置
group.initial.rebalance.delay.ms=0
# JMX 端口
JMX_PORT=9999
EOF
3.4.2 节点2配置(ubuntu-kafka-node2)
创建配置文件:
# 创建必要的目录
mkdir -p /opt/kafka/config/kraft
cat > /opt/kafka/config/kraft/server.properties << 'EOF'
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
############################# 服务器基础配置 #############################
# 服务器的角色设置 ,设置此参数使我们进入KRaft模式
process.roles=broker,controller
# 与此实例角色关联的节点ID
node.id=2
# 用于连接到控制器集群的控制器端点列表
controller.quorum.voters=1@ubuntu-kafka-node1:9093,2@ubuntu-kafka-node2:9093,3@ubuntu-kafka-node3:9093
############################# Socket服务器设置 #############################
# Socket服务器监听的地址
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
# 用于代理间通信的监听器名称
inter.broker.listener.name=PLAINTEXT
# 代理或控制器将向客户端通告的监听器名称、主机名和端口
advertised.listeners=PLAINTEXT://192.168.192.212:9092
# 控制器使用的监听器名称列表
controller.listener.names=CONTROLLER
# 将监听器名称映射到安全协议,默认情况下它们是相同的
listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL
# 服务器用于接收网络请求和发送响应的线程数
num.network.threads=8
# 服务器用于处理请求的线程数,可能包括磁盘I/O
num.io.threads=16
# Socket服务器使用的发送缓冲区(SO_SNDBUF)
socket.send.buffer.bytes=102400
# Socket服务器使用的接收缓冲区(SO_RCVBUF)
socket.receive.buffer.bytes=102400
# Socket服务器将接受的请求的最大大小(防止OOM保护)
socket.request.max.bytes=104857600
############################# 日志基础配置 #############################
# 存储日志文件的目录列表
log.dirs=/data/kafka/data
# 每个主题的默认日志分区数
num.partitions=6
# 每个数据目录用于启动时日志恢复和关闭时刷新的线程数
num.recovery.threads.per.data.dir=4
############################# 内部主题设置 #############################
# 组元数据内部主题的复制因子
offsets.topic.replication.factor=3
share.coordinator.state.topic.replication.factor=3
share.coordinator.state.topic.min.isr=2
transaction.state.log.replication.factor=3
transaction.state.log.min.isr=2
# 控制器引导服务器列表
controller.quorum.bootstrap.servers=ubuntu-kafka-node1:9093,ubuntu-kafka-node2:9093,ubuntu-kafka-node3:9093
############################# 日志刷新策略 #############################
# 在强制将数据刷新到磁盘之前接受的消息数
log.flush.interval.messages=10000
# 消息在日志中停留的最长时间,之后我们强制刷新
log.flush.interval.ms=1000
############################# 日志保留策略 #############################
# 有资格因年龄而被删除的日志文件的最小年龄
log.retention.hours=168
# 日志段文件的最大大小
log.segment.bytes=1073741824
# 检查日志段是否可以根据保留策略删除的间隔
log.retention.check.interval.ms=300000
# 自动创建主题
auto.create.topics.enable=true
# 删除主题
delete.topic.enable=true
# 组协调器配置
group.initial.rebalance.delay.ms=0
# JMX 端口
JMX_PORT=9999
EOF
3.4.3 节点3配置(ubuntu-kafka-node3)
创建配置文件:
# 创建必要的目录
mkdir -p /opt/kafka/config/kraft
cat > /opt/kafka/config/kraft/server.properties << 'EOF'
# Licensed to the Apache Software Foundation (ASF) under one or more
# contributor license agreements. See the NOTICE file distributed with
# this work for additional information regarding copyright ownership.
# The ASF licenses this file to You under the Apache License, Version 2.0
# (the "License"); you may not use this file except in compliance with
# the License. You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
############################# 服务器基础配置 #############################
# 服务器的角色设置,设置此参数使我们进入KRaft模式
process.roles=broker,controller
# 与此实例角色关联的节点ID
node.id=3
# 用于连接到控制器集群的控制器端点列表
controller.quorum.voters=1@ubuntu-kafka-node1:9093,2@ubuntu-kafka-node2:9093,3@ubuntu-kafka-node3:9093
############################# Socket服务器设置 #############################
# Socket服务器监听的地址
listeners=PLAINTEXT://:9092,CONTROLLER://:9093
# 用于代理间通信的监听器名称
inter.broker.listener.name=PLAINTEXT
# 代理或控制器将向客户端通告的监听器名称、主机名和端口
advertised.listeners=PLAINTEXT://192.168.192.213:9092
# 控制器使用的监听器名称列表
controller.listener.names=CONTROLLER
# 将监听器名称映射到安全协议,默认情况下它们是相同的
listener.security.protocol.map=CONTROLLER:PLAINTEXT,PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL
# 服务器用于接收网络请求和发送响应的线程数
num.network.threads=8
# 服务器用于处理请求的线程数,可能包括磁盘I/O
num.io.threads=16
# Socket服务器使用的发送缓冲区(SO_SNDBUF)
socket.send.buffer.bytes=102400
# Socket服务器使用的接收缓冲区(SO_RCVBUF)
socket.receive.buffer.bytes=102400
# Socket服务器将接受的请求的最大大小(防止OOM保护)
socket.request.max.bytes=104857600
############################# 日志基础配置 #############################
# 存储日志文件的目录列表
log.dirs=/data/kafka/data
# 每个主题的默认日志分区数
num.partitions=6
# 每个数据目录用于启动时日志恢复和关闭时刷新的线程数
num.recovery.threads.per.data.dir=4
############################# 内部主题设置 #############################
# 组元数据内部主题的复制因子
offsets.topic.replication.factor=3
share.coordinator.state.topic.replication.factor=3
share.coordinator.state.topic.min.isr=2
transaction.state.log.replication.factor=3
transaction.state.log.min.isr=2
# 控制器引导服务器列表
controller.quorum.bootstrap.servers=ubuntu-kafka-node1:9093,ubuntu-kafka-node2:9093,ubuntu-kafka-node3:9093
############################# 日志刷新策略 #############################
# 在强制将数据刷新到磁盘之前接受的消息数
log.flush.interval.messages=10000
# 消息在日志中停留的最长时间,之后我们强制刷新
log.flush.interval.ms=1000
############################# 日志保留策略 #############################
# 有资格因年龄而被删除的日志文件的最小年龄
log.retention.hours=168
# 日志段文件的最大大小
log.segment.bytes=1073741824
# 检查日志段是否可以根据保留策略删除的间隔
log.retention.check.interval.ms=300000
# 自动创建主题
auto.create.topics.enable=true
# 删除主题
delete.topic.enable=true
# 组协调器配置
group.initial.rebalance.delay.ms=0
# JMX 端口
JMX_PORT=9999
EOF
3.5 创建系统服务
创建 systemd 服务文件 /etc/systemd/system/kafka.service:
cat > /etc/systemd/system/kafka.service << 'EOF'
[Unit]
Description=Apache Kafka
After=network.target
[Service]
Type=simple
User=kafka
Group=kafka
Environment="JAVA_HOME=/usr/lib/jvm/java-17-openjdk-amd64"
ExecStart=/opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties
ExecStop=/opt/kafka/bin/kafka-server-stop.sh
Restart=on-failure
RestartSec=10
[Install]
WantedBy=multi-user.target
EOF
3.6 集群初始化
3.6.1 生成集群 ID
在任意一个节点上执行:
# 生成集群 ID
cd /opt/kafka
./bin/kafka-storage.sh random-uuid
输出示例:
Slj9VqO5Q8mqVgamNQ5CHw
3.6.2 格式化存储目录
在所有节点上执行格式化命令:
# 格式化存储目录
./bin/kafka-storage.sh format -t Slj9VqO5Q8mqVgamNQ5CHw -c /opt/kafka/config/kraft/server.properties
3.5.3 启动 Kafka 服务
在所有节点上启动 Kafka 服务:
# 重新加载 systemd 配置
sudo systemctl daemon-reload
# 启用开机自启
sudo systemctl enable kafka
# 启动 Kafka 服务
sudo systemctl start kafka
# 检查服务状态
sudo systemctl status kafka
# 查看日志
tail -f /opt/kafka/logs/server.log