一、问题背景
使用 Kafka 客户端连接远端 Kafka 集群,程序启动后持续报错:Disconnected while requesting ApiVersion: might be caused by incorrect security.protocol,broker 返回主机名为kafka1:9092,程序反复断开重连,无法正常消费生产消息。
现象:网络端口能通,但是客户端拿到 broker 返回的主机名
kafka1,本机无法解析该域名,导致连接失败。 根本原因:Kafka 的advertised.listeners返回的是主机名而非 IP,本地机器 DNS /hosts 无法解析kafka1,客户端拿到域名后无法建立真实 TCP 连接。
二、现场拓扑简述
业务自研 Kafka 程序部署在自有服务器,无法直连内网 Kafka 集群,链路经过跳板机做 SSH 隧道转发。
约束:
- 跳板机 9092 端口被其他业务占用,跳板机 SSH 隧道使用9093映射内网 Kafka 的 9092 端口。
- 自有服务器无法访问外网,socat 需要在外网电脑下载源码,编译打包后上传至现场服务器离线部署。
完整链路: 自有服务器(自研 Kafka 转发程序) → socat 监听127.0.0.1:9092→ 转发至跳板机x.x.x.x:9093→ 跳板机 SSH 隧道 → 内网 Kafka 集群 9092
三、两种解决思路
方案 1:hosts 域名解析 + socat 端口转发
适用场景:无法修改远端 Kafka 服务端
server.properties配置,不能改动线上 Kafka 集群,只能在业务应用侧做适配。
1)配置 /etc/hosts 域名映射
把 Kafka 广播返回的主机名映射到本机回环地址,让客户端解析kafka1指向本机。
echo "127.0.0.1 kafka1" >> /etc/hosts2)socat 端口转发代理
利用 socat 做 TCP 端口转发:本地监听 端口,将流量转发到远端真实 Kafka 地址x.x.x.x:9093。 命令释义:
TCP-LISTEN:9092,bind=127.0.0.1:仅在本机 127.0.0.1 监听 9092 端口fork:支持多客户端并发连接reuseaddr:端口可快速复用,避免服务重启端口占用报错TCP:x.x.x.x:9093:后端真实 Kafka 服务地址
# 临时前台后台运行 /opt/socat/bin/socat TCP-LISTEN:9092,bind=127.0.0.1,fork,reuseaddr TCP:x.x.x.x:9093 &socat 编译部署步骤
- 下载
socat源码包,上传至业务服务器/opt目录 - 编译安装
cd /opt tar -zxvf socat-1.8.0.0.tar.gz cd socat-1.8.0.0 ./configure --prefix=/opt/socat make -j4 make install # 验证版本 /opt/socat/bin/socat -V- 打包部署包,方便多台机器分发
tar -czzf socat-deploy.tar.gz socat/- 目标机器解压
cd /opt tar -xzvf socat-deploy.tar.gz设置 systemd 开机自启常驻服务
编写socat-forward.service单元文件,实现开机自动端口转发,进程异常自动重启。
[Unit] Description=Socat Kafka TCP Forward After=network.target [Service] ExecStart=/opt/socat/bin/socat TCP-LISTEN:9092,bind=127.0.0.1,fork,reuseaddr TCP:x.x.x.x:9093 Restart=always [Install] WantedBy=multi-user.target生效命令:
systemctl daemon-reload systemctl enable socat-forward.service systemctl start socat-forward.service配置完成后,启动业务 Kafka 程序,连接本地kafka1:9092即可正常工作。
方案 2:治本方案(修改 Kafka 服务端 server.properties)
如果有权限修改 Kafka 服务端,优先改服务端,不需要 socat 转发。 修改
server.properties中advertised.listeners,写业务服务器可以直接访问的真实 IP 地址。
关键点:
advertised.listeners是 broker 返回给客户端的连接地址,客户端会拿这个地址去连接 broker。填域名,客户端必须能解析域名;填 IP,客户端直接使用 IP 连接。
四、问题根因总结
- Kafka 客户端连接流程:客户端连接 bootstrap 地址,broker 返回
advertised.listeners配置的地址列表,客户端丢弃 bootstrap 地址,使用返回的地址列表真正建立连接。 - 当
advertised.listeners配置为主机名(kafka1),应用服务器无法解析该主机名,就会出现ApiVersion请求断开、报 brokers are down。 - socat 方案属于应用侧兼容妥协,适合不能修改 Kafka 集群配置的生产现场;修改
advertised.listeners是最优根治方案。
五、socat 简单科普
socat 全称 SOcket CAT,就是一个 Linux 命令行工具,作用很简单:把两个数据流打通,双向转发数据。它常被叫做 netcat 的增强版。作用:
端口转发:把本机某个端口收到的数据,转发到另一个 IP 和端口。
协议桥接:比如 TCP ↔ UDP、TCP ↔ Unix Socket、TCP ↔ 串口。
网络调试:模拟服务端、客户端,看数据能不能通。
文件/管道/设备转发:不只是网络,还能转发文件、管道、串口设备。
SSL 隧道:给普通 TCP 连接加一层加密。
远程 Shell:也能用来建立正向或反向 Shell,但运维现场一般只用它做转发。
注意:socat 端口转发会增加一层网络开销,生产环境评估性能;bind=127.0.0.1 限制只能本机访问转发端口,提升安全性。
# 本地端口转发(同主机端口映射) socat TCP-LISTEN:端口,bind=127.0.0.1,fork,reuseaddr TCP:目标IP:目标端口 # 双向管道简易测试(本地回环测试) socat - TCP:127.0.0.1:28080六、踩坑清单
- 不要把报错
might be caused by incorrect security.protocol当成一定是 SSL/SASL 配置错误,很多时候只是域名解析失败。 - advertised.listeners 和 listeners 区分:
- listeners:broker 本机监听哪个网卡端口;
- advertised.listeners:返回给外部客户端的访问地址。
- hosts 配置后确认是否生效,
ping kafka1验证解析结果。 - socat 一定要配置
fork,否则只能处理单个客户端连接。