当 Spring Boot 容器尝试连接 kafka 容器时出现“Broker 可能不可用”错误
Posted
技术标签:
【中文标题】当 Spring Boot 容器尝试连接 kafka 容器时出现“Broker 可能不可用”错误【英文标题】:Getting "Broker may not be available" error when spring boot container tries to connect kafka container 【发布时间】:2021-02-15 22:22:05 【问题描述】:我在使用 spring boot kafka docker 时遇到问题,尝试了以下链接中提到的所有方法,但问题仍然存在。
Spring Boot containers can not connect to the Kafka container
附加我的 docker-compose.yml
version: '2'
services:
zookeeper:
image: wurstmeister/zookeeper
container_name: zookeeper
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
container_name: kafka
ports:
- "9092:9092"
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
my-app:
image: my-app
container_name: my-app
ports:
- "8081:8081"
depends_on:
- zookeeper
- kafka
错误日志
-1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
my-app | 2020-11-03 08:10:21.444 WARN 1 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient : [AdminClient clientId=adminclient-1] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
我正在运行 wrustmiester/kafka 和 wrustmiester/zookeeper。 如果我在本地运行 spring boot 应用程序,一切运行顺利。 当我尝试构建我的 Spring Boot 应用程序的映像并运行该映像时,问题就出现了。然后错误是 Broker 可能不可用。 请哪位大神指导一下。
添加我的 application.yml
spring:
kafka:
consumer:
bootstrap-servers: localhost:9092
group-id: group_id
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
#org.apache.kafka.common.serialization.StringDeserializer
properties.spring.json.trusted.packages: com.myapp.pojo
producer:
bootstrap-servers: localhost:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
#org.apache.kafka.common.serialization.StringSerializer
将我的 docker-compose.yml 更新为
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
container_name: zookeeper
network_mode: bridge
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
container_name: kafka
network_mode: bridge
ports:
- "9092:9092"
hostname: kafka
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
# KAFKA_LISTENERS: INSIDE://:9092,OUTSIDE://:9094
# KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
# KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
KAFKA_ADVERTISED_PORT: 9092
links:
- zookeeper
my-app:
image: my-app
container_name: my-app
network_mode: bridge
ports:
- "8081:8081"
depends_on:
- zookeeper
- kafka
将我的 application.yml 更新为
spring:
kafka:
consumer:
bootstrap-servers: kafka:9092
group-id: group_id
auto-offset-reset: earliest
key-deserializer: org.apache.kafka.common.serialization.StringDeserializer
value-deserializer: org.springframework.kafka.support.serializer.JsonDeserializer
#org.apache.kafka.common.serialization.StringDeserializer
properties.spring.json.trusted.packages: com.myapp.pojo
producer:
bootstrap-servers: kafka:9092
key-serializer: org.apache.kafka.common.serialization.StringSerializer
value-serializer: org.springframework.kafka.support.serializer.JsonSerializer
#org.apache.kafka.common.serialization.StringSerializer
错误日志相同
WARN 1 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient : [AdminClient clientId=adminclient-1] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
my-app | 2020-11-03 17:05:39.585 WARN 1 --- [| adminclient-1] org.apache.kafka.clients.NetworkClient : [AdminClient clientId=adminclient-1] Connection to node -1 (localhost/127.0.0.1:9092) could not be established. Broker may not be available.
【问题讨论】:
见confluent.io/blog/… 只提供链接无济于事,请告诉我哪里出错了 博文中提到,连接localhost是不正确的。在应用容器内,它指的是应用容器,而不是代理。您的生产者和消费者无法连接到应用容器中的任何内容 【参考方案1】:我能够解决我的问题。
这是我更新后的 docker-compose.yml ,其余配置与上面相同
version: '2'
services:
zookeeper:
image: confluentinc/cp-zookeeper:latest
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
kafka:
image: confluentinc/cp-kafka:latest
depends_on:
- zookeeper
ports:
- 9092:9092
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://kafka:29092,PLAINTEXT_HOST://localhost:9092
KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: PLAINTEXT:PLAINTEXT,PLAINTEXT_HOST:PLAINTEXT
KAFKA_INTER_BROKER_LISTENER_NAME: PLAINTEXT
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
my-app:
image: my-app
container_name: my-app
environment:
SPRING_KAFKA_BOOTSTRAPSERVERS: kafka:29092
ports:
- "8081:8081"
depends_on:
- kafka
所做的更改是
我已经使用了 confluent Kafka 和 zookeeper,但即使是上面带有 wrustmeister Kafka 和 zookeeper 的 docker-compose.yml 也可以。
最重要的属性
环境: SPRING_KAFKA_BOOTSTRAPSERVERS: kafka:29092
也如@OneCricketeer 所建议的那样
或者,如果所有三个客户端都在与相同的通信 集群,从生产者和消费者中删除引导服务器,以及 使用 spring.kafka.bootstrap-servers 全局设置它
我觉得即使这样也应该有效。 也许我可以稍后再试一下,然后更新我的答案。
【讨论】:
【参考方案2】:我以几乎相同的方式做了同样的事情(差别很小),看看下面的 compose-file,如果这对你有用
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
ports:
- 2181:2181
kafka:
image: wurstmeister/kafka
ports:
- 9092:9092
hostname: kafka
environment:
- KAFKA_ADVERTISED_HOST_NAME=kafka
- KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181
- KAFKA_ADVERTISED_PORT=9092
links:
- zookeeper
【讨论】:
我是否应该在 application.yml 中为引导服务器提及主机名:localhost:9092,而不是 localhost -> kafka 不,在这种情况下你需要使用服务或容器名称访问 kafka,所以基本上你应该在 application.yml 文件中使用 kafka:9092 是的,我已将 localhost:9092 替换为 kafka:9092。但问题仍然存在 @Ajinkya 然后编辑您的问题以反映更改和新的错误消息 @OneCricketeer,我已经更新了问题,错误依旧。【参考方案3】:您的错误来自 AdminClient,因此,如果您没有在代码中手动创建该实例,则需要为 spring.kafka.admin.*
添加一个配置部分,并在那里设置引导服务器
或者,如果所有三个客户端都在与同一个集群进行通信,则从生产者和消费者中删除引导服务器,并将其设置为全局spring.kafka.bootstrap-servers
由于您使用的是 Docker 网络,因此地址需要是 Kafka 容器的主机名。另请注意,links
是已弃用的 Compose 功能,不应依赖
【讨论】:
你提到的所有细节都无法帮助我解决问题。您能否分享一些代码 sn-ps 并指出我在配置中做错了什么。此外,没有3个客户。我有 1 个与 Apache Kafka 通信的 Spring Boot Rest 应用程序 "您的错误来自 AdminClient,因此,如果您没有在代码中手动创建该实例,则需要使用 bootstrap 为 spring.kafka.admin.* 添加一个配置部分-servers 也设置在那里”-> 当我在本地运行 spring boot 应用程序并在 docker 上运行 Kafka 和 zookeeper 图像时,相同的代码可以工作,所以我认为创建 Admin 实例没有任何问题。请阅读我的问题,如果我遗漏了任何其他细节,请告诉我。 我确实阅读了您的问题。您无法将“在本地运行”与在 Docker 中运行所有内容进行比较。就这么简单——如果你试图在其他任何地方部署你的容器(使用 Docker 的要点),它也不会工作。该错误清楚地表明localhost
仍在某处的代码中使用,并且实际上没有看到您的完整 Spring 应用程序,很难说那会是哪里,因为您的配置文件没有显示(除非管理属性默认为 localhost,而且你没有提到它的部分)。如果您可以在本地运行所有内容,请不要使用 Docker
在本地运行意味着 Spring boot 在本地运行,但 Kafka 和 zookeeper 在 docker 上。所以基本上我的 spring-boot 应用程序与 docker 图像通信。此外,如果您需要任何其他详细信息或配置文件,我已准备好发布它,请告诉我。另外,如果需要,我可以分享我的项目的 GitHub 链接。
我的意思是,Kafka 通常位于远程集群环境中。 (例如,亚马逊 MSK)。在这种情况下,您的代码会出现相同的错误。但是,是的,您的完整堆栈跟踪和创建/使用 AdminClient 的代码是必要的【参考方案4】:
你可以试试这个吗
version: '3'
services:
zookeeper:
image: wurstmeister/zookeeper
container_name: zookeeper
ports:
- "2181:2181"
kafka:
image: wurstmeister/kafka
container_name: kafka
ports:
- "9092:9092"
hostname: kafka
environment:
KAFKA_ADVERTISED_HOST_NAME: kafka
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
# KAFKA_LISTENERS: INSIDE://:9092,OUTSIDE://:9094
# KAFKA_LISTENER_SECURITY_PROTOCOL_MAP: INSIDE:PLAINTEXT,OUTSIDE:PLAINTEXT
# KAFKA_INTER_BROKER_LISTENER_NAME: INSIDE
KAFKA_ADVERTISED_PORT: 9092
links:
- zookeeper
my-app:
image: my-app
container_name: my-app
ports:
- "8081:8081"
depends_on:
- zookeeper
- kafka
networks:
default:
external:
name: bridge
【讨论】:
【参考方案5】:我通过在我的 Spring-Boot 应用程序中配置一个 KafkaAdmin bean 并传递 bootstrap-servers 属性来修复:
@SpringBootApplication
public class CpoExecutorApplication
@Value("$spring.kafka.template.default-topic")
private String topicName;
@Value("$spring.kafka.bootstrap-servers")
private String bootstrapAddress;
@Bean
public KafkaAdmin kafkaAdmin()
Map<String, Object> configs = new HashMap<>();
configs.put(AdminClientConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapAddress);
return new KafkaAdmin(configs);
@Bean
public NewTopic processTopic()
return TopicBuilder.name(topicName).partitions(2).build();
....
application.yml
server:
port: 8000
spring:
kafka:
bootstrap-servers: localhost:9094
consumer:
auto-offset-reset: false
template:
default-topic: process-topic
.....
这样我就不需要在 docker-compose.yml 中传递 SPRING_KAFKA_BOOTSTRAPSERVERS 环境变量了。
【讨论】:
以上是关于当 Spring Boot 容器尝试连接 kafka 容器时出现“Broker 可能不可用”错误的主要内容,如果未能解决你的问题,请参考以下文章
Spring Boot,Java,Docker Compose,尝试在两个容器(mysql,my-api)之间建立连接时出现“连接被拒绝”
Docker:无法连接 Spring Boot 和 MYSQL
无法从 Spring Boot Docker 容器连接 mysql Docker 容器