背景

事情是这样的,我们在外地有一套资源池,我们需要通过kafka把数据拿到本地资源池来进行计算。资源池之间通过承载网传输,我们所谓的承载网是一种可以跨资源池的内网,这里为和资源池内部的网络作区分,我把承载网称为外网,资源池内部的网络称为内网。资源池的网络比较复杂,首先,为了安全,不是所有服务器都能访问外网,需要有外网机器进行nat映射,将请求转发到内网机器的HA上,通过HA转发到不同机器,比如我们要用到的Kafka。

image-20230925113527797

Kafka监听地址

Kafka的配置中有两处监听配置,分别是:

  • listeners
  • advertised.listeners

listeners是kafka监听网卡的ip,绑定哪块网卡的ip,kafka就可以监听来自哪块网卡的请求。假设机器上一块内网网卡一块外网网卡,listeners绑定外网网卡时就只能接收来自外网的请求,绑定内网网卡同理。这里要特别明确一下几种特殊情况,监听localhost时,不监听网卡,只能通过localhost:xxxx访问;监听0.0.0.0时,会接收所有网卡的请求。

advertised.listeners是kafka向zookeeper注册的地址,kafka某个节点启动时,会向zookeeper注册自己,这时就会将advertised.listeners的地址注册到zookeeper,同时获取集群内其他节点的通信地址,即其他节点的advertised.listenersadvertised.listeners如果不配置,会默认使用listeners绑定的ip。

监听两个ip实现内外网分流

我们的需求是通过外网能够访问Kafka集群,那么将kafka监听的ip都设置为外网网卡的ip即可,但这样kafka节点间的通讯也通过外网,会有很多安全隐患。所以理想的情况是,集群间通讯使用内网,外部对集群的访问通过外网。

如果想实现上述的内外网分流,需要将两个ip都进行绑定(监听),然后通过inter.broker.listener.name指定内网broker直接通讯使用内网ip。

具体实施方法这里要分两种情况讨论:

  • 机器有外网网卡;
  • 机器没有外网网卡,需要其他机器映射网络或转发。

机器有外网网卡

对于机器本身有外网网卡的情况,只需要将内网网卡与外网网卡都进行监听。

listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT

listeners=INTERNAL://内网ip:9093,EXTERNAL://外网ip:9092

advertised.listeners=INTERNAL://内网ip:9093,EXTERNAL://外网ip:9092

inter.broker.listener.name=INTERNAL

需要注意的是,绑定两个ip的端口不可以相同。如果对外使用9092,那内网调用就不能再使用9092了,反之同理。

这里listenersadvertised.listenersEXTERNAL都监听外网网卡的ip,客户端拿的集群信息也是外网ip,可以实现外网访问。

机器没有外网网卡

如果机器本身没有外网网卡,需要由其他机器转发请求过来实现外网访问,这个时候要注意了,listenersEXTERNAL需要使用内网ip。

listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT

listeners=INTERNAL://内网ip:9093,EXTERNAL://内网ip:9092

advertised.listeners=INTERNAL://内网ip:9093,EXTERNAL://外网ip:9092

inter.broker.listener.name=INTERNAL

当我们通过kafka客户端链接kafka时,kafka会从zookeeper获取kafka集群的信息,这时候客户端得到的就是advertised.listeners的信息。因此我们将advertised.listeners中的EXTERNAL配置为外网ip,客户端通过该外网ip访问kafka集群,因为网络层面配置了转发,请求会被转发到内网ip,从而完成对kafka集群的访问。

这里对于kafka请求的原理可以参考我的另一篇文章Kafka概述与原理初探,对kafka的原理与生产、消费方式进行了一定的解释。

参考资料

特别感谢猫仙草大佬的文章kafka的listeners和advertised.listeners,配置内外网分流

读过之后真的是醍醐灌顶,解决了我大大的疑惑。