【问题标题】:mongoError: Topology was destroyedmongoError:拓扑被破坏
【发布时间】:2015-09-03 17:53:37
【问题描述】:

我有一个内置在 node.js 中的 REST 服务,带有 Restify 和 Mongoose,还有一个 mongoDB,其中包含大约 30.000 个常规大小的文档。 我的节点服务通过 pmx 和 pm2 运行。

昨天,突然,节点开始用消息“MongoError:拓扑被破坏”来解决错误,仅此而已。 我不知道这是什么意思,什么可能触发了这个。谷歌搜索时也找不到太多东西。所以我想我会在这里问。

今天重启节点服务后,错误停止了。 我也有其中一个在生产中运行,这让我害怕,这可能在任何给定时间发生在运行的设置的一个非常关键的部分......

我正在使用上述软件包的以下版本:

  • 猫鼬:4.0.3
  • 修复:3.0.3
  • 节点:0.10.25

【问题讨论】:

  • 我只使用 mongodb 驱动程序时遇到了类似的问题 :(
  • 我没有使用风帆,所以不,我认为这不能解决我的问题

标签: node.js mongodb mongoose restify pm2


【解决方案1】:

这似乎意味着您的节点服务器与您的 MongoDB 实例的连接在尝试写入时被中断。

看看Mongo source code that generates that error

Mongos.prototype.insert = function(ns, ops, options, callback) {
    if(typeof options == 'function') callback = options, options = {};
    if(this.s.state == DESTROYED) return callback(new MongoError(f('topology was destroyed')));
    // Topology is not connected, save the call in the provided store to be
    // Executed at some point when the handler deems it's reconnected
    if(!this.isConnected() && this.s.disconnectHandler != null) {
      callback = bindToCurrentDomain(callback);
      return this.s.disconnectHandler.add('insert', ns, ops, options, callback);
    }

    executeWriteOperation(this.s, 'insert', ns, ops, options, callback);
}

这似乎与 cmets 中引用的 Sails 问题无关,因为没有安装任何升级来促成崩溃或“修复”

【讨论】:

  • 我有同样的问题,它几乎每周都会发生并关闭使用 mongo 的应用程序,这是我产生的一些问题还是 mongoose 中的问题?
  • @MohammadGanji:我在没有 Mongoose 的情况下收到此错误,同时调试客户端代码并且在单步执行语句时速度不够快。不确定是什么原因造成的,但是在 mongo 查询之后立即设置断点可以避免它。
  • @DanDascalescu 我忘了说我的问题已经解决了,这是日志记录的问题,看起来日志中有一些警告,在一段时间后占用了大约 1 GB 的存储空间并关闭了 mongo 进程,所以我尝试压缩和备份并解决问题
【解决方案2】:

我知道 Jason 的回答被接受了,但我对 Mongoose 也有同样的问题,发现 the service hosting my database recommended to apply the following settings 是为了让 Mongodb 的连接在生产中保持活跃:

var options = {
  server: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } },
  replset: { socketOptions: { keepAlive: 1, connectTimeoutMS: 30000 } }
};
mongoose.connect(secrets.db, options);

我希望这个回复可以帮助其他遇到“拓扑被破坏”错误的人。

【讨论】:

  • 这并没有解决我的问题。实际上,我最终将我的 keepAlive 增加到 30000,这非常有帮助。即使我仍然遇到偶尔的拓扑错误。
  • 使用 3.4.2 版本的 Mongo 驱动,这些选项需要在顶层: options: { keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000 }
  • 我在没有 Mongoose 的情况下收到此错误,同时调试客户端代码并且在单步执行语句时速度不够快。不确定是什么原因造成的,但是在 mongo 查询之后立即设置断点可以避免它。
【解决方案3】:

此错误是由于 mongo 驱动程序因任何原因断开连接(例如服务器已关闭)。

默认情况下,猫鼬会尝试重新连接 30 秒,然后停止重试并永远抛出错误,直到重新启动。

您可以通过编辑连接选项中的这两个字段来更改此设置

mongoose.connect(uri, 
    { server: { 
        // sets how many times to try reconnecting
        reconnectTries: Number.MAX_VALUE,
        // sets the delay between every retry (milliseconds)
        reconnectInterval: 1000 
        } 
    }
);

connection options documentation

