一次 SSH 登录随机卡顿(5 秒 / 10 秒)的排查记录

最近一台 CentOS 7 服务器出现了一个很奇怪的问题:

  • SSH 登录偶尔会卡 5 秒或 10 秒
  • 同一台服务器,大多数时候又完全正常;
  • 更奇怪的是,只要客户端使用 ssh -vvv 登录,就几乎不会出现卡顿。

最开始一直怀疑是 SSH 本身的问题,结果最后发现根本不是。


故障现象

普通登录:

1
ssh [email protected]

偶尔停顿:

1
2
Connecting...
(等待约 5 秒)

或者

1
(等待约 10 秒)

但是开启调试:

1
ssh -vvv [email protected]

几乎每次都是秒连。

由于 -vvv 只是增加调试输出,并不会修改 SSH 协议,因此可以判断:

问题不是 SSH 协议本身,而是某个时序相关的问题。


首轮排查

检查 sshd_config

1
2
UseDNS no
GSSAPIAuthentication no

这些常见导致登录变慢的配置都已经关闭。

服务器也没有:

  • nscd
  • systemd-resolved

因此基本可以排除 SSH 配置导致的问题。


抓包发现

抓 DNS:

1
tcpdump -ni ens192 port 53

登录卡顿期间,可以看到服务器不断查询:

1
PTR? 209.1.168.192.in-addr.arpa

返回:

1
NXDOMAIN

说明 SSH 登录过程中确实发生了反向 DNS 查询。


奇异之处

直接测试:

1
dig -x 192.168.1.209

查询时间始终只有:

1
Query time: 8 ms

连续测试上百次都正常。

但是:

1
getent hosts 192.168.1.209

却偶尔出现:

1
real    0m5.013s

甚至:

1
real    0m10.020s

说明:

DNS 服务器本身没有慢。

真正慢的是 glibc 的名称解析(getaddrinfo/gethostbyaddr)

Python 同样能复现:

1
socket.getaddrinfo("www.baidu.com",80)

有时直接等待 10 秒后报:

1
socket.gaierror

进一步证明问题发生在系统解析库,而不是 SSH。


最终定位

后来发现,公司出口实际上有三条公网线路:

  • A
  • B
  • C

205 服务器当时一直走 C 线路

当出口切换到 A/B 后:

  • getent 不再出现 5 秒或 10 秒等待;
  • SSH 登录恢复正常;
  • ssh -vvv 与普通 SSH 都没有任何区别。

而走 C 线路时:

  • 普通 SSH 偶尔卡顿;
  • ssh -vvv 基本正常;
  • DNS 查询 (dig) 很快;
  • glibc 名称解析 (getent) 却偶尔超时。

目前推测是 C 出口上的 UDP/DNS 通信存在偶发异常或丢包,导致 glibc 重试,从而出现 5 秒、10 秒的等待;而开启 -vvv 后,由于客户端和服务端交互时序发生变化,这个问题反而难以触发,因此表现为“加 -vvv 就正常”。


结论

这次问题最大的收获有两点:

  1. SSH 卡顿,不一定是 SSH 的问题。
  2. 如果 ssh -vvv 能恢复正常,往往说明问题与时序、DNS 或网络环境有关,而不是 SSH 配置本身。

以后再遇到 SSH 登录随机卡 5 秒、10 秒的情况,除了检查 sshd_config 外,也建议同步检查:

  • DNS 正向/反向解析
  • getent hosts
  • getent ahosts
  • dig
  • tcpdump port 53
  • 出口线路或 NAT 是否存在异常

很多时候,真正的问题并不在 SSH,而是在系统名称解析或网络出口。