亲宝软件园·资讯

展开

【原创】为什么我的 Kafka 总是连接失败呢?

东北小狐狸 人气:0
## 提出问题 近日助友 Docker 部署 Kafka 服务,服务日志启动正常,但客户端却无法连接 往日曾踩过此坑,然方法均源于博客,其语焉不详,不知为何不行,亦不知为何行,印象不甚深刻,耗费大量时间 为避此坑,特地学习官方文档相关章节,让我寻到珠丝马迹,请听我娓娓道来~ 如嫌篇幅较长,可跳过验证,直奔结论 本文主要记录为何会出现无法连接到 Broker 的原因,想必看完本文你会知道该怎么做的 :) 谨以此文献给那些因为无知而浪费的时光! ## 大胆猜测 Kafka的服务端称为 `Broker`,每个 Broker 启动时会将自己的 Broker 配置信息上报给 `Zookeeper` ,如,监听地址与端口号等,Kafka的客户端(生产者与消费者统称)要连接 Broker 需要经过一层认证,不通过认证就无法连接! ## 小心求证 ### 测试环境: - GNU/Linux Debian 10 4.19.0内核 - Docker:`19.03.6` - Docker-compose:`1.17.1` - 镜像:`zookeeper:3.5.5` - 镜像:`wurstmeister/kafka:2.12-2.2.1` ### 设计实验: 使用 docker 镜像部署一套单节点的 `Zookeeper` + `Kafka` 要求Broker监听自定义域名(主机名)与端口,服务启动后展示 `Zookeeper` 中 `Broker` 的注册信息 使用客户端连接 `Broker` ,使用不同的 `--bootstrap-server` 组合方式,进行验证 ### 开始实验 为了提高部署效率,这里提供一个简单可启动的 `docker-compose-test.yml` ```yaml version: "3.3" services: zookeeper: image: zookeeper:3.5.5 restart: always container_name: zookeeper ports: - "2181:2181" expose: - "2181" environment: - ZOO_MY_ID=1 kafka: image: wurstmeister/kafka:2.12-2.2.1 restart: always container_name: kafka environment: - KAFKA_BROKER_ID=1 - KAFKA_LISTENERS=PLAINTEXT://kafka:9090 - KAFKA_ZOOKEEPER_CONNECT=zookeeper:2181 - KAFKA_MESSAGE_MAX_BYTES=2000000 ports: - "9090:9090" depends_on: - zookeeper ``` 将 `docker-compose-test.yml` 放入你的目录,运行部署脚本 ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309012513269-1982982116.png) 查看两者的日志,检查是否正常启动 ```bash docker logs -f zookeeper ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309012925576-846797736.png) ```bash docker logs -f kafka ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309013408560-662367560.png) 可以看到 Kafka 已经注册成功 让我们查看一下,Zookeeper 中注册的 Broker 信息 ```bash docker exec -it zookeeper bash bin/zkCli.sh ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309014107520-1584005744.png) 输入 `quit` 退出 想到我们已经将Kafka监听的端口号已经映射到宿主机了,使用宿主机 IP 访问不就得了? 先创建个Topic ```bash docker run -it --rm --network host wurstmeister/kafka:2.12-2.2.1 \ bash /opt/kafka/bin/kafka-topics.sh \ --bootstrap-server 192.168.1.19:9090 \ --create --topic logsTopic --partitions 1 --replication-factor 1 ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309015353135-668033151.png) 噢!又是这该死的错误! 想到刚才在 `zookeeper` 中看到的信息,要不我把 IP 换成 `kafka` 不就结了? ```bash docker run -it --rm --network host wurstmeister/kafka:2.12-2.2.1 \ bash /opt/kafka/bin/kafka-topics.sh \ --bootstrap-server kafka:9090 \ --create --topic logsTopic --partitions 1 --replication-factor 1 ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309015042025-1764613927.png) 不对,宿主机本身没有对 `kafka` 作映射,问题一定出在这里! ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309015854775-1057766554.png) 再次执行刚才的命令,没有输出,说明创建 Topic 成功! ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309020104350-1349176194.png) 生产一条消息测试下 ```bash docker run -it --rm --network host wurstmeister/kafka:2.12-2.2.1 \ bash /opt/kafka/bin/kafka-console-producer.sh \ --broker-list kafka:9090 --topic logsTopic ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309020612665-412307096.png) 输入回车,发送消息; ctrl + c 断开连接 创建消费者,消费消息测试 ```bash docker run -it --rm --network host wurstmeister/kafka:2.12-2.2.1 \ bash /opt/kafka/bin/kafka-console-consumer.sh \ --bootstrap-server kafka:9090 --topic logsTopic --from-beginning ``` ![](https://img2020.cnblogs.com/blog/1149398/202003/1149398-20200309021018678-1101588121.png) 嗯,消费也成功了 ## 归纳总结 这个实验说明了什么呢? 说明 Kafka 客户端在连接 Broker 的时候,Broker 将客户端发来的请求带的信息与 Broker 启动时上报给 Zookeeper 的信息 进行了比对,比对相同则认证通过,反之建立连接失败! ## 官方文档 通过耐心地查看 `Kafka` 的官方文档,终于在角落里看到她的影子!(好久不见妹子,看文档都眉清目秀的~) 比如下面这段: > From Kafka version 2.0.0 onwards, host name verification of servers is enabled by default for client connections as well as inter-broker connections to prevent man-in-the-middle attacks. 大意是讲通过这种`认证hostname`的机制,来避免中间人攻击 还有这段: > **advertised.host.name**: DEPRECATED: only used when `advertised.listeners` or `listeners` are not set. Use `advertised.listeners` instead. Hostname to publish to ZooKeeper for clients to use. In IaaS environments, this may need to be different from the interface to which the broker binds. If this is not set, it will use the value for `host.name` if configured. Otherwise it will use the value returned from java.net.InetAddress.getCanonicalHostName(). 虽然这个参数已经标记为废弃了,但是她提供了个信息:如果设置主机名可能会被上报 最后看看这段 > **advertised.listeners**: Listeners to publish to ZooKeeper for clients to use, if different than the `listeners` config property. In IaaS environments, this may need to be different from the interface to which the broker binds. If this is not set, the value for `listeners` will be used. Unlike `listeners` it is not valid to advertise the 0.0.0.0 meta-address. 也就是说,无论设置 `listeners` 还是 `advertised.listeners` 它们其一的信息会被上报,供客户端使用;只有在需要绑定不同接口时,才需要设置 `advertised.listeners` ## 结论 Kafka 客户端在连接 Broker 的时候,Broker 将客户端发来的请求附加信息与 Broker 启动时上报给 Zookeeper 的 listeners参数信息、host(来自listeners的中间域名或主机名部分)、port (来自listeners的端口部分) 进行了验证,认证通过建立连接执行请求,反之建立连接失败 > 写这篇文章费了好大的功夫,猜是一回事,弄明白又是一回事,如果本文对你有所帮助,欢迎点推荐与关注 引用: https://kafka.apache.orghttps://img.qb5200.com/download-x/documentation.html 本文采用 CC BY 4.0 协议进行授权,转载请标注作者署名及来源。 https://www.cnblogs.com/hellxz/p/why_cnnect_to_kafka_always_failure.html

加载全部内容

相关教程
猜你喜欢
用户评论