订阅更新

ssh 登陆卡 30 秒才出密码提示——SSH 会话完整调优

Linux手册 第 15 题 约 14 分钟读完

本文目录
  1. 先说结论
  2. 场景还原:那 30 秒到底卡在哪里
  3. 调优(1):服务端两行改,立即见效
  4. 调优(2):客户端 ~/.ssh/config 才是真正的大杀器
  5. 调优(3):tmux / screen 防断连,是每个 SSH 用户的必修课
  6. SSH 登录慢排查决策树
  7. 面试高频追问
  8. 实战踩坑:那次 30 秒登录的完整复盘
  9. 总结

先说结论

第一条:ssh 登录慢不是网络问题,大概率是 UseDNS=yes 做反解超时 + GSSAPIAuthentication=yes 做 Kerberos 握手,两行 sshd_config 改掉就能从 30 秒降到 1 秒。

第二条:排 ssh 问题第一命令永远是 ssh -vvv,它会打印每一步握手过程,卡在哪里一目了然。

第三条:~/.ssh/config 是 SSH 老用户的必修课——ControlMaster 复用连接、ServerAliveInterval 防断连、跳板机 ProxyJump,全在这里配。

先把这段讲顺;面试官追问时,再展开下面的原理和细节。

详细讲解

某出海硬件品牌有一批跨区的生产服务器,从跳板机 ssh 上去要卡 30 秒才出密码提示框,值班同事苦不堪言。所有人都以为是'网络不好',换跳板机换 VPN 都没用。我上去 ssh -vvv 一看——卡在 GSSAPI 认证握手 + DNS 反解上,跟网络压根没关系。改了两行 sshd_config + 一行客户端 ~/.ssh/config,从 30 秒变成 1 秒。

这道题考的是'ssh 登录链路上你真的理解过哪些环节'——因为 ssh 是所有运维/数据开发每天用几十次的工具,但 90% 的人从没想过它为什么这样那样。

场景还原:那 30 秒到底卡在哪里

先上 ssh -vvv 的真实输出(节选),你一眼就能看到是哪一步卡住:

# 客户端
ssh -vvv wood@10.20.30.40
 
# 输出前几行没问题
debug1: Connecting to 10.20.30.40 port 22.
debug1: Connection established.
debug1: identifying host key: ED25519 SHA256:xxx
 
# 卡住 10 秒 ↓
debug1: SSH2_MSG_SERVICE_ACCEPT received
debug2: key: /home/wood/.ssh/id_rsa
debug1: Next authentication method: gssapi-with-mic
debug1: Unspecified GSS failure.  Minor code may provide more information
# 这里卡了 10 秒,说明 GSSAPI 在尝试找 Kerberos 票据失败超时
 
# 又卡住 10 秒 ↓
debug1: Next authentication method: publickey
# 服务端 sshd 在这里做了反向 DNS 查询——查你的 IP 对应什么域名
# 如果 DNS 超时,又卡 10 秒
 
# 终于:
wood@10.20.30.40's password: 

三个加起来 30 秒的原因:① GSSAPIAuthentication 默认开着,客户端要去找 Kerberos 票据,找不到就超时;② 服务端 UseDNS=yes 默认开着,对入站 IP 做反向解析,DNS 不响应就超时;③ 有时候还叠加一个 GSSAPIKeyExchange 也卡一下。三个串行超时加起来刚好 30 秒左右。

调优(1):服务端两行改,立即见效

sshd_config 只改两行,ssh restart 后立即从 30 秒降到 1 秒:

# /etc/ssh/sshd_config
 
# 1) 关闭反向 DNS:服务端不再对入站 IP 查 PTR 记录
UseDNS no
# 作用:省掉每次登录的 DNS 反解超时
# 副作用:/etc/hosts.deny 之类基于主机名的访问控制失效
# 生产 99% 的场景都可以关
 
# 2) 关闭 GSSAPI 认证
GSSAPIAuthentication no
# 作用:不再走 Kerberos 协商
# 副作用:如果你真用 Kerberos(比如 CDH/HDP Hadoop 集群),不能关
 
# 其他推荐:
UseDNS no
GSSAPIAuthentication no
PermitRootLogin prohibit-password   # 禁止 root 密码登录,只能密钥
PasswordAuthentication no           # 彻底禁密码,只走密钥
MaxStartups 30:60:100                # 防暴力破解连接数限制
ClientAliveInterval 300              # 300 秒发一次心跳,防 NAT 断连
ClientAliveCountMax 3                # 3 次没响应断开
 
# 改完重启 sshd(注意:先确认手头还有另一个已登陆会话做后路)
systemctl reload sshd
# reload 比 restart 更安全,reload 不会断已有连接

血的教训:改 sshd_config 之前永远要保留另一个已登陆的会话,先 reload 试一下新登录能不能进。改完 systemctl restart sshd 然后发现配置写错——当前连接没事,但新连接全进不来——这种尴尬我真见过。reload 永远比 restart 安全。

调优(2):客户端 ~/.ssh/config 才是真正的大杀器