【讨论】:

  • 是的。从技术上讲,接受的答案回答了所提出的问题,但这是避免正在讨论的场景的正确方法。
  • 使用 3.4.2 版本的 Mongo 驱动,这些选项需要在顶层: options: { keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 2000 }
  • 澄清一下,根据documentation of the Node MongoDB Driver,默认情况下服务器会尝试重新连接 30 次,每次重试之间间隔一秒。
  • 您现在不需要在服务器对象下提供这些选项。它直接进入选项对象。
  • 只是想补充一下,最近版本的猫鼬在顶层有这些选项,所以不需要添加server: {等。
【解决方案4】:

在我的例子中,这个错误是由 'async' 内的 'await' 部分中的 db.close(); 引起的

MongoClient.connect(url, {poolSize: 10, reconnectTries: Number.MAX_VALUE, reconnectInterval: 1000}, function(err, db) {
    // Validate the connection to Mongo
    assert.equal(null, err);    
    // Query the SQL table 
    querySQL()
    .then(function (result) {
        console.log('Print results SQL');
        console.log(result);
        if(result.length > 0){

            processArray(db, result)
            .then(function (result) {
                console.log('Res');
                console.log(result);
            })
            .catch(function (err) {
                console.log('Err');
                console.log(err);
            })
        } else {
            console.log('Nothing to show in MySQL');
        }
    })
    .catch(function (err) {
        console.log(err);
    });
    db.close(); // <--------------------------------THIS LINE
});

【讨论】:

  • 在 Carlos 的情况下,我猜收盘发生在其他一切之前。我的情况类似:我在关闭数据库后访问了它。如果 Mongo 开发人员可以生成更明确的错误消息,那就太好了。 “拓扑损坏”听起来像是一个内部注释。
  • 您的解决方案是将db.close 移动到then 块中,对吗?
  • 这是正确的,在我的情况下,我只删除了 db.close() 行,但将其移入 then 块似乎是一个不错的解决方案。
  • db.close 移动到 then 块对我来说非常适合使用原生 MongoDB Node.js 驱动程序。
【解决方案5】:

只是对 Gaafar 答案的一个小补充,它给了我一个弃用警告。而不是在服务器对象上,像这样:

MongoClient.connect(MONGO_URL, {
    server: {
        reconnectTries: Number.MAX_VALUE,
        reconnectInterval: 1000
    }
});

它可以放在顶层对象上。基本上,只需将其从服务器对象中取出并放入 options 对象中,如下所示:

MongoClient.connect(MONGO_URL, {
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 1000
});

【讨论】:

    【解决方案6】:

    “拓扑被破坏”可能是由于在创建 mongo 文档索引之前 mongoose 断开连接造成的,根据this comment

    为了确保所有模型在断开连接之前都已建立索引,您可以:

    await Promise.all(mongoose.modelNames().map(model => mongoose.model(model).ensureIndexes()));
    
    await mongoose.disconnect();
    

    【讨论】:

    • 谢谢你,如果你正在运行测试用例 - 这可能是一个很可能的答案......
    • 这是给我的。谢谢!我在 Jest 中使用 mongodb-memory-server 运行测试,在拓扑或打开句柄/未完成的 Promise 上出现零星错误。但有时它奏效了。添加对索引的等待修复了它。
    • 我在没有 Mongoose 的情况下出现此错误,同时调试像 @roblingle 这样的 Jest 代码并且在单步执行语句时速度不够快。不确定是什么原因造成的,但是在 mongo 查询之后立即设置断点可以避免它。
    • @roblingle 你是怎么解决的?我刚刚遇到了这个问题,这让我无法再次连接到 MongoDB。我已经删除了所有内容并重新安装了 MongoDB(通过自制软件),现在它不再在启动时运行。 (可能是不相关的问题)
    • 听起来不相关。我的应用运行良好,但测试失败。
    【解决方案7】:

    我在 kubernetes/minikube + nodejs + mongoose 环境中遇到了这个。 问题是 DNS 服务出现了某种延迟。检查 DNS 已准备好解决了我的问题。

    const dns = require('dns');
    
    var dnsTimer = setInterval(() => {
    	dns.lookup('mongo-0.mongo', (err, address, family) => {
    		if (err) {
    			console.log('DNS LOOKUP ERR', err.code ? err.code : err);
    		} else {
    			console.log('DNS LOOKUP: %j family: IPv%s', address, family);
    			clearTimeout(dnsTimer);
    			mongoose.connect(mongoURL, db_options);
    		}
    	});
    }, 3000);
    
    
    var db = mongoose.connection;
    var db_options = {
    	autoReconnect:true,
    
    	poolSize: 20,
    	socketTimeoutMS: 480000,
    	keepAlive: 300000,
    
    	keepAliveInitialDelay : 300000,
    	connectTimeoutMS: 30000,
    	reconnectTries: Number.MAX_VALUE,
    	reconnectInterval: 1000,
    	useNewUrlParser: true
    };

    (db_options 中的数字是在 stackoverflow 和类似网站上任意找到的)

    【讨论】:

      【解决方案8】:

      Sebastian 对 Adrien 的回答的评论需要更多关注,这对我有帮助,但有时可能会忽略它所以这是一个解决方案

      var options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000 }
      mongoose.connect(config.mongoConnectionString, options, (err) => {
          if(err) {
              console.error("Error while connecting", err);
          }
      });
      

      【讨论】:

        【解决方案9】:

        我也有同样的错误。最后,我发现我的代码有一些错误。我对两个 nodejs 服务器使用负载平衡,但我只是更新了一个服务器的代码。

        我更改了我的mongod服务器from standalone to replication,但是忘记对连接字符串做相应的更新,所以遇到了这个错误。

        独立连接字符串: mongodb://server-1:27017/mydb 复制连接字符串: mongodb://server-1:27017,server-2:27017,server-3:27017/mydb?replicaSet=myReplSet

        详情看这里:[mongo doc for connection string]

        【讨论】:

          【解决方案10】:

          这是我所做的,它工作正常。添加以下选项后问题消失了。

          const dbUrl = "mongodb://localhost:27017/sampledb";
          const options =  { useMongoClient: true, keepAlive: 1, connectTimeoutMS: 30000, reconnectTries: 30, reconnectInterval: 5000, useNewUrlParser: true }
          mongoose.connect(dbUrl,options, function(
            error
          ) {
            if (error) {
              console.log("mongoerror", error);
            } else {
              console.log("connected");
            }
          
          });
          

          【讨论】:

            【解决方案11】:

            需要重启mongo解决拓扑错误,然后改一些mongoose或者mongoclient的选项就可以解决这个问题:

            var mongoOptions = {
                useMongoClient: true,
                keepAlive: 1,
                connectTimeoutMS: 30000,
                reconnectTries: Number.MAX_VALUE,
                reconnectInterval: 5000,
                useNewUrlParser: true
            }
            
            mongoose.connect(mongoDevString,mongoOptions);
            

            【讨论】:

            【解决方案12】:

            我在 MongoDb Compass 社区上创建新数据库时遇到此错误。问题出在我的 Mongod 上,它没有运行。因此,作为修复,我必须像之前一样运行 Mongod 命令。

            C:\Program Files\MongoDB\Server\3.6\bin>mongod
            

            运行该命令后,我能够创建数据库。

            希望对你有帮助。

            【讨论】:

              【解决方案13】:

              我为此苦苦挣扎了一段时间 - 正如您从其他答案中看到的那样,问题可能非常不同。

              找出原因的最简单方法是在选项中打开loggerLevel: 'info'

              【讨论】:

                【解决方案14】:

                就我而言,此错误是由已在后台运行的相同服务器实例引起的。

                奇怪的是,当我在没有通知的情况下启动我的服务器时,已经有一个正在运行,控制台没有显示类似“某物正在使用端口 xxx”之类的信息。我什至可以上传一些东西到服务器。所以,我花了很长时间才找到这个问题。

                更重要的是,在关闭所有我能想象到的应用程序后,我仍然无法在我的 Mac 的活动监视器中找到使用此端口的进程。我必须使用lsof 来追踪。罪魁祸首并不奇怪——它是一个节点进程。但是,在终端显示的 PID 中,我发现监视器中的端口号与我的服务器使用的端口号不同。

                总而言之,杀死所有节点进程可以直接解决这个问题。

                【讨论】:

                  【解决方案15】:

                  在这里使用猫鼬,但没有它你也可以做类似的检查

                  export async function clearDatabase() {
                    if (mongoose.connection.readyState === mongoose.connection.states.disconnected) {
                      return Promise.resolve()
                    }
                    return mongoose.connection.db.dropDatabase()
                  }
                  

                  我的用例只是测试抛出错误,所以如果我们断开连接,我不会运行操作。

                  【讨论】:

                    【解决方案16】:

                    我最近遇到了这个问题。这是我的工作:

                    1. 重启MongoDb:sudo service mongod restart
                    2. 重新启动我的 NodeJS 应用程序。我使用 pm2 来处理这个pm2 restart [your-app-id]。要获取 ID,请使用 pm2 list

                    【讨论】:

                      【解决方案17】:

                      我通过以下方式解决了这个问题:

                      1. 确保 mongo 正在运行
                      2. 重新启动我的服务器

                      【讨论】:

                      • 这并不能防止问题再次发生
                      猜你喜欢
                      • 2015-07-09
                      • 2020-10-23
                      • 2016-12-27
                      • 2021-04-30
                      • 2019-01-15
                      • 2019-11-14
                      • 2015-08-06
                      相关资源
                      最近更新 更多