如何用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
相关产品推荐
相关产品推荐

