You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

EC2自动部署重启时Node.js集群fork报EADDRINUSE错误排查

问题分析与解决思路

可能的原因

  • 主/子进程重复监听端口:如果主进程代码中也存在监听端口的逻辑,或者子进程的监听配置强制独占端口,会导致多个进程争抢同一端口触发EADDRINUSE。
  • 端口共享配置缺失:Node.js Cluster多进程共享端口依赖系统的SO_REUSEPORT特性,若未显式开启(Node.js v10.12.0+支持reusePort参数),EC2实例的系统环境可能默认限制了端口共享。
  • 部署脚本逻辑问题:即使是全新实例,自动部署脚本可能存在重复执行启动命令的情况,导致多个主进程同时fork子进程,引发端口冲突。
  • 子进程启动竞争:EC2实例启动时网络服务未完全就绪,子进程绑定端口的时机过早,触发暂时的端口占用错误。

排查与解决方法

1. 修正Cluster代码逻辑

确保主进程仅负责管理子进程,不监听端口;子进程监听端口时显式开启端口共享:

const cluster = require('cluster');
const os = require('os');
const http = require('http');

// Node.js v16+ 使用 isPrimary,旧版本用 isMaster
if (cluster.isPrimary) {
  const numCPUs = os.cpus().length;
  for (let i = 0; i < numCPUs; i++) {
    cluster.fork();
  }

  // 子进程异常退出时自动重启
  cluster.on('exit', (worker) => {
    console.log(`子进程 ${worker.process.pid} 退出,重启中`);
    cluster.fork();
  });
} else {
  const server = http.createServer((req, res) => {
    res.writeHead(200);
    res.end('服务响应\n');
  });

  // 显式开启 reusePort 确保多进程共享端口
  server.listen(3000, { reusePort: true }, () => {
    console.log(`子进程 ${process.pid} 监听端口3000`);
  });

  // 捕获端口占用错误,添加重试逻辑
  server.on('error', (err) => {
    if (err.code === 'EADDRINUSE') {
      console.error(`进程 ${process.pid} 端口3000被占用,1秒后重试`);
      setTimeout(() => {
        server.close();
        server.listen(3000, { reusePort: true });
      }, 1000);
    } else {
      throw err;
    }
  });
}

2. 检查部署脚本

  • 确保部署脚本仅执行一次启动命令,避免重复启动主进程。
  • 启动前可添加进程检查命令(如pkill -f node),清理可能残留的Node进程(即使是全新实例,也可能因脚本重试导致进程残留)。

3. 验证系统端口共享配置

在EC2实例上执行以下命令,确认SO_REUSEPORT相关配置是否开启:

sysctl net.ipv4.tcp_tw_reuse net.ipv4.tcp_tw_recycle

若返回值为0,可临时开启:

sysctl -w net.ipv4.tcp_tw_reuse=1
sysctl -w net.ipv4.tcp_tw_recycle=1

如需永久生效,可编辑/etc/sysctl.conf添加对应配置后执行sysctl -p。

内容的提问来源于stack exchange,提问作者Abhay Gupta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.24 07:17:58