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

Express+PM2集群+Nginx负载均衡:请求无法并行运行问题求助

解决Express多实例+Nginx反向代理下请求串行阻塞的问题

从你的日志和配置来看,核心问题并不是Express实例本身不能并行处理请求,而是请求被串行转发到各个实例了——你能看到每个实例都是等前一个请求处理完才接收新请求,这说明请求没有同时到达多个实例,而是排队逐个分发。下面是具体的排查和解决步骤:

一、问题根源:HTTP/1.1的队头阻塞+连接复用

你的测试代码用axios默认配置发起请求时,会复用同一个TCP连接(HTTP/1.1默认开启keepalive)。而Nginx在处理单个TCP连接上的多个请求时,会按顺序转发到上游实例,不会把同一个连接里的请求分配到不同实例,这就导致了请求串行处理的现象。

二、解决方案:从客户端和Nginx两端优化

1. 客户端:强制发起多个TCP连接

修改axios的配置,禁用连接复用或者增大允许的并发连接数,让每个请求可以通过不同的连接发送:

const axios = require('axios');
const http = require('http');
const https = require('https');

// 创建自定义axios实例,配置多连接支持
const axiosInstance = axios.create({
  httpAgent: new http.Agent({ 
    keepAlive: false,  // 禁用连接复用,每个请求新建连接
    maxSockets: 10     // 允许同时建立10个连接
  }),
  httpsAgent: new https.Agent({ 
    keepAlive: false,
    maxSockets: 10 
  })
});

async sendRequest() {
  const startTime = performance.now();
  console.log("Sending request");
  const els = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9];
  const promises = els.map(() => axiosInstance.get("http://my_server_with_nginx:8000"));
  let results = await Promise.all(promises);
  console.log(results);
  const stopTime = performance.now();
  console.log("Time of request: " + (stopTime - startTime));
}

2. Nginx:优化上游连接配置

调整Nginx的上游和客户端连接设置,确保它能并行分发请求到多个Express实例:

upstream test_upstream {
  least_conn;  # 按最少连接数分发,比默认的轮询更合理
  server 127.0.0.1:3000;
  server 127.0.0.1:3001;
  server 127.0.0.1:3002;
  server 127.0.0.1:3003;
  keepalive 32;  # 与上游保持32个空闲连接,避免频繁新建连接
}

server {
  listen 8000;
  keepalive_timeout 65;  # 客户端连接超时时间
  keepalive_requests 100;  # 单个客户端连接允许的最大请求数,防止长期占用

  location / {
    # 启用与上游的HTTP/1.1 keepalive
    proxy_http_version 1.1;
    proxy_set_header Connection "";

    # 你的CORS配置保持不变
    proxy_hide_header Access-Control-Allow-Origin;
    add_header Access-Control-Allow-Origin * always;
    proxy_hide_header Access-Control-Allow-Methods;
    add_header Access-Control-Allow-Methods "GET,POST,DELETE,PUT,OPTIONS" always;
    proxy_hide_header Access-Control-Allow-Headers;
    add_header Access-Control-Allow-Headers "Authorization, X-Requested-With, Content-Type" always;
    proxy_hide_header Access-Control-Allow-Credentials;
    add_header Access-Control-Allow-Credentials "true" always;

    if ($request_method = OPTIONS ) {
      add_header Access-Control-Allow-Origin *;
      add_header Access-Control-Allow-Methods "GET,POST,DELETE,PUT,OPTIONS";
      add_header Access-Control-Allow-Headers "Authorization, X-Requested-With, Content-Type";
      add_header Access-Control-Allow-Credentials "true" always;
      add_header Content-Length 0;
      add_header Content-Type text/plain;
      add_header Allow GET,POST,DELETE,PUT,OPTIONS;
      return 200;
    }

    proxy_pass http://test_upstream;
  }
}

3. 验证并行效果

修改配置后重启Nginx和PM2,重新运行测试代码,你应该能看到Node日志里多个实例同时处理请求,比如:

0|index | -----> GOT REQUEST -> 1527796135425
1|index | -----> GOT REQUEST -> 1527796135426
2|index | -----> GOT REQUEST -> 1527796135427
3|index | -----> GOT REQUEST -> 1527796135428
0|index | Response time: 1527796135572
1|index | Response time: 1527796135573
...

也可以用curl快速验证:

for i in {1..10}; do curl http://localhost:8000 & done

三、额外建议

  • 你的Express代码本身是无状态的异步处理,只要请求能并行到达,就能充分利用多实例的优势
  • 如果后续性能还不够,可以考虑升级到HTTP/2(Nginx和Express都支持),从协议层面解决队头阻塞问题

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.29 09:07:13