一次 SSH 登录随机卡顿(5 秒 / 10 秒)的排查记录
最近一台 CentOS 7 服务器出现了一个很奇怪的问题:
- SSH 登录偶尔会卡 5 秒或 10 秒;
- 同一台服务器,大多数时候又完全正常;
- 更奇怪的是,只要客户端使用
ssh -vvv登录,就几乎不会出现卡顿。
最开始一直怀疑是 SSH 本身的问题,结果最后发现根本不是。
故障现象
普通登录:
1 | ssh [email protected] |
偶尔停顿:
1 | Connecting... |
或者
1 | (等待约 10 秒) |
但是开启调试:
1 | ssh -vvv [email protected] |
几乎每次都是秒连。
由于 -vvv 只是增加调试输出,并不会修改 SSH 协议,因此可以判断:
问题不是 SSH 协议本身,而是某个时序相关的问题。
首轮排查
检查 sshd_config:
1 | UseDNS 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 就正常”。
结论
这次问题最大的收获有两点:
- SSH 卡顿,不一定是 SSH 的问题。
- 如果
ssh -vvv能恢复正常,往往说明问题与时序、DNS 或网络环境有关,而不是 SSH 配置本身。
以后再遇到 SSH 登录随机卡 5 秒、10 秒的情况,除了检查 sshd_config 外,也建议同步检查:
- DNS 正向/反向解析
getent hostsgetent ahostsdigtcpdump port 53- 出口线路或 NAT 是否存在异常
很多时候,真正的问题并不在 SSH,而是在系统名称解析或网络出口。