KAFKA跨主机部署网络不通解决思路_weixin_30618985的博客-程序员宅基地

技术标签: 运维  大数据  

KAFKA跨主机部署网络不通解决思路

问题背景:

Kafka的部署不仅需要集群可用,同时需要对orderer节点可连,这就是为什么有的时候,kafka集群本身没问题,但是orderer却总是报错。为了试验kafka剥离方案的可行性,跨阿里云网络和内网进行BAAS部署。

部署环境如下:

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

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

因为orderer节点会起在slave机器上,也就是107这台机器,它无法直连外网。因此,通过nginx转发来保证orderer可以连上kafka集群,如下图所示。
1592847-20190530105150256-1674394745.png

那么advertised listeners的配置就尤为重要,毕竟这是kafka节点保存在zookeeper集群中的brokers元信息,orderer最终是通过这些地址去访问kafka的。

如果将kafka0的KAFKA_ADVERTISED_LISTENERS地址设为192.168.9.21:9092,虽然集群创建正常,但是orderer无法连上内网地址,也就是无法连上kafka。所以,选择将kafka0的KAFKA_ADVERTISED_LISTENERS地址设为192.168.8.108:9092,然后在108上设置nginx代理,转发到 内网代理IP:9092(反向代理,通过该ip,外网可以连接内网。),这样就可以连上kafka0节点了。

尝试Setupbaas 发现orderer仍然报错kafka集群异常,但是kafka的启动日志没有任何异常。

setup的流程很长,还要清理环境,用kafkaclient来调试会方便很多。 fabric用的go语言client是sarama,简单改一下fabric_test里面的producer就可以起一个简单的client,来测试kafka集群是否可用了。

用producer向kafka写入数据,发现报错信息如下:

1592847-20190530105212745-2078013124.png

报错说明,现在这个partiton没有leader,我们知道kafka每个partiton都会有一个leader,负责client的读写。

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

1592847-20190530105222228-75484452.png

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

流程如下图所示:
1592847-20190530105239517-1728819725.png

根据报错信息,可以发现GetMetadata返回的信息里面有ErrLeaderNotAvailable报错。
1592847-20190530105249060-1739877215.png
1592847-20190530105256173-937705352.png

由上图可知,GetMetadata向kafkabroker发送了获取metadata的请求,并且key是3。查看kafka源码,可以找到kafkaAPI如何处理key为3的请求。
1592847-20190530105658045-378451285.png
跳转到 handleTopcMetadataRequest里面:
1592847-20190530105712858-1560456550.png
跳转到getTopicMetadata:

1592847-20190530105727792-1701208281.png

跳转到createTopic:

1592847-20190530105734742-1676441787.png

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

1592847-20190530105741581-1467106508.png

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

1592847-20190530105748092-2030858965.png

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

1592847-20190530105755290-1560021524.png

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

1592847-20190530105802986-1633564699.png

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

1592847-20190530105813053-1649104726.png

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

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

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

1592847-20190530105820572-320044825.png

跳转到getPartitionMetadata:

1592847-20190530105828114-1706955971.png

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

1592847-20190530105835298-81425411.png

controller的日志中也可看到:

1592847-20190530105846096-1890240473.png

初始化partition的时候:
1592847-20190530105900078-1754762511.png

进入addLeaderAndIsrRequestForBrokers:
1592847-20190530110033843-491886722.png

由以上代码可见,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里面的数据一致,需要慎重使用。

转载于:https://www.cnblogs.com/zooqkl/p/10948376.html

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接:https://blog.csdn.net/weixin_30618985/article/details/99760051

智能推荐

状语从句_bigdreamerxz的博客-程序员宅基地

一、什么是状语定语:修饰名词的成分主语:发出谓语动作的对象同位语:解释名词的成分宾语:谓语动词的作用对象He runs away.He runs away quickly.run是实意动词,quickly是副词,副词修饰实意动词,做状语He looks exhausted.He looks quite exhausted.quite是副词,修饰形容词exhausted...

mysql的 s是查看什么意思,MySQL和SQLserver的区别_仇子杰TuesdayQ的博客-程序员宅基地

MySQL和SQLserver的区别1、自增长列的插入:SQLServer中可以不为自动增长列插入值,MySQL中需要为自动增长列插入值。2、获取当前时间函数:SQLServer写法:getdate()MySQL写法:now()3、从数据库定位到表。Sqlserver写法:库名.dbo.表名 ;或者:库名..表名(注:中间使用两个点)select password from Info.dbo.us...

