Node.js 报错 ENOBUFS 处理方案

Node.js 报错 ENOBUFS 处理方案

在使用 Node.js 进行文件操作(例如解压 200M 大文件)时,经常会遇到 ENOBUFS(缓冲区溢出)错误。本文主要介绍如何通过两部分来解决此问题:

  1. 调整 Linux 系统配置
    包括查询当前配置、配置说明以及如何调整这些配置。
  2. 调整 Node.js 代码实现方式
    针对解压操作进行优化,避免过多输出占用缓冲区,同时确保进程不会因 Egg.js 进程管理而被异常杀掉。

一、Linux 系统配置调整

1.1 查询当前配置

使用 ulimit -a 命令可以查看当前用户的各项资源限制。例如,常见输出如下:

bash 复制代码
core file size          (blocks, -c) unlimited
data seg size           (kbytes, -d) unlimited
scheduling priority             (-e) 0
file size               (blocks, -f) unlimited
pending signals                 (-i) 31138
max locked memory       (kbytes, -l) 64
max memory size         (kbytes, -m) unlimited
open files                      (-n) 65535
pipe size            (512 bytes, -p) 8
POSIX message queues     (bytes, -q) 819200
real-time priority              (-r) 0
stack size              (kbytes, -s) 8192
cpu time               (seconds, -t) unlimited
max user processes              (-u) 4096
virtual memory          (kbytes, -v) unlimited
file locks                      (-x) unlimited

对于处理大文件(如 200M 文件),可能需要调整以下参数:

  • Stack Size (-s):默认 8192 KB 太小,建议增大到 64MB(65536 KB)。
  • Max User Processes (-u):默认 4096 可能不足,建议增大到 65535。
  • Open Files (-n):默认 65535,建议适当提高到 1048576,以防止打开文件数不足。
  • Max Locked Memory (-l):默认 64 KB 太低,建议增大到 512MB(524288 KB)。

1.2 临时调整

在终端中执行以下命令,进行临时调整(当前 Shell 会话生效,重启后失效):

bash 复制代码
ulimit -s 65536    # 堆栈大小改为 64MB
ulimit -u 65535    # 允许最多 65535 个用户进程
ulimit -n 1048576  # 打开文件数限制提升到 1048576
ulimit -l 524288   # 锁定内存大小增加到 512MB

1.3 永久调整

为了让调整在系统重启后依然有效,可按以下步骤修改系统配置:

修改 /etc/security/limits.conf

编辑该文件,添加以下内容:

conf 复制代码
* soft stack 65536
* hard stack 65536
* soft nproc 65535
* hard nproc 65535
* soft nofile 1048576
* hard nofile 1048576
* soft memlock 524288
* hard memlock 524288
修改 PAM 配置

确保 PAM 会话加载了 pam_limits 模块。编辑 /etc/pam.d/common-session/etc/pam.d/common-session-noninteractive 文件,并添加:

bash 复制代码
session required pam_limits.soc
修改 systemd 配置

编辑 /etc/systemd/system.conf/etc/systemd/user.conf,添加或修改如下内容:

conf 复制代码
DefaultLimitSTACK=65536
DefaultLimitNOFILE=1048576
DefaultLimitNPROC=65535

修改完成后,重启系统使配置生效:

bash 复制代码
sudo reboot

二、Node.js 代码调整方案

传统使用 execSyncspawnSync 执行 shell 命令时,如果命令输出大量内容(例如使用 tar -zxvf 时的详细日志),会导致缓冲区溢出,引发 ENOBUFS 错误。以下代码提供了一种通过异步 spawn 调用、避免输出过多数据的解决方案:

2.1 代码实现

javascript 复制代码
const { spawn } = require("child_process");
const path = require("path");

const INSTALL_DIR = "/your/install/path"; // 请替换为实际路径

const zxvfWebPackage = async function (filePath) {
    console.info(`解压 web 包: ${filePath}`);

    return new Promise((resolve, reject) => {
        try {
            const absFilePath = path.resolve(filePath);
            const absInstallDir = path.resolve(INSTALL_DIR);

            console.info(`执行解压: tar -zxf ${absFilePath} -C ${absInstallDir}`);

            const tarProcess = spawn("tar", ["-zxf", absFilePath, "-C", absInstallDir], {
                detached: true,  // 使进程独立于 Egg.js 进程
                shell: true,
                stdio: "ignore", // 避免缓冲区溢出,屏蔽标准输出和标准错误
            });

            tarProcess.unref(); // 让 Node.js 忽略该进程,不再跟踪它的生命周期

            console.info("解压进程已启动,不再跟踪");

            resolve({ code: 0, msg: "解压进程已启动" });
        } catch (err) {
            console.error(`解压失败: ${err.message}`);
            reject(err);
        }
    });
};

2.2 关键说明

  • 使用 tar -zxf
    通过去掉 -v 参数,可以避免打印过多的文件列表,从而减少标准输出数据,防止缓冲区溢出。
  • 异步 spawn 调用:
    使用异步 spawn 替代同步方法,避免因为大量数据输出而造成 Node.js 进程阻塞或内存溢出问题。
  • detached: trueunref()
    这两个参数使得解压进程独立于主进程(例如 Egg.js worker),即使主进程退出,解压进程仍能独立运行,不受管理进程生命周期的影响。
  • stdio: "ignore"
    屏蔽标准输出和错误,防止缓冲区因大量输出数据而溢出。如果需要调试输出,可以选择 inherit 或定制配置,但要谨慎控制输出量。

三、总结

Linux 系统调整:

  • 通过 ulimit 命令及修改配置文件,增大堆栈、用户进程、打开文件数以及锁定内存的限制。
  • 临时调整适用于当前会话,永久调整确保重启后生效。

Node.js 代码调整:

  • 避免使用同步命令(如 spawnSyncexecSync),而改用异步 spawn
  • 使用 tar -zxf 去除冗余输出,通过 detachedunref 参数确保子进程不受主进程生命周期的影响。
  • 采用 stdio: "ignore" 配置防止输出数据过多,避免 ENOBUFS 错误。

通过上述调整,可以有效避免 Node.js 处理大文件时因输出缓冲区溢出而产生的 ENOBUFS 错误,同时确保 Linux 系统和 Node.js 应用能够稳定高效地运行。

相关推荐
晨曦54321019 分钟前
零基础12周精通Linux学习计划
linux
linux修理工29 分钟前
n1 Armbian OS 24.11.0 noble 安装suricata
linux·运维·服务器
傅里叶33 分钟前
sudo启动Flutter程序AMD初始化失败
linux·flutter
bug攻城狮34 分钟前
CentOS 7 出现 “Could not resolve host“ 错误的修复方案
linux·运维·centos
feifeigo1231 小时前
CentOS系统管理:useradd命令的全面解析
linux·运维·centos
こ进制掌控者1 小时前
CentOS 8重启后网卡不见了解决办法
linux·运维·centos
Nightwish51 小时前
Linux随记(二十三 )
linux·运维
叶落阁主2 小时前
Neovim 插件 i18n.nvim 介绍
java·vue.js·vim
牛奶咖啡132 小时前
从零到一使用Linux+Nginx+MySQL+PHP搭建的Web网站服务器架构环境——LNMP(上)
linux·lnmp·ngnix的源码安装部署·mysql的二进制文件安装部署·php源码的安装部署·记录并解决安装php的各种问题
软件测试很重要2 小时前
UOS20系统安装与 SSH/XRDP 远程访问功能配置指南
linux·运维·ssh