Linux能登陆,执行命令时卡住


作者Lou Xiao创建时间2023-08-11 19:08:00更新时间2023-08-11 19:08:00

1. 问题描述

能够通过ssh登陆账户(或通过 su -l UserName),但是获取shell(bash)之后,执行任何命令时终端卡住,Ctrl + C 无效。

2. 初步猜测

  • 系统的RAM被用完,若开启swap,导致频繁的读写硬盘,导致程序卡死;
  • 该用户的$HOME所在的文件系统(硬盘等)满了,导致不能创建新进程;
  • 该用户的进程数太多,超出限制。

3. 初步验证

  • 获取root账号,执行 df -h,该命令卡死,无法判断硬盘是否满了。但是可以得出新的猜测:某文件系统故障(损坏、nfs 超时等);
  • 用root用户,执行su -l UserName, 切换到UserName后,执行任何命令依然卡死;
  • 用root账户,ls -hl /home/UserName, 执行正常,排除文件系统的问题;
  • 使用 free -g 排除RAM容量问题;
  • 使用 iostat 1 初步排除硬盘故障问题;
  • 使用 top 排除进程数的问题。

此时并没有定位到问题,只能reboot重启;重启之后,问题还存在(记不清楚了,汗......)。
凭直觉,试了试:用root账户把UserName的bash配置文件备份了一下,再次登陆UserName,发现问题解决。

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 cd /home/UserName/
2 mkdir origin
3 mv -iv .bash* origin/

4. 定位问题

既然问题是~/.bash*配置文件导致,那么仔细检查文件内容,发现了端倪:

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 # ~/.bashrc 存在潜在问题的代码(埋一颗雷,等有缘人,爆掉,surprising~~~)
2 export PATH="/nfs/xxx/bin/:$PATH"

这行代码初次看没什么问题,再次看很OK,定睛再看3分钟,就发现了一个严重的问题!
环境变量$PATH指向了一个nfs的挂载点/nfs/,那么这个挂载点就可能存在故障(网络原因等导致的)。当挂载点/nfs出现故障时,访问/nfs文件的进程被卡死(Linux下超级严重的问题)。

5. 故障分析

  1. 用户UserName登陆,获取一个bash进程作为shell;
  2. 此bash进程加载~/.bashrc,设置环境变量PATH="/nfs/xxx/bin/:$PATH"
  3. shell等待用户的命令;
  4. 用户键入命令,例如 pwd
  5. bash按照 环境变量$PATH指定的多个路径,依次搜索名叫pwd的程序;由于/nfs/xxx/bin/放在第一个,它被优先查找;
  6. 由于/nfs出现故障,当bash检索/nfs/xxx/bin/时,从而导致bash进程永久卡死。

6. 良好实践指南

  • 环境变量$PATH 不要包含 网络挂载点(nfs、ftp、smb等);
  • 程序和数据尽可能放在稳定的本地文件系统上;
  • 模块化设计,配置文件按功能拆分为独立小文件,需要的时候明确加载。

7. 如何解决此类问题

  1. 登陆UserName,获取shell

  2. 重置 $PATH

1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 export PATH=/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin
  1. 备份 ~/.bash*
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 mkdir ~/origin/
2 mv -iv ~/.bash* ~/origin/
  1. 重置 ~/.bashrc
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 cat >> "$HOME/.bashrc" <<'EOF'
2 # .bashrc
3
4 # Source global definitions
5 if [ -f /etc/bashrc ]; then
6 . /etc/bashrc
7 fi
8
9 # Uncomment the following line if you don't like systemctl's auto-paging feature:
10 # export SYSTEMD_PAGER=
11
12 # User specific aliases and functions
13 EOF
  1. 重置 ~/.bash_profile
1.双击鼠标左键复制此行;2.单击复制所有代码。
                                
                                    
1 cat >> "$HOME/.bash_profile" <<'EOF'
2 # .bash_profile
3
4 # Get the aliases and functions
5 if [ -f ~/.bashrc ]; then
6 . ~/.bashrc
7 fi
8
9 # User specific environment and startup programs
10
11 PATH=$PATH:$HOME/.local/bin:$HOME/bin
12
13 export PATH
14 EOF
文章目录