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 应用能够稳定高效地运行。

相关推荐
头发尚存的猿小二1 小时前
Linux——基本指令
linux·运维·服务器
诚丞成2 小时前
linux启程指南——体悟虚拟开源天地的漫步翩翩
linux·运维·开源
D-river2 小时前
【Linux 下Web(Apache/Nginx)入口安全事件及日志溯源流程】
linux·安全·web安全·网络安全·apache
yqcoder4 小时前
Node.js 实现 fs 模块删除文件
node.js
时差freebright4 小时前
【MySQL】第一章:数据库基础
linux·服务器·数据库·mysql
闪耀迪迦`4 小时前
linux常见操作命令
linux·运维·服务器
菜_小_白5 小时前
C++理解(六)
linux·开发语言·c++
众乐乐_20086 小时前
腾讯云扩容记录
linux·运维·服务器
web135085886357 小时前
在Linux系统上使用nmcli命令配置各种网络(有线、无线、vlan、vxlan、路由、网桥等)
linux·服务器·网络