问题背景
- 前段时间,遇到一个kafka集群部署在k8s中,而kafka客户端在另一个k8s集群的pod的容器中,kafka集群中配置的advertised_listeners便是hostname。然而当时我只知道kafka集群的ip地址,当在客户端直接使用ip操作broker的时候便报错无法解析一个hostname。
- 当时不知道什么原因,只听同事说需要在kafka客户端对应的yaml文件中添加HostAliases字段然后重新部署kafka客户端所在的pod。 然后便可以访问了。
- 不明所以然的我,查了一下hostAliases的使用发现没什么特别之处。然后查了listeners的使用也没有说是可以携带域名之类的
- 最后查了一下kafka客户端的请求过程才明白是怎么回事(笔者接触kafka不久只是阅读过文档并没有了解到其客户端的请求过程和步骤,所以迷惑了这么久 - _ -)
kafka broker配置介绍
先来看一下官方文档对kafka broker中有关listeners配置项的介绍:
名称 | 描述 | 类型 | 默认值 | 有效值 | 重要性 |
---|---|---|---|---|---|
listeners | 监听器列表 - 使用逗号分隔URI列表和监听器名称。如果侦听器名称不是安全协议,则还必须设置listener.security.protocol.map。指定主机名为0.0.0.0来绑定到所有接口。留空则绑定到默认接口上。合法监听器列表的示例:PLAINTEXT:// myhost:9092,SSL://:9091 CLIENT://0.0.0.0:9092,REPLICATION:// localhost:9093 | string | null | 高 | |
advertised.listeners | 监听器发布到ZooKeeper供客户端使用,如果与listeners 配置不同。在IaaS环境,这可能需要与broker绑定不通的接口。如果没有设置,将使用listeners 的配置。与listeners 不同的是,配置0.0.0.0元地址是无效的。 | string | null | 高 | |
listener.security.protocol.map | 侦听器名称和安全协议之间的映射。必须定义为相同的安全协议可用于多个端口或IP。例如,即使两者都需要ssl,内部和外部流量也可以分开。具体的说,用户可以定义名字为INTERNAL和EXTERNAL的侦听器,这个属性为:internal:ssl,external:ssl。 如图所示,键和值由冒号分隔,映射条目以逗号分隔。 每个监听者名字只能在映射表上出现一次。 通过向配置名称添加规范化前缀(侦听器名称小写),可以为每个侦听器配置不同的安全性(ssl和sasl)设置。 例如,为内部监听器设置不同的密钥仓库,将会设置名称为“listener.name.internal.ssl.keystore.location”的配置。 如果没有设置侦听器名称的配置,配置将回退到通用配置(即ssl.keystore.location )。 | string | PLAINTEXT:PLAINTEXT,SSL:SSL,SASL_PLAINTEXT:SASL_PLAINTEXT,SASL_SSL:SASL_SSL | 低 | |
inter.broker.listener.name | broker间通讯的监听器名称。如果未设置,则侦听器名称由security.inter.broker.protocol定义。 同时设置此项和security.inter.broker.protocol属性是错误的,只设置一个。 | string | null | 中 | |
security.inter.broker.protocol | broker之间的安全通讯协议,有效值有:PLAINTEXT, SSL, SASL_PLAINTEXT, SASL_SSL。同时设置此配置和inter.broker.listener.name属性会出错 | string | PLAINTEXT | 中 |
- listeners : 监听器配置,通俗的说就是给kafka配置一个监听器,告诉外部连接者需要通过什么样的协议、什么样的地址、什么样的端口进行连接kafka broker
- advertised_listeners: 这组监听器是 Broker 用于对外发布的,advertised_listeners 监听器会注册在 zookeeper 中。
- 当我们对172.17.2.3:9092建立请求连接的时候,kafka broker会通过zk找到注册的INSIDE监听器,然后通过listeners找到对应的ip和端口 : 172.17.2.3:9092
- 当我们对<公网 ip>:端口建立请求连接的时候,kafka broker会通过zk找到注册的OUTSIDE监听器,然后通过listeners找到对应的ip和端口: 172.17.2.3:9094
- 更多关于listeners介绍:Kafka Listeners
listeners: INSIDE://172.17.2.3:9092,OUTSIDE://172.17.2.3:9094
advertised_listeners: INSIDE://172.17.2.3:9092,OUTSIDE://<公网 ip>:端口listener_security_protocol_map: "INSIDE:SASL_PLAINTEXT,OUTSIDE:SASL_PLAINTEXT"
inter_broker_listener_name: "INSIDE"
DNS介绍
域名系统(服务)协议(DNS)是一种分布式网络目录服务,主要用于域名与 IP 地址的相互转换,以及控制因特网的电子邮件的发送
hostname
- hostname即主机名字 , 每一个主机都会对应一个hostname, 在特定的网络范围内唯一
- 每一个主机都会对应一个IP地址,在特定的网络范围内唯一
域名及域名解析
- 域名是因特网范围内某一个服务器的名字,是用来解决IP地址不可读不好记的问题,例如百度的域名为 :baidu.com , 这个域名在响应的DNS服务中有对应的ip,当我们访问这个域名的时候会在先进行域名解析得到ip后在进行tcp/ip建立连接,具体的域名解析过程原理在此不赘述。
- 专门用来进行域名解析的成为DNS服务器,DNS服务器根据范围不同分为互联网DNS服务器,局域网DNS服务器,当然对于每个主机而言在/etc/hosts配置ip地址和主机hostname的映射也可称为一个DNS服务器。
kafka中使用hostname(这是本篇文章的重点)
如上文所描述,kafka broker配置项listeners的作用和使用,listeners的地址配置不一定是ip, 也可以是hsotname:
listeners: INSIDE://my-hostname:9092,OUTSIDE://my-hostname:9094
advertised_listeners: INSIDE://my-hostname:9092,OUTSIDE://<my-out-hostname>:端口listener_security_protocol_map: "INSIDE:SASL_PLAINTEXT,OUTSIDE:SASL_PLAINTEXT"
inter_broker_listener_name: "INSIDE"
如上所示,当advertised-listeners配置的地址为hostname的时候,外部客户端请求连接的时候是怎样的流程呢?
此时,我们如果直接访问ip进行请求连接是无法获取kafka broker中的数据的;当在主机的/etc/hosts文件中添加该hostname所映射的ip之后便可以请求kafka broker中的数据。
- 执行命令 kafka-topics --list --bootstrap-server ip:端口, kafka客户端会向broker请求kafka broker的所有元数据。 --bootstrap.servers实际上是引导地址,而不是客户端真正建立长链接的地址。也就是说,客户端会根据引导地址去broker询问集群的所有broker信息,拿到返回的broker服务信息之后,再向指定的broker发起链接请求。此时由于kafka borker的advertised_listeners配置的是hostname,那么返回给客户端的元信息中的地址也是hostname,当客户端准备根据这个hostname建立长连接请求数据的时候,发现并解析不了该hostname。 于是当在主机etc/hosts文件中添加该hostname的ip映射之后便会根据域名解析找到ip建立连接。
- –bootstrap.servers是指向kafka broker的,如果使用–zookeeper便是向zk请求kafka broker的元数据了。