
上周五下班前,运维老大突然给我派了个活:去排查一下为啥公司的CentOS服务器SSH登录慢得跟蜗牛爬似的。我当时心想,这能有多慢?结果一连上去,我傻眼了。
输完用户名之后,光标在那闪啊闪啊闪,足足等了快40秒才蹦出来让我输密码。这要是平时也就算了,关键是那天晚上线上出问题,急着要上服务器处理,结果光等登录就快一分钟,差点没把人急死。
更诡异的是,同样的操作,连公司另一台Debian服务器就贼快,敲完用户名1秒钟就能输密码。这就奇怪了,难道CentOS天生有毛病?
先说说我是怎么发现问题的
周末在家闲着没事,我就琢磨这事儿。既然Debian快CentOS慢,那肯定是配置上有区别。于是我决定用调试模式看看SSH连接过程到底在干啥。
先测CentOS这台慢的:
ssh -v test_user@192.168.1.100
敲完这个命令,终端哗啦啦输出一堆日志。我盯着屏幕看,前面一切正常,到了认证那块突然就卡住了。日志里出现了这几行:
debug1: Next authentication method: gssapi-keyex
debug1: No valid Key exchange context
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure. Minor code may provide more information
Cannot determine realm for numeric host address
然后就是反复重试,每次都报错”Cannot determine realm for numeric host address”,一直折腾了半分钟才放弃,进入下一个认证方式。
再看Debian这台快的:
用同样的命令测试,日志里压根就没出现gssapi相关的内容,直接就是publickey和password两种认证方式,刷刷刷就过去了。
看到这我就明白了,问题出在GSSAPI认证上。
GSSAPI是个啥玩意儿?
说实话我之前也不太懂这东西。查了半天资料才搞清楚,GSSAPI全称Generic Security Services Application Program Interface,听着挺高大上,其实就是个安全认证的接口标准,最常见的实现是基于Kerberos的。
简单说,它是用来做企业级身份认证的。在大公司里,如果部署了Kerberos这套系统,SSH登录时就能用统一的账号密码,不用每台机器单独管理用户。
但问题是:
我们公司压根就没部署Kerberos!
CentOS默认开启了GSSAPI认证,SSH登录时会先尝试这种方式。可是没有Kerberos服务器,这个认证注定要失败。系统就在那傻等,反复尝试,直到超时才罢休。这30多秒的延迟就是这么来的。
解决办法其实很简单
知道了原因,处理起来就容易了。核心思路就是:既然用不上GSSAPI,那就把它关了呗。
有两个方向可以操作:客户端关或者服务端关。
方法一:客户端临时禁用
如果你只是偶尔连某台服务器,懒得改配置,可以在命令行加个参数:
ssh -o GSSAPIAuthentication=no root@192.168.1.100
这样这次连接就不会尝试GSSAPI了,速度立马上来。
但每次都要敲这么长的命令也挺烦的,所以我一般会在客户端配置文件里改:
sudo vim /etc/ssh/ssh_config
找到这一行:
#GSSAPIAuthentication yes
把注释去掉,改成no:
GSSAPIAuthentication no
保存退出,以后从这台机器连任何服务器都不会再尝试GSSAPI了。
如果你只想影响当前用户,不想影响别人,可以改用户目录下的配置:
mkdir -p ~/.ssh
vim ~/.ssh/config
在文件里加上这一行就行:
GSSAPIAuthentication no
方法二:Windows下用PuTTY的处理
公司好多同事用Windows,装的是PuTTY。这个也能改,打开PuTTY的配置界面:
Connection → SSH → Auth → GSSAPI
把”Attempt GSSAPI authentication”前面的勾去掉就行了。
记得保存Session,不然下次还得重新设置。
方法三:服务端一劳永逸
客户端改的话,每个人都得改一遍,太麻烦。我觉得最省事的办法是直接在服务器上关掉。
登录到那台慢的CentOS服务器,编辑SSH配置:
sudo vim /etc/ssh/sshd_config
找到这两行(可能被注释了):
#GSSAPIAuthentication yes
#UseDNS yes
改成:
GSSAPIAuthentication no
UseDNS no
这里特别注意UseDNS这一项!
我一开始只改了GSSAPI,发现还是慢。后来查日志才发现SSH还会尝试反向DNS查询,根据客户端IP去查主机名,又是一轮超时等待。
UseDNS这个选项在CentOS上默认是yes,即使注释掉也是yes。所以必须显式写上no才能关掉。
改完之后重启SSH服务:
sudo systemctl restart sshd
# 或者老版本系统用
sudo service sshd restart
测试一下效果:
我改完配置后再连这台服务器,从敲命令到输密码,1秒钟不到!之前那种等到怀疑人生的感觉彻底没了。
还碰到个特殊情况
有个同事按我说的改完之后,发现还是慢。我远程帮他看了一眼,发现他们办公室的网络环境比较复杂,有多层NAT,导致SSH连接时还有别的问题。
后来我给他加了几个参数:
vim ~/.ssh/config
加上这些:
Host *
GSSAPIAuthentication no
ServerAliveInterval 60
ServerAliveCountMax 3
TCPKeepAlive yes
ServerAliveInterval这个参数的作用是每隔60秒发个心跳包,防止长时间无操作被路由器断开。这样即使登录慢点,至少不会莫名其妙掉线。
为什么Debian就不慢?
后来我对比了一下两个系统的默认配置,发现Debian的sshd_config里:
GSSAPIAuthentication no
UseDNS no
这两项默认就是no,所以人家压根不存在这个问题。
CentOS可能是为了企业级应用考虑,默认开启了这些功能。但对于我们这种没有Kerberos环境的普通用户来说,反而成了累赘。
总结一下踩坑经验
- SSH登录慢,第一步先用-v参数看日志,别瞎猜。日志会明确告诉你卡在哪个环节。
- GSSAPI和UseDNS是两个常见的坑,遇到登录慢基本就是这俩搞的鬼。
- 客户端和服务端都可以改,看你的权限和需求。有root权限就改服务端,一劳永逸;没权限就改客户端,也能解决问题。
- 改完配置记得重启SSH服务,不然不生效。我见过有人改完配置就去测试,发现没用就说我瞎扯,其实是没重启服务。
- 备份配置文件! 改之前先备份一份,万一改错了还能恢复:
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak
写在最后
这次排查SSH慢的问题,前前后后折腾了三天。虽然最终解决方案就是改两行配置,但这个过程让我对SSH的认证机制有了更深的理解。
有时候遇到问题不要急着去百度”SSH慢怎么办”,那些文章千篇一律,抄来抄去。自己动手用-v参数看看日志,往往能更快找到症结所在。
最后提醒一句:生产环境改配置一定要慎重,最好先在测试机器上验证一遍,确认没问题再推广。别问我怎么知道的,上次我一个同事直接在生产环境改SSH配置,结果配错了,所有人都连不上服务器,最后只能让机房的人去现场处理,那叫一个尴尬。
好了,就说这么多,希望能帮到遇到同样问题的你。有啥问题欢迎留言讨论!
原创文章,作者:余初云,如若转载,请注明出处:https://blog.jidcy.com/dynamicip/vpsbh/1208.html
