SSH 每次登录都要等十几秒,我顺着日志查到是 DNS 在拖后腿
上周新开了一台华为云 ECS,装好系统配好密钥,第一次 ssh 连上去的时候就觉得不对劲:敲完命令,终端光标在那闪了十来秒,才弹出密码提示。输完密码又卡了几秒才进 shell。一次两次还能忍,每天登几十次,这十几秒攒起来特别烦。
第一反应是网络问题。家里宽带最近不太稳,晚高峰经常丢包。但 ping 了一下,延迟 30ms 出头,挺稳的,传文件速度也正常。网络没毛病,那这十几秒耗在哪了?
先量一下到底慢在哪
光凭感觉不行,先拿 time 量一下:
$ time ssh root@xxx.xxx.xxx.xxx "echo ok"
ok
real 0m12.4s
user 0m0.1s
sys 0m0.0s
12.4 秒,user 和 sys 时间几乎为 0,说明时间全耗在等服务端响应上。然后上 -v 看详细过程,看到底卡在哪一步:
$ ssh -v root@xxx.xxx.xxx.xxx
...
debug1: SSH2_MSG_SERVICE_ACCEPT received
输出停在 SSH2_MSG_SERVICE_ACCEPT received 这一行,卡了大概七八秒,才继续往下走:
debug1: Authentications that can continue: publickey,gssapi-keyex,gssapi-with-mic,password
debug1: Next authentication method: gssapi-with-mic
然后又在 gssapi 这一步卡了几秒,最后才轮到 password。两处卡顿加起来,就是那 12 秒。
第一处卡顿:UseDNS 反向解析
第一处卡在 SERVICE_ACCEPT 之后,这是服务端在干活。sshd 收到连接之后,默认会拿客户端的 IP 去做一次反向 DNS 解析,查这个 IP 对应什么主机名,再拿主机名正向解析回来比对,确认一致才放行。这个行为由 /etc/ssh/sshd_config 里的 UseDNS 控制,很多发行版默认是 yes。
问题是我的宽带是动态 IP,运营商根本没给这个 IP 配 PTR 记录,反向解析查不到,sshd 就一直等,等到 DNS 超时才肯往下走。验证办法很简单,在服务端上手动跑一次反向查询:
$ dig -x 1.2.3.4 +time=5
; <<>> DiG 9.16.1 <<>> -x 1.2.3.4 +time=5
;; connection timed out; no servers could be reached
果然超时。解决办法就是把反向解析关掉:
$ grep -i usedns /etc/ssh/sshd_config
#UseDNS yes
$ sudo sed -i 's/^#UseDNS yes/UseDNS no/' /etc/ssh/sshd_config
$ grep -i usedns /etc/ssh/sshd_config
UseDNS no
顺手说一句,关这个不影响安全组和密钥认证,只是 sshd 不再拿客户端 IP 去查 DNS 了。内网固定 IP 的机器本来就解析得快,关不关没感觉;公网动态 IP 的客户端登录,这一下能省好几秒。
第二处卡顿:GSSAPI 认证
第二处卡在 gssapi-with-mic。我的客户端没有配 Kerberos,服务端也没跑 KDC,但只要服务端开着 GSSAPIAuthentication yes,客户端就会先试一轮 GSSAPI,试不通再换 password,白白浪费几秒。
客户端侧可以先验证是不是这一步在拖时间:
$ time ssh -o GSSAPIAuthentication=no root@xxx.xxx.xxx.xxx "echo ok"
real 0m8.1s
从 12.4 秒降到 8.1 秒,少了 4 秒多,确认 GSSAPI 也在拖后腿。服务端侧直接关掉,一劳永逸:
$ grep -i gssapi /etc/ssh/sshd_config
GSSAPIAuthentication yes
GSSAPICleanupCredentials no
$ sudo sed -i 's/^GSSAPIAuthentication yes/GSSAPIAuthentication no/' /etc/ssh/sshd_config
改配置之前,先给自己留条后路
改 sshd_config 最怕的就是改错一个字符,重启之后把自己锁在外面。我这次改之前做了两件事。
第一,先检查语法,别直接重启:
$ sudo sshd -t
没输出就是没问题,有错它会直接报行号。
第二,改完不要直接 systemctl restart sshd。先用 reload,再新开一个终端窗口登录验证,老的会话保持不动:
$ sudo systemctl reload sshd
新窗口登录成功了,再关老会话。万一新登录失败,老会话还在,马上能把配置改回去。云服务器还有个兜底:华为云控制台的远程登录(VNC)不走 SSH,就算 sshd 彻底起不来,也能从控制台进去修。这次没用上,但知道有这条退路,改配置的时候手就没那么抖。
验证结果
两处都改完,重新测一次:
$ time ssh root@xxx.xxx.xxx.xxx "echo ok"
ok
real 0m0.8s
user 0m0.1s
sys 0m0.0s
12.4 秒变 0.8 秒。登录的时候再也不用盯着光标发呆了。
回头想想,这问题其实挺常见的:家里宽带动态 IP 没 PTR 记录,客户端又没配 Kerberos,两个默认开启的选项加起来,白白拖了十几秒。之前一直以为是网络卡,差点去升级宽带。其实定位的方法也不复杂,ssh -v 看卡在哪一行,time 量一下,剩下的就是顺着那一行去查对应的配置。以后碰到类似“连接慢但传文件快”的情况,我第一反应不会再是怪网络了,先看看到底是哪一步在等。
- 点赞
- 收藏
- 关注作者
评论(0)