实际场景:
- kafka应用通过docker进行部署并暴露出不同kafka节点到不同的指定端口;
- 业务系统通过虚拟机进行部署;
- docker宿主机与业务系统在同一个局域网;
报错:
- 业务系统连接kafka时返回docker kafka服务名及原端口(9092)
- can not found the leader of kafka
原因:
- kafka配置文件server.properties中,host.name只绑定在了内部的IP上面,对外的网卡无法访问,及在物理业务系统服务器上面并不能识别到kafka服务名;
- 把值设置为空的话会kafka监听端口在所有的网卡上绑定。但是在外网访问时,客户端又遇到了“java.nio.channels.ClosedChannelException”异常信息,server端用tcpdump分析的时候发现客户端有传递kafka所在容器的服务名过来。在client里断点跟踪一下发现是findLeader的时候返回的元信息是容器服务名而不是IP。业务系统客户端无法解析这个机器名所以出现了前面的异常。
在server.properties 里还有另一个参数是解决这个问题的, advertised.host.name参数用来配置返回的host.name值,把这个参数配置为局域网IP地址即可。
这个参数默认没有启用,默认是返回的java.net.InetAddress.getCanonicalHostName的值。
除了IP之外,还有PORT,外网对应的PORT也需要修改。
以下是server.properties文件对应位置。
针对docker容器可以用环境变量参数将具体的参数传递进去:
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://xxx.xxx.xxx.xxx:port (局域网宿主机的IP地址而非容器的IP,及暴露出来的端口)
针对局域网向公网IP端口暴露的话,这修改配置文件,加入以下配置:
advertised.listeners=PLAINTEXT://xxx.xxx.xxx.xxx:port
当Kafka broker启动时,它会在ZK上注册自己的IP和端口号,客户端就通过这个IP和端口号来连接。此时就需要显示指定 advertised.host.name, advertised.listeners参数,让注册到ZK上的IP是外外部IP。需要在 server.properties 配置文件里增加如下配置(版本0.10.x broker及之后的新版本):
新版本0.10.x broker配置弃用了advertised.host.name和 advertised.port这两个个配置项,就配置advertised.listeners就可以了。