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

如何用Node.js初始化MongoDB副本集?解决连接超时问题

MongoDB副本集初始化死锁问题解决(Node.js环境)

问题描述

我尝试用以下Node.js代码初始化MongoDB副本集:

try {
  const mongoClient: MongoClient = new MongoClient(process.env.MONGODB_URI || 'mongodb://mongodb:27017', {replicaSet: "rs0"});
  const mongoDb: Db = new Db(mongoClient, "admin");
  const response = await mongoDb.admin().command({ replSetInitiate: {} }, {})
} catch (error) {
  console.error(error)
}

但执行时出现错误:

MongoServerSelectionError: Server selection timed out after 30000 ms

其他数据库命令也遇到同样的超时问题,虽然用mongosh执行rs.initiate()可以解决,但我需要在Node.js运行时完成初始化。排查后发现这是死锁状态:初始化副本集需要先连接数据库,而驱动连接时因为指定了副本集参数,会等待副本集状态就绪,导致连接超时。

版本信息:MongoDB 4.2,mongodb npm包4.10.0

补充MongoDB启动日志:

I  CONTROL  [main] Automatically disabling TLS 1.0, to force-enable TLS 1.0 specify --sslDisabledProtocols 'none'
W  ASIO     [main] No TransportLayer configured during NetworkInterface startup
I  CONTROL  [initandlisten] MongoDB starting : pid=1 port=27017 dbpath=/data/db 64-bit host=mongodb
I  CONTROL  [initandlisten] db version v4.2.22
I  CONTROL  [initandlisten] git version: eef44cd56b1cc11e5771736fa6cb3077e0228be2
I  CONTROL  [initandlisten] OpenSSL version: OpenSSL 1.1.1  11 Sep 2018
I  CONTROL  [initandlisten] allocator: tcmalloc
I  CONTROL  [initandlisten] modules: none
I  CONTROL  [initandlisten] build environment:
I  CONTROL  [initandlisten]     distmod: ubuntu1804
I  CONTROL  [initandlisten]     distarch: x86_64
I  CONTROL  [initandlisten]     target_arch: x86_64
I  CONTROL  [initandlisten] options: { net: { bindIp: "*" }, replication: { replSet: "rs0" } }
I  STORAGE  [initandlisten]
I  STORAGE  [initandlisten] ** WARNING: Using the XFS filesystem is strongly recommended with the WiredTiger storage engine
I  STORAGE  [initandlisten] **          See http://dochub.mongodb.org/core/prodnotes-filesystem
I  STORAGE  [initandlisten] wiredtiger_open config: create,cache_size=12243M,cache_overflow=(file_max=0M),session_max=33000,eviction=(threads_min=4,threads_max=4),config_base=false,statistics=(fast),log=(enabled=true,archive=true,path=journal,compressor=snappy),file_manager=(close_idle_time=100000,close_scan_interval=10,close_handle_minimum=250),statistics_log=(wait=0),verbose=[recovery_progress,checkpoint_progress],
I  STORAGE  [initandlisten] WiredTiger message [1665036200:416720][1:0x7f8baf77eb00], txn-recover: Set global recovery timestamp: (0, 0)
I  RECOVERY [initandlisten] WiredTiger recoveryTimestamp. Ts: Timestamp(0, 0)
I  STORAGE  [initandlisten] No table logging settings modifications are required for existing WiredTiger tables. Logging enabled? 0
I  STORAGE  [initandlisten] Timestamp monitor starting
I  CONTROL  [initandlisten]
I  CONTROL  [initandlisten] ** WARNING: Access control is not enabled for the database.
I  CONTROL  [initandlisten] **          Read and write access to data and configuration is unrestricted.
I  CONTROL  [initandlisten]
I  CONTROL  [initandlisten]
I  CONTROL  [initandlisten] ** WARNING: /sys/kernel/mm/transparent_hugepage/enabled is 'always'.
I  CONTROL  [initandlisten] **        We suggest setting it to 'never'
I  CONTROL  [initandlisten]
I  STORAGE  [initandlisten] Flow Control is enabled on this deployment.
I  STORAGE  [initandlisten] createCollection: local.startup_log with generated UUID: bd81a433-4ec3-48df-b67d-e37c47c24343 and options: { capped: true, size: 10485760 }
I  INDEX    [initandlisten] index build: done building index _id_ on ns local.startup_log
I  FTDC     [initandlisten] Initializing full-time diagnostic data capture with directory '/data/db/diagnostic.data'
I  STORAGE  [initandlisten] createCollection: local.replset.oplogTruncateAfterPoint with generated UUID: 0aa8d2bd-f0c7-4703-8641-a029cde77b48 and options: {}
I  INDEX    [initandlisten] index build: done building index _id_ on ns local.replset.oplogTruncateAfterPoint
I  STORAGE  [initandlisten] createCollection: local.replset.minvalid with generated UUID: 370687e5-79d9-4365-b6e0-b05cd4ab31f0 and options: {}
I  INDEX    [initandlisten] index build: done building index _id_ on ns local.replset.minvalid
I  STORAGE  [initandlisten] createCollection: local.replset.election with generated UUID: 4f892389-a4c5-4abb-b8e6-d5bdb282dc9f and options: {}
I  INDEX    [initandlisten] index build: done building index _id_ on ns local.replset.election
I  REPL     [initandlisten] Did not find local initialized voted for document at startup.
I  REPL     [initandlisten] Did not find local Rollback ID document at startup. Creating one.
I  STORAGE  [initandlisten] createCollection: local.system.rollback.id with generated UUID: 1049c565-09b2-4bf9-95c3-ade2162773f5 and options: {}
I  INDEX    [initandlisten] index build: done building index _id_ on ns local.system.rollback.id
I  REPL     [initandlisten] Initialized the rollback ID to 1
I  REPL     [initandlisten] Did not find local replica set configuration document at startup;  NoMatchingDocument: Did not find replica set configuration document in local.system.replset
I  CONTROL  [LogicalSessionCacheRefresh] Sessions collection is not set up; waiting until next sessions refresh interval: Replication has not yet been configured
I  NETWORK  [listener] Listening on /tmp/mongodb-27017.sock
I  NETWORK  [listener] Listening on 0.0.0.0
I  CONTROL  [LogicalSessionCacheReap] Sessions collection is not set up; waiting until next sessions reap interval: config.system.sessions does not exist
I  NETWORK  [listener] waiting for connections on port 27017
I  NETWORK  [listener] connection accepted from 172.21.0.7:56492 #1 (1 connection now open)
I  NETWORK  [conn1] received client metadata from 172.21.0.7:56492 conn1: { driver: { name: "nodejs", version: "3.7.3" }, os: { type: "Linux", name: "linux", architecture: "x64", version: "5.10.16.3-microsoft-standard-WSL2" }, platform: "'Node.js v12.22.7, LE (legacy)" }

