我试图在我的Kafka连接设置中尽可能多地构建诊断程序,但它仍然会导致神秘问题。特别是,我做的第一件事是使用Kafka Admin Client来获取clusterId,因为如果此操作失败,则没有其他任何可能成功。
def getKafkaClusterId(describeClusterResult: DescribeClusterResult): Try[String] = {
try {
val clusterId = describeClusterResult.clusterId().get(futureTimeout.length / 2, futureTimeout.unit)
Success(clusterId)
} catch {
case cause: Exception =>
Failure(cause)
}
}
在测试中,这通常有效,一切都很好。它通常仅在端点无法以某种方式到达时失败。它失败是因为未来超时,所以我没有其他的诊断方法。为了测试这些问题,我通常telnet到端点,例如
$ telnet blah 9094
Trying blah...
Connected to blah.
Escape character is '^]'.
Connection closed by foreign host.
通常如果我可以telnet到Kafka经纪人,我可以从我的服务器连接到Kafka。所以我的问题是:
在这种特殊情况下,我通过Docker Swarm在AWS上运行Kafka,并试图找出我的服务器无法成功连接的原因。当我尝试telnet时,我可以在代理日志中看到,所以我知道代理可以访问。但是当我的服务器尝试连接到3个代理中的任何一个时,日志都是完全无声的。
答案 0 :(得分:0)
如果你没有正确配置listeners和advertised.listeners,基本上Kafka就是不听。即使telnet正在侦听您配置的端口,Kafka客户端库也会无声地失败。
我认为这是卡夫卡设计中的一个缺陷,导致不必要的混淆。
答案 1 :(得分:0)
这是一篇很好的文章,解释了第一次连接到Kafka代理时发生的步骤
https://community.hortonworks.com/articles/72429/how-kafka-producer-work-internally.html
如果您可以telnet到引导服务器,那么它正在侦听客户端连接和请求。
但是,客户端不知道哪个真正的代理是主题的每个分区的领导者,因此他们总是发送到引导服务器的第一个请求是获取所有主题元数据的完整列表的元数据请求。客户端使用来自引导服务器的元数据响应来知道它可以在何处与每个Kafka代理建立新连接,并为您要生成的主题的每个主题分区提供活动的领导。
这是您错误配置的经纪人问题发挥作用的地方。当您错误配置advertised.listener端口时,第一个元数据请求的结果是重定向客户端以连接到无法访问的IP地址或主机名。这是第二个连接超时,而不是你正在telnet的端口上的第一个连接。
另一种思考方式是,您必须将Kafka服务器配置为作为引导服务器和常规发布/订阅消息代理正常工作,因为它为客户端提供了这两种服务。您的正确配置为发布/订阅服务器但错误地作为引导服务器,因为AWS中的内部和外部IP地址不同(也在docker容器中或NAT或代理后面)。
在小型集群中,它似乎是反直觉的,其中您的引导服务器通常是客户端最终连接的同一个代理,但它实际上是一种非常有用的架构设计,允许kafka无缝扩展和故障转移,而无需提供引导服务器列表中包含20个或更多代理的静态列表,或者维护额外的负载均衡器和运行状况检查,以了解重定向客户端请求的代理。