實際場景:
- 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就可以了。