1. 准备工作
- 3台阿里云ECS服务器 (Rocky Linux 9.6 64位)
- jdk17安装包
- kafka安装包
- 安装包格式 : kafka_xx-yy.tgz
- xx是scala版本,yy是kafka版本
- 下载地址 : https://kafka.apache.org/downloads
2 安装包搭建kafka集群
2.1 安装JDK17(三台服务器同样操作)
# 编辑文件
vim /etc/profile
# 将下列内容追加到配置文件
JAVA_HOME=/usr/local/jdk/jdk17
CLASSPATH=$JAVA_HOME/lib/
PATH=$PATH:$JAVA_HOME/bin
export PATH JAVA_HOME CLASSPATH
# 立即生效
source /etc/profile
# 验证是否生效
java -version
2.2 搭建kafka集群
2.2.1 修改配置文件 (/安装包解压路径/config/kraft/server.properties)
########################### 节点1 ###########################
# 指定当前Kafka服务器所扮演的角色,配置多个角色,角色之间使用逗号进行分隔
# controller: 指定当前服务器为Kafka集群的Controller,负责管理整个集群的状态和拓扑结构
# broker: 指定当前服务器为普通的Kafka Broker,负责接收和处理消息
# 例如配置 process.roles=controller,broker 表示当前服务器既是Controller,也是一个普通的 Broker
process.roles=broker,controller
# 节点id:和选举相关,全局唯一(和下面的quorum后的编号一致)
# 在Kafka-Kraft架构中, node.id的值与broker.id的值是相同的,用于指定当前服务器在集群中的唯一标识符
node.id=1
# 用于配置Controller节点的选举投票者的配置项,它指定了在控制器选举过程中要参与投票的节点
# 至少需要三个节点才能形成有效的选举quorum,配置的节点必须是有效的Kafka-Kraft集群节点,且node.id必须唯一
controller.quorum.voters=1@172.19.146.151:9093,2@172.19.240.110:9093,3@172.19.240.111:9093
# 不同服务绑定的端口
listeners=PLAINTEXT://172.19.146.151:9092,CONTROLLER://172.19.146.151:9093
# 用于向生产者和消费者提供用于连接到Kafka服务器的地址和端口
# 通常与listeners配置一起使用,但如果Kafka服务器之间使用不同的网络接口通信,可以指定不同的地址
advertised.listeners=PLAINTEXT://172.19.146.151:9092
# 配置Kafka服务器存储日志文件的目录路径。可以指定多个目录,用逗号分隔。
log.dirs=/usr/local/kafka/kafka_2.12-3.7.1/logs
########################### 节点2 ###########################
# 指定当前Kafka服务器所扮演的角色,配置多个角色,角色之间使用逗号进行分隔
# controller: 指定当前服务器为Kafka集群的Controller,负责管理整个集群的状态和拓扑结构
# broker: 指定当前服务器为普通的Kafka Broker,负责接收和处理消息
# 例如配置 process.roles=controller,broker 表示当前服务器既是Controller,也是一个普通的 Broker
process.roles=broker,controller
# 节点id:和选举相关,全局唯一(和下面的quorum后的编号一致)
# 在Kafka-Kraft架构中, node.id的值与broker.id的值是相同的,用于指定当前服务器在集群中的唯一标识符
node.id=2
# 用于配置Controller节点的选举投票者的配置项,它指定了在控制器选举过程中要参与投票的节点
# 至少需要三个节点才能形成有效的选举quorum,配置的节点必须是有效的Kafka-Kraft集群节点,且node.id必须唯一
controller.quorum.voters=1@172.19.146.151:9093,2@172.19.240.110:9093,3@172.19.240.111:9093
# 不同服务绑定的端口
listeners=PLAINTEXT://172.19.240.110:9092,CONTROLLER://172.19.240.110:9093
# 用于向生产者和消费者提供用于连接到Kafka服务器的地址和端口
# 通常与listeners配置一起使用,但如果Kafka服务器之间使用不同的网络接口通信,可以指定不同的地址
advertised.listeners=PLAINTEXT://172.19.240.110:9092
# 配置Kafka服务器存储日志文件的目录路径。可以指定多个目录,用逗号分隔。
log.dirs=/usr/local/kafka/kafka_2.12-3.7.1/logs
########################### 节点3 ###########################
# 指定当前Kafka服务器所扮演的角色,配置多个角色,角色之间使用逗号进行分隔
# controller: 指定当前服务器为Kafka集群的Controller,负责管理整个集群的状态和拓扑结构
# broker: 指定当前服务器为普通的Kafka Broker,负责接收和处理消息
# 例如配置 process.roles=controller,broker 表示当前服务器既是Controller,也是一个普通的 Broker
process.roles=broker,controller
# 节点id:和选举相关,全局唯一(和下面的quorum后的编号一致)
# 在Kafka-Kraft架构中, node.id的值与broker.id的值是相同的,用于指定当前服务器在集群中的唯一标识符
node.id=3
# 用于配置Controller节点的选举投票者的配置项,它指定了在控制器选举过程中要参与投票的节点
# 至少需要三个节点才能形成有效的选举quorum,配置的节点必须是有效的Kafka-Kraft集群节点,且node.id必须唯一
controller.quorum.voters=1@172.19.146.151:9093,2@172.19.240.110:9093,3@172.19.240.111:9093
# 不同服务绑定的端口
listeners=PLAINTEXT://172.19.240.111:9092,CONTROLLER://172.19.240.111:9093
# 用于向生产者和消费者提供用于连接到Kafka服务器的地址和端口
# 通常与listeners配置一起使用,但如果Kafka服务器之间使用不同的网络接口通信,可以指定不同的地址
advertised.listeners=PLAINTEXT://172.19.240.111:9092
# 配置Kafka服务器存储日志文件的目录路径。可以指定多个目录,用逗号分隔。
log.dirs=/usr/local/kafka/kafka_2.12-3.7.1/logs
PS : 本地SpringBoot服务连接kafka集群的时候需要把advertised.listeners的内网IP改成公网IP
2.2.2 搭建集群
# 任一节点执行下列命令,并保存输出结果,例如:1rixITfMSO2l-NvXwlyf9A
echo "$(/usr/local/kafka/kafka_2.12-3.7.1/bin/kafka-storage.sh random-uuid)"
# 写入token,三台都执行如下命令
/usr/local/kafka/kafka_2.12-3.7.1/bin/kafka-storage.sh \
format -t 1rixITfMSO2l-NvXwlyf9A \
-c /usr/local/kafka/kafka_2.12-3.7.1/config/kraft/server.properties
# 查看配置是否生效,三台都执行如下命令
cat /usr/local/kafka/kafka_2.12-3.7.1/logs/meta.properties
# 启动集群信息
/usr/local/kafka/kafka_2.12-3.7.1/bin/kafka-server-start.sh /usr/local/kafka/kafka_2.12-3.7.1/config/kraft/server.properties
PS : 如果搭建的过程中出现错误,找到配置文件server.properties中log.dirs指定的目录,删除目录下的__cluster_metadata-0、meta.properties,再按照3.2的步骤重新搭建
2.2.3 验证集群
# 任一节点创建topic
./kafka-topics.sh --create --replication-factor 3 --partitions 3 --topic test-topic --bootstrap-server 172.19.146.151:9092
# 其他节点查看topic
./kafka-topics.sh --list --bootstrap-server 172.19.146.151:9092
./kafka-topics.sh --list --bootstrap-server 172.19.240.110:9092
./kafka-topics.sh --list --bootstrap-server 172.19.240.111:9092
3. docker搭建kafka集群
3.1 创建文件夹(三台服务器同样操作)
# 创建文件件
mkdir -p /usr/local/software/kafka/{config,logs}
# 修改权限
chmod a+w /usr/local/software/kafka/logs
3.2 创建配置文件 server.properties
########################### 节点1 ###########################
process.roles=broker,controller
node.id=1
controller.quorum.voters=1@kafka1:9093,2@kafka2:9093,3@kafka3:9093
listeners=PLAINTEXT://kafka1:9092,CONTROLLER://kafka1:9093
advertised.listeners=PLAINTEXT://kafka1:9092
log.dirs=/opt/kafka/logs
########################### 节点2 ###########################
process.roles=broker,controller
node.id=2
controller.quorum.voters=1@kafka1:9093,2@kafka2:9093,3@kafka3:9093
listeners=PLAINTEXT://kafka2:9092,CONTROLLER://kafka2:9093
advertised.listeners=PLAINTEXT://kafka2:9092
log.dirs=/opt/kafka/logs
########################### 节点3 ###########################
process.roles=broker,controller
node.id=3
controller.quorum.voters=1@kafka1:9093,2@kafka2:9093,3@kafka3:9093
listeners=PLAINTEXT://kafka3:9092,CONTROLLER://kafka3:9093
advertised.listeners=PLAINTEXT://kafka3:9092
log.dirs=/opt/kafka/logs
3.3 生成cluster_id
# 拉取镜像
docker pull apache/kafka:3.7.1
# 任一节点执行,并保存结果,例如 Z2dR-1puS6Cmi3UGYby9Ow
echo $(docker run --rm apache/kafka:3.7.1 /opt/kafka/bin/kafka-storage.sh random-uuid)
3.4 执行docker命令
# 节点1
docker run -d \
--name kafka1 \
--network host \
--add-host kafka1:172.19.146.151 \
--add-host kafka2:172.19.240.110 \
--add-host kafka3:172.19.240.111 \
-p 9092:9092 \
-p 9093:9093 \
-v /usr/local/software/kafka/config/server.properties:/opt/kafka/config/kraft/server.properties \
-v /usr/local/software/kafka/logs:/opt/kafka/logs \
apache/kafka:3.7.1 \
sh -c "(if [ ! -d /usr/local/software/kafka/logs/__cluster_metadata-0 ];then
/opt/kafka/bin/kafka-storage.sh format -t Z2dR-1puS6Cmi3UGYby9Ow -c /opt/kafka/config/kraft/server.properties
fi) && /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties"
# 节点2
docker run -d \
--name kafka2 \
--network host \
--add-host kafka1:172.19.146.151 \
--add-host kafka2:172.19.240.110 \
--add-host kafka3:172.19.240.111 \
-p 9092:9092 \
-p 9093:9093 \
-v /usr/local/software/kafka/config/server.properties:/opt/kafka/config/kraft/server.properties \
-v /usr/local/software/kafka/logs:/opt/kafka/logs \
apache/kafka:3.7.1 \
sh -c "(if [ ! -d /usr/local/software/kafka/logs/__cluster_metadata-0 ];then
/opt/kafka/bin/kafka-storage.sh format -t Z2dR-1puS6Cmi3UGYby9Ow -c /opt/kafka/config/kraft/server.properties
fi) && /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties"
# 节点3
docker run -d \
--name kafka3 \
--network host \
--add-host kafka1:172.19.146.151 \
--add-host kafka2:172.19.240.110 \
--add-host kafka3:172.19.240.111 \
-p 9092:9092 \
-p 9093:9093 \
-v /usr/local/software/kafka/config/server.properties:/opt/kafka/config/kraft/server.properties \
-v /usr/local/software/kafka/logs:/opt/kafka/logs \
apache/kafka:3.7.1 \
sh -c "(if [ ! -d /usr/local/software/kafka/logs/__cluster_metadata-0 ];then
/opt/kafka/bin/kafka-storage.sh format -t Z2dR-1puS6Cmi3UGYby9Ow -c /opt/kafka/config/kraft/server.properties
fi) && /opt/kafka/bin/kafka-server-start.sh /opt/kafka/config/kraft/server.properties"
4. SpringBoot集成kafka
4.1 加入kafka依赖
<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
4.2 yaml配置
spring :
kafka:
bootstrap-servers:
- IP1:9092
- IP2:9092
- IP3:9092
producer:
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
consumer:
auto-commit-interval: 1s
enable-auto-commit: false
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
listener:
ack-mode: manual_immediate
logging:
level:
org.apache.kafka.clients.consumer.internals.ConsumerCoordinator: ERROR
4.3 KafkaConfig和KafkaMQListener
@Configuration
public class KafkaConfig {
public static final String TOPIC_NAME = "boot_test_topic";
@Bean
public NewTopic topic() {
return TopicBuilder.name(TOPIC_NAME)
.partitions(3)
.compact()
.build();
}
}
@Component
public class KafkaMQListener {
@KafkaListener(topics = {KafkaConfig.TOPIC_NAME}, groupId = "boot_test_topic_group_1")
public void onMessage(ConsumerRecord<?, ?> record, Acknowledgment ack, @Header(KafkaHeaders.RECEIVED_TOPIC) String topic) {
System.out.println("消费:" + topic + "-" + record.partition() + "-" + record.value());
ack.acknowledge();
}
}