解决方案

核心思路是拆分连接流程:先以单实例模式连接数据库(不指定replicaSet参数),执行初始化命令后,再切换到副本集模式连接。

修改后的代码:

try {
  // 第一步:以单实例模式连接,不指定副本集参数
  const mongoClient = new MongoClient(process.env.MONGODB_URI || 'mongodb://mongodb:27017');
  await mongoClient.connect();
  
  const adminDb = mongoClient.db('admin');
  // 显式指定副本集配置执行初始化
  const response = await adminDb.command({ 
    replSetInitiate: {
      _id: "rs0",
      members: [
        { _id: 0, host: "mongodb:27017" }
      ]
    }
  });
  
  console.log("副本集初始化成功:", response);
  
  // 关闭单实例连接
  await mongoClient.close();
  
  // 第二步:切换到副本集模式连接(后续业务操作使用)
  const replicaSetClient = new MongoClient(process.env.MONGODB_URI || 'mongodb://mongodb:27017', { replicaSet: "rs0" });
  await replicaSetClient.connect();
  console.log("已连接到副本集");
  
} catch (error) {
  console.error("初始化失败:", error);
}

注意事项

  • 初始化命令中显式定义成员配置,避免依赖默认配置可能出现的节点识别问题
  • 单实例连接时必须移除replicaSet参数,让驱动直接连接单个节点,跳过副本集状态校验
  • 初始化完成后建议等待2-3秒,让副本集状态同步稳定后再进行后续连接操作
  • 从启动日志看MongoDB已正常监听0.0.0.0,网络连接无问题,无需额外排查网络层面

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.18 01:40:25