服务端改不了的时候(比如公用环境、堡垒机、别人的机器),你只能在客户端做调优。~/.ssh/config 是 ssh 用户进阶的分水岭。

# ~/.ssh/config
 
# 全局默认(适用所有 Host)
Host *
  # 关闭客户端 GSSAPI,省 10 秒
  GSSAPIAuthentication no
  # 每 60 秒发一次心跳,防 NAT / 防火墙 idle 断连
  ServerAliveInterval 60
  ServerAliveCountMax 3
  # 连接复用:第一次连上后开一个 socket,后续所有连接复用这个 socket
  # 第二次 ssh 同一机器几乎瞬间,scp/rsync 也快
  ControlMaster auto
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlPersist 10m
 
# 跳板机(堡垒机)配置
Host bastion
  HostName 10.0.0.1
  User wood
  IdentityFile ~/.ssh/id_ed25519
 
# 通过 bastion 跳进内网机器
Host prod-*
  User wood
  ProxyJump bastion
  # 或者老写法:ProxyCommand ssh -W %h:%p bastion
 
# 现在 ssh prod-kafka-01 等价于先连 bastion 再连 prod-kafka-01
# scp file prod-kafka-01:/tmp/ 也会自动走跳板机

ControlMaster 的实测效果:我有一组 20 台机器,每台都有 5-6 个常用命令要跑(检查 jvm、看日志、看磁盘)。开 ControlMaster 之前每次 ssh 要 1-2 秒握手,跑一圈要 2 分钟;开了之后第一次 1 秒,后续每次 ssh 几乎瞬间(< 100ms),跑一圈 15 秒。这就是熟手和新手的效率差距。

调优(3):tmux / screen 防断连,是每个 SSH 用户的必修课

场景:你 ssh 上生产机跑一个需要 2 小时的数据处理脚本,跑到 1.5 小时你的网络抖动一下断开了——脚本随着 SSH session 一起被 SIGHUP 干掉。怎么避免?

# 方法一:nohup + &(最老派,但脚本退出就退出)
nohup /data/job/run.sh > /tmp/run.log 2>&1 &
disown   # 从当前 shell 的 job 表里移除,防止 shell 退出时带走
 
# 方法二:tmux(最推荐,session 可以随时 attach)
tmux new -s bigjob
# 在 tmux 里跑你的脚本
/data/job/run.sh
# Ctrl+b 然后按 d 脱离(detach),脚本继续跑
# 下次登上来:
tmux attach -t bigjob
# 或者看看有哪些 session:
tmux ls
 
# 方法三:screen(老派,tmux 的前辈,现在 tmux 已完全替代)
screen -S bigjob
# Ctrl+a 然后 d 脱离
screen -r bigjob
 
# 方法四:systemd-run(无 tmux 时的系统级方案)
systemd-run --user --scope /data/job/run.sh
# 或全局:systemd-run /data/job/run.sh

tmux 三个最值得花 10 分钟学的快捷键:Ctrl+b d 脱离(最常用);Ctrl+b c 新建窗口;Ctrl+b ' 横切分屏。会这三个就够用了,一辈子不会再被 SSH 断连吓一次。

SSH 登录慢排查决策树

现象', '第一步查', '常见原因', '修法
卡在 'Connecting to'', 'telnet IP 22', '网络不通/端口封', '查路由/防火墙
卡在 'identifying host key'', 'DNS', '客户端解析慢', '写 /etc/hosts
卡在 'gssapi'', '-vvv 看', '客户端/服务端 GSSAPI=yes', '两端都关 GSSAPI
卡在 'publickey' 前', '-vvv 看', '服务端 UseDNS 反解超时', 'UseDNS no
卡在 password 提示', '-vvv + time', 'PAM 做额外认证', '看 /etc/pam.d/sshd
卡在欢迎信息', 'cat /etc/motd', 'motd 脚本慢', '精简 motd

面试高频追问

追问一:SSH 密钥 vs 密码,你在生产怎么管理 10000 台机器的登录?

三个层面:第一是严格禁用密码登录(PasswordAuthentication no),强制密钥;第二是密钥不直接发给每个人,用统一的堡垒机(Teleport、JumpServer、SSHD 公司定制),人登堡垒机认证后由堡垒机下发一次性 cert 证书登录目标机;第三是服务账号和个人账号分开,服务账号的密钥托管在机密管理系统(Vault、AWS SM、K8s Secret),CI/CD 拉取使用。某出海硬件品牌用的是 Teleport,所有人登生产机都走 Teleport,有完整的录屏审计,比自己维护 authorized_keys 省心得多。

追问二:known_hosts 是干什么的?MITM 怎么防?

known_hosts 是客户端缓存的'这台机器公钥指纹'列表,每次连接时 ssh 会对比当前服务端返回的公钥指纹和 known_hosts 里的记录,不一致就警告 REMOTE HOST IDENTIFICATION HAS CHANGED! 这个机制就是防中间人攻击的——如果有人冒充目标机插到中间,它的主机密钥不一样,客户端立即发现。生产上要避免的是:① 不要用 StrictHostKeyChecking no 跳过检查(这等于关了 MITM 防护);② 机器重装时主动 ssh-keygen -R 10.20.30.40 清掉旧指纹再登录;③ 用 ssh-keyscan 在部署时提前把新机器的指纹写进 known_hosts(注意验证)。

