当你用SSH客户端(比如MobaXterm、PuTTY等)连接Linux服务器时,突然看到"Server refused to start a shell/command"这个报错,是不是感觉一头雾水?这个错误看起来简单,但背后可能隐藏着多种系统级问题。我遇到过不少这种情况,特别是在管理高并发的生产服务器时。
这个报错的本质是SSH服务端拒绝了创建新会话的请求。就像你去餐厅吃饭,服务员告诉你"现在没位置了"一样。但具体是为什么没位置?是餐厅座位太少(系统资源不足)?还是有人占着位置不走(僵尸会话)?或者是经理规定了接待上限(系统配置限制)?我们需要一步步排查。
先看几个典型场景:
内存不足是最常见的原因之一。当系统内存严重不足时,连最基本的shell都无法启动。我遇到过一台服务器,平时运行良好,但某天突然开始拒绝SSH连接,就是因为某个进程发生了内存泄漏。
检查内存状况很简单:
bash复制free -h
如果available内存接近0,或者swap使用率很高,那很可能就是内存问题。
遇到这种情况,可以先用root用户登录(如果还能登录的话),用以下命令找出内存消耗大的进程:
bash复制ps aux --sort=-%mem | head -n 10
如果确定是某个进程导致的问题,可以先用kill命令终止它:
bash复制kill -9 [PID]
但更彻底的做法是清理所有僵尸会话:
bash复制pkill -KILL -u [username]
注意:这个命令会强制终止该用户的所有进程,包括可能正在运行的重要任务。生产环境慎用!
Linux系统对每个用户可以创建的进程数有限制,这个限制在/etc/security/limits.d/20-nproc.conf文件中定义。默认值通常是4096,但在高并发场景下很容易达到上限。
我曾经管理过一台运行着大量Docker容器的服务器,就经常碰到这个问题。因为每个容器都会创建多个进程,很容易触发限制。
永久解决方案是修改nproc限制:
bash复制vi /etc/security/limits.d/20-nproc.conf
code复制* soft nproc 65535
SSH服务本身也有会话限制,主要涉及两个参数:
默认配置通常是注释掉的,这意味着使用较保守的默认值。在高并发场景下,这会导致新连接被拒绝。
修改/etc/ssh/sshd_config文件:
bash复制# 取消以下两行的注释并调整值
MaxSessions 20
MaxStartups 30:60:100
解释一下MaxStartups的格式:
修改后重启SSH服务:
bash复制systemctl restart sshd
预防胜于治疗。建议设置以下监控:
可以用简单的shell脚本实现:
bash复制#!/bin/bash
# 监控内存
mem=$(free | awk '/Mem/{printf("%.2f"), $3/$2*100}')
if (( $(echo "$mem > 90" | bc -l) )); then
echo "内存使用率过高:$mem%" | mail -s "服务器告警" admin@example.com
fi
# 监控进程数
pcount=$(ps -u [username] | wc -l)
if [ $pcount -gt 4000 ]; then
echo "进程数接近上限:$pcount" | mail -s "服务器告警" admin@example.com
fi
建议将以下操作加入crontab定期执行:
例如:
bash复制# 每天凌晨清理超过24小时的SSH会话
0 3 * * * pkill -9 -u [username] -t pts/[0-9]
现代Linux系统大多使用systemd,可以用它来查看资源占用情况:
bash复制systemd-cgtop
这个命令会显示按控制组(cgroup)排序的资源使用情况,能帮你快速定位问题服务。
如果怀疑是内存不足导致的问题,可以查看内核日志:
bash复制dmesg | grep -i oom
这个命令会显示内核的内存杀手(oom-killer)的活动记录,告诉你哪些进程因为内存不足被终止了。
去年我遇到一个典型案例:某电商公司的服务器在促销活动期间频繁出现SSH连接被拒的问题。通过排查发现:
解决方案是:
调整后,即使在更高峰期也没有再出现连接被拒的情况。这个案例告诉我们,系统参数的优化需要结合实际业务场景。