JavaScript 已禁用

为了获得更好的体验,请启用JavaScript,或点击下方链接跳转:

跳转至百度
Skip to content

服务器cup占用异常

在给服务器安装nodejs时我使用了nvm这个工具来简化安装流程,但是发现安装后出现cpu占用高的问题(经过了一番排查才发现是这个原因导致),究其原因是因为nvm会在配置文件中添加一些命令,然后被finalshell重复执行导致

注释掉 .bashrc 中与 nvm(Node Version Manager)相关的配置后,CPU 占用下降,这说明问题的根源在于 nvm 的初始化脚本在 FinalShell 连接时被频繁执行,导致了额外的 CPU 消耗。具体原因和原理如下:

一、为什么 nvm 初始化会导致 CPU 升高?

nvm 的初始化脚本(nvm.shbash_completion)包含以下操作,在频繁触发时会消耗 CPU:

  1. 环境变量加载与解析nvm.sh 需要读取 $NVM_DIR 目录下的配置文件、版本列表,解析 Node 版本信息,这些操作涉及大量文件 I/O 和字符串处理,会触发系统调用(提升 %sys 系统态 CPU)。

  2. 命令补全脚本执行bash_completion 脚本用于实现 nvm 命令的自动补全(如输入 nvm use 按 Tab 补全版本),但它需要扫描所有可用的 Node 版本和命令,生成补全缓存,这一过程在每次 Shell 初始化时都会执行,消耗用户态(%usr)和系统态 CPU。

  3. FinalShell 的 exec channel 触发多次初始化 FinalShell 的 exec channel 可能会在后台创建多个 Shell 会话(即使你只打开一个窗口),例如:

    • 实时监控面板通过单独的 Shell 会话执行 top 等命令;
    • 文件浏览器、日志查看器等功能会隐式创建临时 Shell 会话。

    每个会话都会加载 .bashrc,导致 nvm 初始化脚本被重复执行(每创建一个会话执行一次),短时间内多次执行就会累积 CPU 消耗,最终导致整体占用达到 50%-60%。

二、为什么注释后 CPU 恢复正常?

注释掉 nvm 相关配置后,避免了以下消耗:

  • 不再加载 nvm.sh,减少了文件 I/O 和环境变量解析的系统态 CPU 消耗;
  • 不再执行 bash_completion 脚本,消除了命令补全的扫描和缓存生成过程;
  • 即使 FinalShell 创建多个 Shell 会话,.bashrc 中也没有高消耗的初始化操作,CPU 自然下降到正常水平。

三、后续建议(如需使用 nvm

如果需要在服务器上使用 nvm,但又想避免 FinalShell 连接时的高 CPU 消耗,可按以下方式优化:

1. 仅在需要时手动加载 nvm

.bashrc 中的 nvm 配置修改为手动触发,避免自动加载:

bash
# 在 .bashrc 中替换原配置为:
# 手动输入 `load_nvm` 才加载 nvm
load_nvm() {
  export NVM_DIR="${HOME}/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
  [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
}
  • 需要使用 nvm 时,在终端输入 load_nvm 手动加载,用完后关闭会话即可。

2. 限制 nvm 初始化的频率

修改 nvm 初始化逻辑,仅在交互式 Shell 中加载(FinalShell 的后台会话通常为非交互式,可跳过):

bash
# 在 .bashrc 中添加判断,仅交互式 Shell 加载 nvm
if [[ $- == *i* ]]; then  # 检查是否为交互式 Shell
  export NVM_DIR="${HOME}/.nvm"
  [ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
  [ -s "$NVM_DIR/bash_completion" ] && \. "$NVM_DIR/bash_completion"
fi
  • 原理:FinalShell 的后台 exec channel 会话通常为非交互式($- 中不含 i),因此不会加载 nvm,仅在你手动打开的交互式终端中才加载。

3. 减少 FinalShell 的后台会话

在 FinalShell 中关闭不必要的功能,减少自动创建的 Shell 会话:

  • 关闭 “实时性能监控”“自动日志刷新” 等依赖后台会话的功能;
  • 在连接设置中,将 “默认 Shell 类型” 从 login shell 改为 non-login shell(减少初始化脚本执行次数)。

通过以上方式,既能保留 nvm 的功能,又能避免 FinalShell 连接时的 CPU 高负载问题。核心逻辑是:减少非必要场景下的初始化脚本执行次数

四、后续使用

最终我采用手动加载 nvm的方式,以后使用nvmnodejs方式如下

bash
[root@dl ~]# nvm -v
-bash: nvm: 未找到命令
[root@dl ~]# load_nvm
[root@dl ~]# nvm -v
0.39.5
[root@dl ~]# node -v
v20.19.3
[root@dl ~]#
最近更新