KAFKA host deployments across the network blocked Solutions

KAFKA host deployments across the network blocked Solutions

Background to the issue:

Kafka cluster deployment requires not only available, but need to orderer nodes can be connected, which is why sometimes, kafka cluster itself is no problem, but the orderer is always an error. In order to test the feasibility of kafka peel program, Ali cloud across the network and internal network for BAAS deployment.

Deployment environment as follows:

K8s部署在阿里云环境上,
192.168.8.108可连外网,作为master;
192.168.8.107不能连外网,作为slave;

Kafka集群部署在内网,
192.168.9.21等机器上,都可以连外网。

Because orderer will play on the slave node machine, this machine is 107, it can not be directly connected to the Internet. Thus, by forwarding to ensure nginx orderer kafka cluster can be connected, as shown in FIG.

So advertised listeners configuration is particularly important, after all, this is the brokers meta-information stored in the zookeeper kafka node cluster, orderer ultimately through these addresses to access the kafka.

If KAFKA_ADVERTISED_LISTENERS address kafka0 set 192.168.9.21:9092, although normal cluster creation, but orderer can not connect to the network address, which is not even on kafka. Therefore, KAFKA_ADVERTISED_LISTENERS kafka0 address selection will be set 192.168.8.108:9092, then the agent 108 disposed nginx forwarded to the network proxy IP: 9092 (. Reverse proxy, through the IP, the network may be connected to the external network), so that it can connect to the node kafka0.

Setupbaas still trying to find orderer error kafka cluster abnormal, but kafka start logging without any exception.

The setup process is very long, but also to clean up the environment, with kafkaclient to debug a lot easier. go language client fabric using a sarama, simply change it fabric_test inside the producer can play a simple client, to test whether kafka cluster available.

Kafka write data to a producer, given the information found as follows:

Error description, and now this partiton no leader, we know kafka each partiton will have a leader, responsible for client read and write.

为了确认测试用的partition到底有没有leader,通过kafka内部的kafka-topic.sh来查看详细信息,结果如下图所示:

结果发现,topic首先是创建成功了,partition leader也是存在的,那么为什么client没有获取到该partition的leader信息呢?
带着疑问,查看sarama的部分源码,发现传给kafkaclient(例如orderer里面的producer)的addrlist只是作为seedbrokers,从seedbrokers里面尝试去连接kafka server来获取metadata。
这个metadata里面包括了,注册在zk里面的所有brokers的信息, kafkaclient实际上是与这些brokers进行交互的,所以即使seedbroker填的不全,有时候也不影响kafka集群的使用。

流程如下图所示:

根据报错信息,可以发现GetMetadata返回的信息里面有ErrLeaderNotAvailable报错。

由上图可知,GetMetadata向kafkabroker发送了获取metadata的请求,并且key是3。查看kafka源码,可以找到kafkaAPI如何处理key为3的请求。

跳转到 handleTopcMetadataRequest里面:

跳转到getTopicMetadata:

跳转到createTopic:

如果topic不存在,GetMetadata在zk里面注册topic,然而在kafka里面把该topic标记为无leader状态。实际上,每个新建的topic都是处于LEADER_NOT_AVAILABLE的状态的,那问题应该出现在metadata的更新上面,负责管理各个partition状态的组件是controller,是不是controller哪里出了问题了?难道kafka启动日志里有报错被忽略了吗?搜索Controller相关log,发现并没有报错。

ZookeeperLeaderElector: 主要用于KafkController Leader选举,选举出Controller是broker1,但是后续却没有给出controller报错信息。实际上,controller作为kafka的组件,日志另有输出,报错如下,确实是访问不到broker的地址。

controller是随机选择一个kafka节点上启动的,为了同步副本状态,controller需要连接上每一个kafka节点,因为advertised listener地址在容器里访问不到,所以controller与各个broker的连接出现异常。进入容器查看网络连接情况,通过netstat –ae发现其中一个kafka有不正常的连接。

通过zkCli.sh发现,这正是controller所在的kafka,可以坐实是controller的问题了。

问题的原因找到了,但是为什么用kafka自带的脚本查出来的topic状态却是正常的呢?
查看该脚本调用的函数,发现改脚本调用的函数查询的数据居然来自于zk,并不是从kafka中获得。因为所有kafka连接zk并不存在问题,所以可以得出一致的topic 描述,看来使用这个脚本去查看topic状态也得慎重。

GetMetadata有报错,kafka-topic.sh却显示正常,终于有了解释。

Client在GetMetadata的时候,第一次创建了无主topic,在retry的时候,kafkaclient获取的metadata信息是来自于kafka的MetadataCache,因为controller的原因partitionState没有更新,所以返回的topic信息仍然有LEADER_NOT_AVAILABLE报错。

但是为什么正常情况,却没有返回这个LEADER_NOT_AVIALABLE呢?继续往下看:

跳转到getPartitionMetadata:

可见查询partitionMetadata时,是通过partitionState来判断存活的brokers里面是否有leader。如果有partitionState未更新,就返回LEADER_NOT_AVIALABLE的metadata,否则就可以返回最新的metadata。
Controller是如何更新partitionState的呢?
集群所有partition状态是由PartitionStateMachine来管理的。

controller的日志中也可看到:

初始化partition的时候:

进入addLeaderAndIsrRequestForBrokers:

由以上代码可见,partitionState更新需要通过ControllerChannelManager。

ControllerChannelManager负责维护Controller Leader与集群中其他broker之间连接,是管理这个集群的基础。然而,ControllerChannelManager在启动时就出问题了,连不上其他的broker,因此所有的kafka metadata都没能更新。因此,controller必须连上advertised listeners,包括其自身所在的broker。

问题解决方案:

​ 如果将kafka0的KAFKA_ADVERTISED_LISTENERS设为 内网服务映射到外网的IP:9092,阿里云192.168.8.107上倒是可以通过修改host文件,把 内网服务映射到外网的IP 解析成192.168.8.108。这样,107在访问内网IP时,会连到108并通过nginx转发到192.168.9.21:9092。orderer需要连kafka集群的话,需要在k8s容器里添加host才行。

问题总结:

  1. advertised listeners不仅需要让orderer可连接,还需要让每个可能成为controller的kafkabroker容器可连才行。

  2. 这种表面可以创建topic,实际集群无法使用的情况,可以考虑查看controller的日志。

  3. kafka自带的kafka-topic脚本,描述的是zk里面的信息,并不一定于kafka里面的数据一致,需要慎重使用。

Guess you like

Origin www.cnblogs.com/zooqkl/p/10948376.html