二极管和发光二极管_cuihuwu0252的博客-程序员宅基地

二极管的单向导电 二极管是半导体二极管的简称,是由半导体材料制成的.它有两根引线(图15-1),一根叫正极,一根叫负极.二极管的导电性质很特殊.它只允许用流从它的正极流向负极.这很像自行车的气门芯只允许...

java简易的web服务器_简易web服务器(java版)_Cyandev的博客-程序员宅基地

//直接使用 ServerSocket 监听服务器端口,就能实现web服务器package ThreadPoolTest;import java.io.InputStream;import java.io.OutputStream;import java.net.InetAddress;import java.net.ServerSocket;import java.net.Socket;impo...

Kafka生产者ack和lag机制剖析_一只牛_007的博客-程序员宅基地_kafka lag

Kafka有两个很重要的配置参数,acks与min.insync.replicas。其中acks是producer的配置参数,min.insync.replicas是Broker端的配置参数,这两个参数对于生产者不丢失数据起到了很大的作用。接下来,本文会以图示的方式讲解这两个参数的含义和使用方式。通过本文,你可以了解到:Kafka的分区副本 什么是同步副本(In-sync replicas) 什么是acks确认机制 什么是最小同步副本 ack=all与最小同步副本是如何发挥作用的分区副本

随便推点

使用Docker镜像_weixin_34357962的博客-程序员宅基地

镜像(image)是Docker三大核心概念中最为重要的,自Docker诞生之日起“镜像”就是相关社区最为热门的关键词。Docker运行容器前需要本地存在对应的镜像,如果镜像没保存在本地,Docker会尝试先从默认镜像仓库下载(默认使用Docker Hub公共注册服务器中的仓库),用户也可以通过配置,使用自定义的镜像仓库。获取镜像使用docker ...

nyoj 128 前缀式计算_坐看镜花水月的博客-程序员宅基地

描述先说明一下什么是中缀式:如2+(3+4)*5这种我们最常见的式子就是中缀式。而把中缀式按运算顺序加上括号就是:(2+((3+4)*5))然后把运算符写到括号前面就是+(2 *( +(3 4) 5) )把括号去掉就是:+ 2 * + 3 4 5最后这个式子就是该表达式的前缀表示。给你一个前缀表达式,请你计算出该前缀式的值。比如:

1.JAVA开发介绍---1.DOS常用命令_wei15801110272的博客-程序员宅基地

一、DOS使用常识DOS的概况DOS(Disk Operating System)是一个使用得十分广泛的磁盘操作系统,就连眼下流行的Windows9x/ME系统都是以它为基础。常见的DOS有两种:IBM公司的PC-DOS和微软公司的MS-DOS,它们的功能、命令用途格式都相同,我们常用的是MS-DOS。打开命令提示符窗口的方式:win+R > 输入cmd > 回车(最简单)开始...

Python单人贪吃蛇_我帅的是不是无可救药的博客-程序员宅基地

小编的贪吃蛇代码有控制速度,想快的可以自己调。这是如何下载pygame的,大家自己操作!环境首先要准备开发环境:系统:windowsPython版本:3.8,从官网下载安装直接安装就好。IDE:pycharm,官网下载安装需要的Python库pip install pygame测试是否安装成功:D:\WWW\pythonsty\learn>pythonPython 3.8.0 (tags/v3.8.0:fa919fd, Oct 14 2019, 19:37:5.

web项目有叹号且myeclipse不可自动编译_surefire_zl的博客-程序员宅基地

用myeclipse从SVN上down下web项目,类文件不能自动编译,各种办法各种痛苦上网搜索资料都没有解决,无耐加痛苦之中在反其道而行在build path中把jar包全部remove,结果奇迹出现,项目居然可以自动编译了。痛定私痛解决问题原理最重要,web项目上出现叹号基本都是因为项目上jar引用错误导致的,而引用jar包主要是项目的“.classpath”来控制的。.classpa

Golang Redigo连接Redis 简单使用_jhc888007的博客-程序员宅基地

func newPool(host string, db int) *redis.Pool { return &redis.Pool { MaxIdle: 50, MaxActive: 100, Dial: func() (redis.Conn, error) { options := redis.Dial...

推荐文章

热门文章

相关标签