追问三:你怎么实现从本地 PC 一个命令直接拷文件到内网机器?

~/.ssh/config 里配好 ProxyJump 就能直接 scp。比如配了 Host prod-* ProxyJump bastion 之后,本地执行 scp ./data.tsv prod-kafka-01:/tmp/ ssh 会自动串起 '本地 → bastion → prod-kafka-01' 的链路,文件中转不落地在 bastion 上(ProxyJump 是端口转发不是存储转发)。如果是大文件,用 rsync -av --progress -e 'ssh' ./data.tsv prod-kafka-01:/tmp/ 支持断点续传;如果要经常同步目录,用 rsync --delete 做双向镜像。

实战踩坑:那次 30 秒登录的完整复盘

某出海硬件品牌那次跨区 ssh 慢,症状是:从跳板机登任何一台海外生产机都卡约 30 秒,但从生产机互相登又很快。我上去的排查过程:

# 第一步:ssh -vvv 看卡在哪
ssh -vvv wood@10.20.30.40 2>&1 | ts '%H:%M:%.S' | tee /tmp/ssh.log
# ts 打时间戳(需要 apt install moreutils),看每一行几点几分打印
# 马上能看到两段 10 秒的静默,分别在 gssapi 和 publickey 前
 
# 第二步:服务端确认
grep -E 'UseDNS|GSSAPI' /etc/ssh/sshd_config
# UseDNS yes
# GSSAPIAuthentication yes
# 两个都是开的,根因锁定
 
# 第三步:先从客户端临时规避(不改服务端)
ssh -o GSSAPIAuthentication=no -o UseDNS=no wood@10.20.30.40
# 立即 < 1 秒进去,确认根因
 
# 第四步:服务端正式改
sudo sed -i 's/^#*UseDNS.*/UseDNS no/' /etc/ssh/sshd_config
sudo sed -i 's/^#*GSSAPIAuthentication.*/GSSAPIAuthentication no/' /etc/ssh/sshd_config
sudo sshd -t   # 语法检查
sudo systemctl reload sshd
 
# 第五步:客户端统一配置(全组生效)
cat >> ~/.ssh/config <<EOF
Host *
  GSSAPIAuthentication no
  ServerAliveInterval 60
  ControlMaster auto
  ControlPath ~/.ssh/cm-%r@%h:%p
  ControlPersist 10m
EOF

效果:服务端改完后登录从 30 秒降到 0.8 秒,客户端开 ControlMaster 后第二次登录降到 50ms。全组运维同事第一反应是'你是不是悄悄换了网络?'——其实只是改了 3 行配置。这种级别的收益,属于改一次受益几年。

防复发:我把这份 sshd_config 片段写进了机器基线配置模板(Ansible role),新机器初始化必跑。后来新上线的机器,再也没有出现过'ssh 卡 30 秒'的问题。

总结

SSH 是我们每天用几十次的工具,但 90% 的人从来没真正理解过它的握手过程。面试时能把'UseDNS + GSSAPI 两个开关导致登录卡 30 秒'讲出来、能聊 ControlMaster 连接复用、能讲 ProxyJump 和 tmux 防断连——基本就能证明你是真正在生产里用 SSH 干活的。下次再听到人抱怨'ssh 慢',你已经知道第一反应该是 ssh -vvv,而不是'换个网'了。

下一篇预告:进入第 16-20 篇'性能调优 / 内核参数 / 运维实战'——第 16 题讲'CPU 平均负载 200 但 top 看所有进程 CPU 都不到 10%,load 到底是什么'。

你用过最花哨的 ~/.ssh/config 配置是什么?欢迎在评论区分享你的 ssh 进阶技巧。

关注「Wood聊大数据」| 9年大数据老兵,聊技术、聊职场、聊成长

Linux 面试通关手册

第16-20篇:性能调优 / 内核参数 / 系列收官

Wood聊大数据

9年大数据老兵,聊技术、聊职场、聊成长

本册导读(系列收官)

这是 Linux 面试通关手册 20 题的最后一册——第 16-20 篇。

前 15 篇把'线上排障的基本功'和'进阶排查链路'都讲过了,本册的主题是更深的一层:性能调优和内核参数。当你已经能定位问题之后,下一个问题是'这台机器为什么跑不到硬件上限'——load 为什么飙到 200、swap 为什么被触发、sysctl 哪些参数必调、OOM killer 为什么总是杀错进程。

最后的第 20 篇不是一道新题,而是系列收官——20 题回顾、难度分级表、排障三板斧、不同阶段的面试策略,以及我做 9 年大数据最想告诉新人的 5 条'生产生存建议'。看完这一册,整套 Linux 面试通关手册就彻底完结了。

感谢一路看到这里的每一位读者。希望这本手册能在你的某个凌晨 3 点,替你省两个小时。

— Wood,2026 年春

刷题进度保存在当前浏览器