Kafka客户端报Connection refused,telnet通nc通就是连不上——网络排查完整流程
本文目录
先说结论
'telnet 通但客户端连不上' 九成是协议层问题。telnet 只验证 TCP 三次握手,不发业务数据。Kafka 客户端连上去之后要 METADATA 请求返回 broker 列表,broker 列表里是 `advertised.listeners` 配的地址。配错了客户端就会尝试连那个错误地址,然后失败。
网络排查有固定的分层顺序:L1 物理层(ping 通不通)→ L3 路由(traceroute)→ L4 TCP(telnet / nc / ss)→ L7 应用(tcpdump / strace)。跨过层级盲查是新手做法。
DNS 是最容易被忽略的坑。hostname 解析、/etc/hosts、K8s DNS、advertised.listeners 用的 hostname 还是 IP——任何一层出问题都可能导致 '有的机器连得上、有的连不上'。
先把这段讲顺;面试官追问时,再展开下面的原理和细节。
详细讲解
这是一道让很多 2-3 年工作经验的同学翻车的题。面试官问 '你遇到过连不上某个服务怎么排查?',新人一般回答 '我 telnet 一下、ping 一下、看看防火墙'。面试官想听的远不止这些——他想听你能不能说清楚 '为什么 telnet 通但客户端连不上'、'advertised listeners 的坑'、'tcpdump 抓包怎么看三次握手'、'strace 看 connect syscall 返回值'。这些是真正在线上解过 Kafka 连接故障的人才答得出来。
业务场景:Kafka 从 VPC 外连不上的历史疑案
我在某短剧出海公司的时候,有一次新搭建一个海外办公室的数据分析环境,数据分析师要从办公网通过专线访问 VPC 内的 Kafka 集群。结果他们反馈 '连不上'。数据组的同事先查了一轮:
# 从分析师机器执行
telnet kafka-broker-1.internal 9092
# Connected to kafka-broker-1.internal.
# <-- TCP 通了!
nc -zv kafka-broker-1.internal 9092
# Connection to kafka-broker-1.internal 9092 port [tcp/*] succeeded!
# <-- nc 也通
# 但是 kafka-console-consumer 就是连不上
kafka-console-consumer --bootstrap-server kafka-broker-1.internal:9092 --topic test
# WARN Connection to node -1 (kafka-broker-1.internal/10.0.1.5:9092) could not be established
# WARN Bootstrap broker kafka-broker-1.internal:9092 disconnected
telnet 通、nc 通,客户端就是连不上。数据组的同事以为是 SSL、SASL 配置问题,查了一天一无所获。我接手的时候第一件事是让他们抓包:
# 在分析师机器上抓包
tcpdump -i any -n -s 0 -w /tmp/kafka.pcap 'host kafka-broker-1.internal'
# 同时启动客户端
kafka-console-consumer --bootstrap-server kafka-broker-1.internal:9092 --topic test
# Ctrl+C 停 tcpdump,分析
tcpdump -nn -r /tmp/kafka.pcap | head -20
# 看到:
# 14:01:23 IP 10.100.1.5.45678 > 10.0.1.5.9092: Flags [S] <-- SYN
# 14:01:23 IP 10.0.1.5.9092 > 10.100.1.5.45678: Flags [S.] <-- SYN/ACK
# 14:01:23 IP 10.100.1.5.45678 > 10.0.1.5.9092: Flags [.] <-- ACK,三次握手成功
# 14:01:23 IP 10.100.1.5.45678 > 10.0.1.5.9092: Flags [P.] <-- METADATA 请求
# 14:01:23 IP 10.0.1.5.9092 > 10.100.1.5.45678: Flags [P.] <-- METADATA 响应
# 14:01:23 IP 10.100.1.5.45678 > 172.20.1.15.9092: Flags [S] <-- !!! 开始连 172.20 ?!
# 14:01:26 IP 10.100.1.5.45678 > 172.20.1.15.9092: Flags [S] <-- 重传
# 14:01:33 超时
真相浮出水面:客户端第一次连 10.0.1.5(DNS 解析的),三次握手成功,METADATA 请求也成功。但 METADATA 响应里告诉客户端 '真正的 broker 地址是 172.20.1.15:9092',这个 172.20 是 VPC 内网地址,办公网到不了。于是客户端去连 172.20.1.15,超时失败。这就是经典的 `advertised.listeners` 坑。
修复方案:给 broker 配双 listener,一个 INTERNAL(172.20 内网给 VPC 内访问),一个 EXTERNAL(专线网段给办公网访问)。改完之后分析师立刻连上了。一天的疑案 15 分钟解决。
手段一:网络排查的分层检查顺序
网络问题排查必须按层走,乱跳层次会错过重要信号。
# L1/L2:物理/数据链路层 - 网卡和连通
ip link # 看网卡状态
ip addr # 看 IP
ethtool eth0 # 看网卡速率和 link 状态
# L3:网络层 - 路由和 ICMP
ping -c 3 kafka-broker-1 # 能不能通
traceroute kafka-broker-1 # 路由跳数
ip route # 本机路由表
ip route get 10.0.1.5 # 去 10.0.1.5 走哪条路由
# L4:传输层 - TCP/UDP 连通
telnet kafka-broker-1 9092 # 最基础
nc -zv kafka-broker-1 9092 # 更优雅
ss -tnp dst :9092 # 看已建立的连接
ss -tln sport = :9092 # 本机监听
# L7:应用层 - 协议级连通
curl -v http://... # HTTP
kafka-console-consumer # Kafka
mysql -h ... -P ... -u ... # MySQL
# DNS 单独检查
nslookup kafka-broker-1
dig kafka-broker-1
getent hosts kafka-broker-1 # 会走 /etc/hosts + DNS
cat /etc/resolv.conf # 看配的 DNS server
手段二:tcpdump 抓包看三次握手和业务数据
tcpdump 是网络排查的终极工具。'telnet 通但客户端连不上' 这种问题必须抓包才能看清楚。
# 最基本:抓某个主机的包
tcpdump -i any -nn host 10.0.1.5
# 抓某个端口
tcpdump -i any -nn port 9092
# 组合:某主机的某端口
tcpdump -i any -nn host 10.0.1.5 and port 9092
# 抓包存文件,之后用 Wireshark 分析
tcpdump -i any -nn -s 0 -w /tmp/cap.pcap host kafka-broker-1
# -s 0 = 抓完整包(默认只抓前 68 字节,看不到应用数据)
# -w 写文件
# 只看 TCP 三次握手(SYN 和 SYN/ACK)
tcpdump -nn 'tcp[tcpflags] & (tcp-syn|tcp-ack) == tcp-syn'
# 只看 RST(连接被拒绝)
tcpdump -nn 'tcp[tcpflags] & tcp-rst != 0'
# 抓 DNS
tcpdump -nn -i any port 53
# 分析 pcap 文件
tcpdump -nn -r /tmp/cap.pcap
tcpdump -nn -X -r /tmp/cap.pcap # -X 显示十六进制和 ASCII
实战技巧:tcpdump 抓下来的 pcap 文件传到本地用 Wireshark 打开,右键 '追踪流 → TCP 流',能把一个 TCP 连接的完整内容按时间顺序拼出来,业务数据一目了然。这比在命令行里看 tcpdump 直观 10 倍。
手段三:ss 替代 netstat 看连接状态
netstat 虽然老但已经被官方废弃,ss 是新一代工具,速度快很多(直接读 /proc/net,不扫描 proc fs)。
# 看所有 TCP 连接
ss -tn
# 看监听端口
ss -tln
# 看 TCP 状态分布
ss -tan | awk '{print $1}' | sort | uniq -c
# 120 ESTAB
# 45 TIME-WAIT
# 12 CLOSE-WAIT
# 8 LISTEN
# 看某个进程的连接
ss -tnp | grep java
# 看某个端口的连接
ss -tn sport = :9092
ss -tn dst = :9092
# 带进程信息
ss -tnp state established '( dport = :9092 or sport = :9092 )'
# 看 socket 的发送/接收队列(重要!)
ss -tn state established
# Recv-Q Send-Q Local Peer
# 0 1024 ... ...
# Recv-Q: 已接收但 app 未读取的字节
# Send-Q: 已发送但对方未 ACK 的字节
# 如果 Send-Q 持续增长 = 对方接收慢或网络慢
手段四:strace 看 connect 系统调用
连接失败的现象在应用层只看到 'ConnectException',想知道底层到底发生了什么(ECONNREFUSED、EHOSTUNREACH、ETIMEDOUT 各是什么),strace 看系统调用最直接。
# 追踪一个客户端启动时的网络系统调用
strace -f -e trace=network kafka-console-consumer \
--bootstrap-server kafka-broker-1:9092 --topic test
# 关键关注这几个系统调用:
# socket() - 创建 socket
# connect() - 发起连接
# sendto/recvfrom - 收发数据
# 看 connect() 的返回值
# connect(5, {...10.0.1.5:9092...}, 16) = 0 # 成功
# connect(5, {...10.0.1.5:9092...}, 16) = -1 ECONNREFUSED # 对方没监听
# connect(5, {...10.0.1.5:9092...}, 16) = -1 EHOSTUNREACH # 路由不通
# connect(5, {...10.0.1.5:9092...}, 16) = -1 ETIMEDOUT # 超时
# connect(5, {...10.0.1.5:9092...}, 16) = -1 ENETUNREACH # 网络不通
# 只跟 connect
strace -f -e trace=connect -p <pid>
# JVM 客户端:strace 附加到 JVM 进程的所有线程
strace -f -e trace=network -p $(pgrep -f kafka-console) 2>&1 | head -50
几种 '连不上' 的典型症状
| 症状 | 原因 | 排查命令 | 特征 |
|---|---|---|---|
| ping 不通 | L3 路由/防火墙 | traceroute, ip route | ICMP 无响应 |
| ping 通 telnet 不通 | L4 端口未监听或防火墙 | ss -tln, iptables -L | SYN 发出无响应 |
| telnet 通客户端不通 | 应用协议或配置 | tcpdump, strace | 握手成功后断 |
| DNS 解析错误 | DNS/hosts 配置 | dig, getent | 解析到错误 IP |
| 有的机器通有的不通 | 网段/路由/安全组 | traceroute 对比 | 按源 IP 不同结果不同 |
面试高频追问
追问一:advertised.listeners 是什么?为什么要配?
Kafka 客户端连 broker 时分两步:第一步连 bootstrap.servers 里的任何一个 broker,发 METADATA 请求;第二步 broker 返回集群的完整 broker 列表(每个 broker 的地址是什么),客户端后续读写就按这个列表连。`advertised.listeners` 就是 broker 告诉别人 '我的对外地址是什么' 的配置。如果 broker 装在 VPC 内网,listeners 可以是 `PLAINTEXT://0.0.0.0:9092`(监听所有网卡),但 advertised.listeners 必须是客户端能访问到的地址,比如 `PLAINTEXT://10.0.1.5:9092`。配错了会出现 '第一次连得上、后续连不上' 的诡异现象,和我遇到的那个办公网案例一样。解决方案是配多 listener:`INTERNAL://10.0.1.5:9092,EXTERNAL://1.2.3.4:9092`,然后客户端通过 `security.protocol` 选不同 listener。
追问二:ConnectionRefused 和 Timeout 的区别?
ConnectionRefused(ECONNREFUSED)是对方 TCP 栈收到 SYN 后回了 RST,意思是 '这个端口没人监听',几乎是即时返回的。Timeout(ETIMEDOUT)是 SYN 发出去之后没收到任何响应,持续重传(默认几次)都没回,最后内核放弃。两者含义完全不同:Refused 说明对方主机活着但端口没开,Timeout 说明对方主机/端口/防火墙层面把包吃掉了(不回 RST)。线上常见:本地服务挂了是 Refused,iptables DROP 规则是 Timeout,安全组 DENY 是 Timeout,路由不可达是 EHOSTUNREACH。面试能一口气说出这四种区别的就是真正懂 TCP 的。
追问三:tcpdump 抓不到某些包,可能是什么原因?
几个常见坑:① 没加 `-i any`,只抓某个特定网卡,流量走了别的网卡;② 开启了 bond/vlan,包被包装在 vlan header 里,默认过滤会漏;③ 没加 `-s 0`,只抓前 68 字节看不到应用数据;④ Kafka/Spark 这类有 SSL 的协议,抓到的是加密后的包,看不到内容,要么在 SSL termination 点抓,要么配置 SSL key 让 Wireshark 解密;⑤ K8s 环境在 Pod 内抓 eth0 只能看 Pod 流量,要抓宿主机的 cni0/docker0 才能看 service 流量;⑥ bridge/veth 对,有些包要在网桥上抓(`tcpdump -i docker0`)。另外如果目标主机在本机(127.0.0.1),必须 `-i lo` 才抓得到,用 `-i eth0` 看不到。
实战踩坑:DNS 缓存导致'连不上'的幽灵
还有一次在某出海硬件品牌,一个数据迁移的作业运行中出现 'Name or service not known' 错误,但手动 `nslookup` 域名都能解析。这个问题让人很懵。排查过程:
# 1. 先看是否 DNS server 出问题
dig @8.8.8.8 kafka-broker.internal
# 正常返回
# 2. 看本机 DNS 配置
cat /etc/resolv.conf
# nameserver 10.0.0.2 (公司内部 DNS)
# 3. 直接用 dig
dig kafka-broker.internal
# 正常返回 10.0.1.5
# 4. 但是用 getent hosts(走系统库的解析)
getent hosts kafka-broker.internal
# 一会儿返回,一会儿不返回
# 5. 用 strace 看 JVM 的 getaddrinfo
strace -f -e trace=network -p <pid> 2>&1 | grep -A 5 getaddrinfo
# 发现间歇性 getaddrinfo 失败,返回 EAI_AGAIN
# 6. 查系统日志
journalctl -u systemd-resolved | tail
# resolved 日志显示有时候向 DNS server 的 UDP 包丢了
# 7. 看 DNS server 可用性
while true; do
t=$(date +%s)
dig +time=2 +tries=1 kafka-broker.internal > /dev/null
echo "$t: $?"
sleep 1
done
# 每 10 秒左右有一次失败
根因:公司内部 DNS server 压力过大,偶发丢包(UDP)。Java 的 DNS 查询默认不缓存成功结果(`networkaddress.cache.ttl` 默认 -1 在 JDK 老版本是 never)——实际上是 30 秒,但对于高频短连接的 Kafka 客户端完全不够。修复方案:① 给 JVM 加 `-Dsun.net.inetaddr.ttl=300` 缓存 5 分钟;② 升级 DNS server 容量;③ 应用层对关键服务做本地 hosts 兜底。这种问题不抓包不查 strace,光看应用日志永远找不到。
总结
网络排查这道题考的是分层思维:L3 → L4 → L7 → DNS 四个维度都要能覆盖。工具链要熟悉 ping/traceroute/ss/tcpdump/strace/dig,至少能说清楚每个的用处。面试时主动讲 'telnet 通不代表应用协议通' 这个坑,再举一个 advertised.listeners 或者 DNS 缓存的案例,基本就是这题满分答案。
下一篇聊 TCP 连接状态两大经典:CLOSE_WAIT 和 TIME_WAIT 哪个该紧张?怎么处理?
你们最坑的一次网络排障是怎么解决的?评论区聊聊~
关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长