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

为何使用Cluster模块后请求仍在同一PID/线程运行?未实现多线程?

为什么Express+Cluster没有以多线程模式处理请求?

问题核心原因

  • 浏览器TCP连接复用:现代浏览器会对同一域名的请求复用已建立的TCP连接,而Cluster模块默认的轮询负载均衡是基于新连接分配Worker进程的。如果在同一个浏览器窗口连续发起请求,所有请求会复用同一个连接,因此都会被同一个Worker进程处理,导致你看到的PID一致。
  • 代码逻辑冗余(非直接原因):else if (cluster) 这个判断完全多余,因为cluster是已加载的模块对象,永远为真。正确的写法应该是直接用else,明确子进程的启动分支。

验证与修复方法

  1. 正确验证多进程:

    • 使用不同浏览器、Postman多窗口同时发起请求,或者在命令行用curl多次执行(每次请求都是新TCP连接),就能看到请求被分配到不同PID的Worker进程。
    • 比如打开多个命令行窗口,同时执行:
      curl http://localhost:8000/
      curl http://localhost:8000/timer
      
  2. 修正代码逻辑:
    将子进程的判断分支改为else,让代码逻辑更清晰:

    const express=require("express");
    const app=express();
    const cluster=require('cluster');
    const os=require('os');
    
    function delay(duration){
        const start=Date.now();
        while(Date.now()-start<duration){}
    }
    
    app.get('/',(req,res)=>{
        res.status(200).send(`request running at id ${process.pid}`)
    })
    
    app.get('/timer',(req,res)=>{
        delay(5000)
        res.status(200).send(`Timer running at id ${process.pid}`)
    })
    
    if(cluster.isPrimary){
        console.log(`Master running...`)
        const NUM_WORKERS=os.cpus().length
        for(let i=0;i<NUM_WORKERS;i++){
            cluster.fork()
        }
    }
    else {
        console.log(`Fork running at ${process.pid}`)
        app.listen(8000,()=>{
            console.log(`Server is running at port ${8000}`)
        })
    }
    
  3. 关于同步阻塞的补充:
    你的delay函数是同步阻塞操作,一旦某个Worker处理了/timer请求,该Worker会被阻塞5秒无法处理其他请求,但其他Worker仍能正常响应请求。用多客户端同时请求时,就能明显看到不同PID的Worker在处理请求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.27 05:34:59