最近在搭建基于KRaft模式的Kafka集群时,遇到了消息发送后无法接收的问题。经过反复排查,最终通过调整Broker配置解决了这个典型问题。下面分享完整的Docker部署过程和Spring Boot集成方案。
KRaft是Kafka从2.8版本开始引入的新共识协议,用于替代ZooKeeper。相比传统架构,KRaft模式简化了部署复杂度,提高了集群稳定性。本次部署采用3节点架构:1个Controller节点负责集群元数据管理,2个Broker节点处理消息存储和转发。
注意:生产环境建议使用host网络模式以获得更好性能,测试环境使用bridge模式更方便
Controller节点配置要点:
bash复制docker run -id --privileged=true \
--net=bridge --name=kafka-1 -p 10001:9093 \
-v /data/docker/kafka-1/config:/mnt/shared/config \
-v /data/docker/kafka-1/data:/var/lib/kafka/data \
-v /data/docker/kafka-1/secrets:/etc/kafka/secrets \
-e LANG=C.UTF-8 \
-e KAFKA_INTER_BROKER_LISTENER_NAME=PLAINTEXT \
-e KAFKA_CONTROLLER_LISTENER_NAMES=CONTROLLER \
-e CLUSTER_ID=kafka-cluster \
-e KAFKA_NODE_ID=1 \
-e KAFKA_PROCESS_ROLES=controller \
-e KAFKA_CONTROLLER_QUORUM_VOTERS="1@host.docker.internal:10001" \
-e KAFKA_LISTENERS="CONTROLLER://:9093" \
apache/kafka:3.9.0
关键参数说明:
KAFKA_PROCESS_ROLES=controller:指定节点角色为ControllerKAFKA_CONTROLLER_QUORUM_VOTERS:定义投票成员列表KAFKA_LISTENERS:设置监听协议和端口Broker节点特殊配置:
bash复制-e KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR=2 \
-e KAFKA_AUTO_CREATE_TOPICS_ENABLE=true \
这两个参数解决了消息无法接收的问题:
使用host.docker.internal代替IP地址,这是Docker提供的特殊DNS名称,指向宿主机。相比硬编码IP地址,这种方案更具可移植性。
实测发现:在Linux环境下可能需要额外配置才能使用host.docker.internal,此时可改用实际IP或配置hosts文件
使用Spring Boot 3.3.1和Spring Kafka 3.2.1:
xml复制<dependency>
<groupId>org.springframework.kafka</groupId>
<artifactId>spring-kafka</artifactId>
</dependency>
application.yml配置示例:
yaml复制spring:
kafka:
bootstrap-servers: 127.0.0.1:9092,127.0.0.1:9094
consumer:
group-id: products-group
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.apache.kafka.common.serialization.StringDeserializer
producer:
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.apache.kafka.common.serialization.StringSerializer
template:
default-topic: default-topic
配置说明:
bootstrap-servers:连接所有Broker节点auto-offset-reset: earliest:从最早的消息开始消费消息生产者服务:
java复制@Service
public class KafkaProducerService {
@Autowired
private KafkaTemplate<String, String> kafkaTemplate;
public void sendMessage(String topic, String message) {
kafkaTemplate.send(topic, message)
.thenAccept(result ->
System.out.println("消息发送成功,元数据:" + result.getRecordMetadata()))
.exceptionally(ex -> {
System.err.println("发送失败:" + ex.getMessage());
return null;
});
}
}
消息消费者服务:
java复制@Service
public class KafkaConsumerService {
@KafkaListener(topics = "products_topic", groupId = "csProducts")
public void consume(String message) {
System.out.println("收到消息:" + message);
}
}
REST接口实现:
java复制@PostMapping("ceshi")
public void testEndpoint(@RequestBody CeshiParam param) {
kafkaProducerService.sendMessage("products_topic", param.getMess());
}
问题现象:
解决方案:
KAFKA_AUTO_CREATE_TOPICS_ENABLE是否设置为trueKAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR值不超过Broker数量典型错误:
排查步骤:
在KRaft模式下部署Kafka集群,最关键的是理解角色分配和投票机制。Controller节点负责集群元数据管理,需要保证其稳定性。Broker节点的配置要特别注意副本因子和自动创建主题的设置,这是新手最容易出问题的地方。
Spring Boot集成方面,3.x版本对Kafka客户端的封装已经相当完善,大部分配置都可以通过application.yml完成。对于复杂场景,可以考虑自定义序列化器或拦截器。