mongoError:拓扑已被破坏


163

我有一个用Restify和Mongoose在node.js中构建的REST服务,以及一个mongoDB,它的集合包含大约30.000个常规大小的文档。我的节点服务通过pmx和pm2运行。

昨天,节点突然开始通过消息“ MongoError:拓扑已被破坏”消除错误,仅此而已。我不知道这是什么意思,可能触发了什么。谷歌搜索时也没有太多发现。所以我想在这里问。

今天重新启动了节点服务后,错误停止了出现。我也有其中一个正在生产中运行,这使我感到害怕,这可能在任何给定时间发生在运行在那里的设置的相当关键的部分...

我正在使用以下版本的提及的软件包:

  • 猫鼬:4.0.3
  • 重新调整:3.0.3
  • 节点:0.10.25

2
我仅使用mongodb驱动程序存在类似问题:(
0x8890

1
我没有用帆,所以不,我认为这不会解决我的问题
dreagan

Answers:


98

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

看一下产生该错误Mongo源代码

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);
}

这似乎与注释中引用的Sails问题无关,因为未安装任何升级来加速崩溃或“修复”


2
我有同样的问题,几乎每个星期都会发生,并关闭与mongo一起使用的应用程序,这是我产生的一些问题还是这是猫鼬的问题?
Mohammad Ganji

@MohammadGanji:我在没有Mongoose的情况下遇到此错误,同时调试了客户端代码并且在执行语句时不够快。不知道是什么原因导致的,但是在mongo查询之后立即设置断点可以避免这种情况。
Dan Dascalescu

@DanDascalescu我忘了提到我的问题已解决,这是日志记录问题,看起来日志中有些警告,表明一段时间后需要大约1 GB的存储空间并关闭mongo进程,因此我尝试了压缩和备份和问题得到解决
Mohammad Ganji '18

83

我知道Jason的答案已被接受,但是Mongoose遇到了同样的问题,并且发现托管我的数据库的服务建议应用以下设置,以使Mongodb的连接在生产中保持活动状态:

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

我希望此答复可以帮助其他人遇到“拓扑已被破坏”错误。


4
这并不能解决我的问题。实际上我最终将我的keepAlive增加到30000,这极大地帮助了我。即使我仍然偶尔遇到拓扑错误,也仍然会出现。
ifightcrime,2016年

9
使用3.4.2版以上的Mongo驱动程序时,这些选项必须处于最高级别:选项:{keepAlive:1,connectTimeoutMS:30000,reconnectTries:30,reconnectInterval:5000}
Sebastien H.

我在没有Mongoose的情况下遇到了此错误,同时调试了客户端代码并且在执行语句时不够快。不知道是什么原因导致的,但是在mongo查询之后立即设置断点可以避免这种情况。
Dan Dascalescu

76

此错误是由于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 
        } 
    }
);

连接选项文档


3
是的 从技术上讲,公认的答案可以回答所提出的问题,但这是避免正在讨论的情况的正确方法。
kingdango

3
使用3.4.2版以上的Mongo驱动程序时,这些选项必须处于最高级别:选项:{keepAlive:1,connectTimeoutMS:30000,reconnectTries:30,reconnectInterval:2000}
Sebastien H.

1
为了明确起见,根据Node MongoDB Driver文档,默认情况下,服务器将尝试重新连接30次,每次重试之间间隔一秒钟。
波阿斯

4
您现在不需要在服务器对象下提供这些选项。它直接进入选项对象。
Animesh Singh

3
只是想补充的是最新版本的猫鼬拥有顶级的选项,所以没有必要添加server: {
亚历ķ

17

就我而言,此错误是由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
});

2
在卡洛斯的情况下,我猜想关闭是在其他所有事情之前发生的。我的情况类似:关闭数据库后,我访问了数据库。如果Mongo开发人员可以产生更明确的错误消息,那就太好了。“拓扑已损坏”听起来像是内部注释。
胡安·拉努斯

3
您的解决方案是将其移动db.close到一个then街区,对不对?
AlexChaffee

没错,就我而言,我只删除db.close()行,但是将其移至then块似乎是一个不错的解决方案。
卡洛斯·罗德里格斯

1
使用本地MongoDB Node.js驱动程序,将其移动db.close到一个then块对我来说非常有用。
kevinmicke

12

加法尔(Gaafar)的回答只是很小的补充,它给了我一个过时的警告。而不是在服务器对象上,像这样:

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

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

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

7

根据此注释,“拓扑被破坏”可能是由于在创建mongo文档索引之前断开猫鼬的连接引起的

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

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

await mongoose.disconnect();

谢谢,如果您正在运行测试用例-这可能是一个很可能的答案...
Nick H247

1
这是给我的。谢谢!我正在用mongodb-memory-server在Jest中运行测试,在拓扑或打开的句柄/未完成的Promises上出现了零星的错误。但有时它起作用。添加索引等待修复了它。
roblingle

在调试诸如@roblingle之类的Jest代码并且没有足够快地执行语句时,我遇到了没有Mongoose的错误。不知道是什么原因导致的,但是在mongo查询之后立即设置断点可以避免这种情况。
Dan Dascalescu '18

@roblingle您最终如何解决它?我只是遇到了这个问题,这使我无法再次连接到MongoDB。此后,我删除了所有内容并重新安装了MongoDB(通过自制程序),现在它不再在启动时运行。(可能是无关的问题)
bobbyz

听起来无关。我的应用程序运行良好,但测试失败。
roblingle '18 -10-21

3

塞巴斯蒂安(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);
    }
});

2

我也有同样的错误。最后,我发现我的代码有一些错误。我为两台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]


2

我在kubernetes / minikube + nodejs +猫鼬环境中遇到了这个问题。问题在于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和类似站点上可以任意找到的)


2

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

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");
  }

});

2

您需要重新启动mongo以解决拓扑错误,然后只需更改mongoose或mongoclient的某些选项即可解决此问题:

var mongoOptions = {
    useMongoClient: true,
    keepAlive: 1,
    connectTimeoutMS: 30000,
    reconnectTries: Number.MAX_VALUE,
    reconnectInterval: 5000,
    useNewUrlParser: true
}

mongoose.connect(mongoDevString,mongoOptions);

欢迎来到SO!请编辑您的答案并添加更多信息,即它如何解决问题,有关更多指导,请参见stackoverflow.com/help/how-to-ask
B--rian

1

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

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

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

希望能帮助到你。


1

我为此苦了一段时间-从其他答案中可以看出,问题可能大不相同。

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


0

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

奇怪的是,当我启动服务器而未通知服务器已经在运行时,控制台未显示“正在使用端口xxx”之类的信息。我什至可以将某些内容上传到服务器。因此,我花了很长时间才找到这个问题。

而且,在关闭所有我可以想象的应用程序之后,我仍然无法在Mac的活动监视器中找到正在使用此端口的进程。我必须用lsof跟踪。罪魁祸首并不奇怪-这是一个节点过程。但是,使用终端中显示的PID,我发现监视器中的端口号与服务器使用的端口号不同。

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


-3

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

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

4
这不会阻止问题再次发生
Sam Munroe '18
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.