Bootstrap

kafka的listeners和advertised.listeners,配置内外网分流

总结:
listeners 指明 kafka 当前节点监听本机的哪个网卡
advertised.listeners 指明客户端通过哪个 ip 可以访问到当前节点

内网和外网并不必须是是我们通常说的公司内部网络公网,只要是两块网卡都可以,不管是这两块网卡是公网、内网、甚至是k8s的虚拟网络
两个网段的主要目的是实现分流,一个负责节点间通信,一个负责对外收发消息。

listeners:

kafka监听的网卡的ip,假设你机器上有两张网卡,内网192.168.0.213和外网101.89.163.1
如下配置

listeners=PLAINTEXT://192.168.0.213:9092
#或者
listeners=PLAINTEXT://:9092

那么kafka只监听内网网卡,即只接收内网网卡的数据,如果如下配置:

listeners=PLAINTEXT://101.89.163.1:9092

那么kafka只监听外网网卡,即只接收外网网卡的数据。
当然ip可以配置成0.0.0.0,监听所有网卡。
说明:
listeners 解决的是 kafka 监听来自于哪个网卡的请求。

advertised.listeners

一般配置

listeners=PLAINTEXT://192.168.0.213:9092
advertised.listeners=PLAINTEXT://101.89.163.1:9092

配置过 zookeeper 的都知道, zookeeper 的配置文件中写明了所有 zookeeper 节点的 ip 地址,以便启动后节点之间的互相通信。我们观察 kafka 的配置文件 server.properties,会发现里面并没有记录其他 kafka 节点的地址,即各个节点都不知道其他节点的 ip 地址。那么 kafka 集群的各个节点之间是怎么通信的呢?
kafka 节点启动后,会向 zookeeper 注册自己,同时告诉 zookeeper 自身的通信地址,这个地址就是配置文件中的 advertised.listeners,如果没有配置 advertised.listeners,就会使用listeners。同时从 zookeeper 中获取兄弟节点的这个地址,以便与兄弟节点通信。即 kafka 节点是从 zookeeper 获取的其他节点的通信地址。
我们使用客户端以一个 ip 地址首次连接 kafka 节点后,节点返回给客户端的 kafka 集群地址就是从 zookeeper 中获得的这些地址,也就是各个节点配置的 advertised.listeners,包括当前连接的节点。所以可能客户端后续访问当前节点的 ip 地址有可能和首次连接的 ip 地址并不一样。

只需要内网访问kafka

只配置 listeners 并且使用内网 ip

listeners=PLAINTEXT://192.168.0.213:9092
#或者
listeners=PLAINTEXT://:9092

客户端访问 kafka 节点,以及与其他节点通信都用这个 ip 地址。

需要外网访问

如果机器是通过转发或者映射搞出来的外网ip(例如你访问腾讯新闻某个页面使用的 ip,这个 ip 和实际的网卡并不在为你提供首页内容的那台机器上),此时kafka无法监听这个外网ip,启动就会报错。
需要配置一下 advertised.listeners,例如:

listeners=PLAINTEXT://192.168.0.213:9092
advertised.listeners=PLAINTEXT://101.89.163.1:9092

此时 kafka 客户端访问 kafka 集群的一个完整流程是:

  1. 客户端访问 101.89.163.1:9092,该请求被发送到 kafka 节点宿主机的内网地址 192.168.0.213:9092 上(也可以是其他 kafka 节点,效果是一样的),第一次请求成功,此次请求申请获得 kafka 集群的所有节点的地址。
  2. kafka 从 zookeeper 拿到自己和其他兄弟节点注册在 zookeeperadvertised.listeners,作为 kafka 集群各个节点的的服务 ip 返回给客户端。
  3. 客户端拿这些返回的服务 ip 访问kafka集群,该请求从 实际拥有该 ip 的机器被转发到被具体 kafka 节点所在的内网ip,访问到了 kafka 节点

为什么客户端需要在第一次请求中获取 kafka 各个节点的服务 ip

因为你可以在启动客户端时只配置一个 kafka 节点的地址而不是列出所有节点(这样是不推荐的),但是客户端必须具有访问集群中的每一个节点的能力(收消息、发消息都可能面向所有节点)。
对于 2.2 的情况,如果去掉
bash advertised.listeners=PLAINTEXT://101.89.163.1:9092

你会发现虽然你在启动 kafka 客户端时配置的访问地址是101.89.163.1:9092,但是 kafka 客户端启动时报错:

Connection to node -1[192.168.0.213:9092] could not be established. Broker may not be available.

为什么明明配置的是101.89.163.1:9092启动时连接的是192.168.0.213?这就是因为不配置advertised.listeners 则使用listeners 代替并注册到zookeeper 中,客户端拿到的 kafka 节点 ip 就是listeners配置的内网 ip 192.168.0.213

内外网分流

配置1(针对没有实际的外网网卡):

istener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
listeners=INTERNAL://192.168.0.213:9092,EXTERNAL://192.168.0.213:19092
advertised.listeners=INTERNAL://192.168.0.213:9092,EXTERNAL://101.89.163.9:19092
inter.broker.listener.name=INTERNAL

配置2(针对有实际的外网网卡):

listener.security.protocol.map=INTERNAL:PLAINTEXT,EXTERNAL:PLAINTEXT
listeners=INTERNAL://192.168.0.213:9092,EXTERNAL://101.89.163.9:19092
advertised.listeners=INTERNAL://192.168.0.213:9092,EXTERNAL://101.89.163.9:19092
inter.broker.listener.name=INTERNAL

这两配置的区别是只有 listenersEXTERNAL 使用的 ip 不一样,一个使用内网 ip ,一个使用外网 ip
对内网 INTERNAL 的配置就不说了,主要用于节点间通信,无论 listeners 还是 advertised.listeners 都配置成内网 ip,自然所有请求都走内网;主要是外网 EXTERNAL 配置:

  1. 如果机器的外网 ip 是映射来的,listeners 的 EXTERNAL 使用内网ip,客户端拿到的是 advertised.listeners 配置的外网 ip,对于该外网 ip 的请求会被转发到对应的内网 ip,即访问到了对应的 kafka 节点,请求完成闭环。不要问怎么转发的,既然机器被映射了外网 ip,自然能够转发
  2. 如果你的kafka宿主机有外网网卡,listenersEXTERNAL 使用用外网ip,客户端拿到的是 advertised.listeners 配置的外网 ip,直接就访问到了对应的 kafka 节点。
;