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

Node.js集群环境下数据库单例模式失效问题排查

问题原因

你的单例模式在单个Node.js进程内是有效的,但因为使用了cluster模块,而cluster的每个worker都是独立的V8进程,内存完全隔离——每个worker都会重新加载你的database模块,各自初始化自己的database.instance,自然会创建多份数据库连接。

解决方案

根据业务场景,有两种常用处理方式:

方式一:主进程统一管理数据库连接,Worker通过IPC通信

让主进程单独初始化数据库连接,所有worker不直接连接数据库,而是通过进程间通信(IPC)把数据库操作请求发给主进程,主进程处理后返回结果。这样所有worker共用一套连接池,不会重复创建实例。

示例代码参考:

主进程代码

const cluster = require('cluster');
const db = require('./database'); // 主进程初始化数据库

if (cluster.isPrimary) {
  // 监听worker的数据库操作请求
  cluster.on('message', (worker, msg) => {
    if (msg.type === 'mysql_query') {
      db.mysql.query(msg.sql, msg.params)
        .then(result => worker.send({ type: 'mysql_result', id: msg.id, result }))
        .catch(err => worker.send({ type: 'mysql_error', id: msg.id, err }));
    }
  });

  // 启动worker进程
  const cpuCount = require('os').cpus().length;
  for (let i = 0; i < cpuCount; i++) {
    cluster.fork();
  }
} else {
  // Worker进程处理业务请求,通过IPC委托主进程操作数据库
  app.get('/get-data', (req, res) => {
    const queryId = Date.now(); // 用ID标识请求,避免结果混淆
    process.send({ 
      type: 'mysql_query', 
      id: queryId, 
      sql: 'SELECT * FROM your_table WHERE id = ?',
      params: [req.query.id]
    });
    
    // 监听主进程返回的结果
    const handleResult = (msg) => {
      if (msg.id === queryId) {
        process.off('message', handleResult);
        if (msg.type === 'mysql_result') {
          res.json(msg.result);
        } else {
          res.status(500).send(msg.err.message);
        }
      }
    };
    process.on('message', handleResult);
  });
}

方式二:每个Worker维持独立连接池,但严格限制连接数

如果业务需要worker直接操作数据库(避免IPC的性能开销),那每个worker都会创建自己的连接池,此时必须降低单个worker的连接池上限,防止数据库连接数被打满。

原代码里connectionLimit: 10000的设置完全不合理,数据库默认最大连接数通常在100-1000区间。假设你有8个worker,可将单个worker的连接数设为10,总连接数控制在80以内:

createMysql() {
    this.mysql = mysqlModule.createPool({
        // ...其他原有配置
        connectionLimit: 10, // 根据worker数量和数据库最大连接数灵活调整
        // ...其他原有配置
    });
}

这种方式下每个worker仍会创建独立实例,但连接数处于可控范围,不会造成资源浪费或数据库连接溢出。

补充说明

你之前尝试把instance变量放到类外部无效,本质原因是cluster的每个worker拥有独立内存空间,模块内的变量在每个worker进程中都会重新初始化,跨进程无法共享任何内存数据。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.30 16:25:26