MongoDB副本集连接异常:20个Node.js进程重启时出错
我来帮你分析下这个问题,结合Mongo副本集和Mongoose连接的特性,大概率是连接数过载或者重启时的连接风暴导致的——毕竟从16个进程升到20个后才出现问题,说明连接规模的变化触发了这个情况。下面给你几个具体的排查和解决方向:
一、先排查MongoDB的连接数是否超限
首先得确认主节点的连接负载情况,登录主节点的Mongo shell,执行这个命令查看当前连接状态:
db.serverStatus().connections
你会看到current(当前活跃连接数)、available(可用连接数)和max(最大允许连接数)这几个关键数值。如果current已经接近max,那就是连接数超限导致的报错。
解决办法:
- 修改Mongo的配置文件
mongod.conf,调整net.maxIncomingConnections参数(默认是10000,但实际受系统文件描述符限制),根据服务器的CPU、内存资源适当调高; - 同时要检查系统的文件描述符限制,用
ulimit -n查看,要是数值太低的话,需要修改系统配置(比如/etc/security/limits.conf)来提升,确保Mongo能用到足够的文件描述符。
二、优化Mongoose的连接池配置
每个Node.js进程的Mongoose连接池默认大小是5,20个进程加起来就是100个连接,看起来不多,但重启时多个进程同时重建连接,会瞬间产生连接峰值,压垮主节点。
你可以调整连接池参数,降低每个进程的连接池大小,同时优化重连逻辑:
const mongoose = require('mongoose'); // 替换成你的副本集连接字符串 const connStr = 'mongodb://host1:27017,host2:27017,host3:27017/your_db?replicaSet=your_rs_name'; mongoose.connect(connStr, { maxPoolSize: 3, // 降低每个进程的连接池大小,减少总连接数 minPoolSize: 1, // 保持最小空闲连接,避免频繁创建销毁连接 serverSelectionTimeoutMS: 5000, // 缩短节点选择超时时间 socketTimeoutMS: 45000, autoReconnect: true, reconnectTries: 30, // 增加重连次数 reconnectInterval: 1000 // 调整重连间隔 });
重点是把maxPoolSize降下来,比如设为3,20个进程总连接数就是60,远低于Mongo的默认上限,能有效缓解重启时的连接压力。
三、避免重启时的连接风暴
不要同时重启所有20个Node.js进程,采用滚动重启的方式:每次只重启1-2个进程,间隔30秒以上,给Mongo足够的时间处理旧连接的断开和新连接的建立。
另外,还可以在Node进程启动时加个小延迟,比如启动后等待1-2秒再初始化Mongo连接,避免多个进程同时发起连接请求。
四、检查仲裁节点的状态
虽然仲裁节点不存储数据,但它需要和主、从节点保持心跳通信。如果主节点压力过大,可能会影响心跳,导致副本集的状态判断异常。你可以查看仲裁节点的Mongo日志,看看有没有心跳超时的错误,确保仲裁节点的CPU、内存资源充足,没有被其他进程抢占。
五、精准定位问题:查看主节点的具体错误日志
上面的方法都是通用排查方向,要彻底解决问题,一定要看主节点的Mongo日志(Linux系统通常在/var/log/mongodb/mongod.log),找到重启Node进程时的具体错误信息,比如:
Too many open connections:明确是连接数超限Heartbeat failed:副本集节点间心跳异常Connection refused:连接请求被主节点拒绝
根据具体的错误信息再针对性调整配置,效率会更高。
内容的提问来源于stack exchange,提问作者Daphoque

