node.js mongoDB 有重新连接问题还是我做错了?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/13980236/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-09-02 16:47:52  来源:igfitidea点击:

Does mongoDB have reconnect issues or am i doing it wrong?

node.jsmongodbazuremongoosemlab

提问by rob_james

I'm using nodejs and a mongoDB - and I'm having some connection issues.

我正在使用 nodejs 和 mongoDB - 我遇到了一些连接问题。

Well, actually "wake" issues! It connects perfectly well - is super fast and I'm generally happy with the results.

好吧,实际上是“唤醒”问题!它连接得非常好 - 速度非常快,我对结果通常很满意。

My problem:If i don't use the connection for a while (i say while, because the timeframe varies 5+ mins) it seems to stall. I don't get disconnection events fired - it just hangs.

我的问题:如果我有一段时间不使用连接(我说是一段时间,因为时间范围变化超过 5 分钟),它似乎会停止。我不会触发断开连接事件 - 它只是挂起。

Eventually i get a response like Error: failed to connect to [ * .mongolab.com: * ] - ( * = masked values)

最终我得到一个响应,如 Error: failed to connect to [ * .mongolab.com: * ] - ( * = masked values)

A quick restart of the app, and the connection's great again. Sometimes, if i don't restart the app, i can refresh and it reconnects happily.

快速重启应用程序,连接再次良好。有时,如果我不重新启动应用程序,我可以刷新并愉快地重新连接。

This is why i think it is "wake" issues.

这就是为什么我认为这是“唤醒”问题。

Rough outline of code:

粗略的代码概要:

I've not included the code - I don't think it's needed. It works (apart from the connection dropout)

我没有包含代码 - 我认为不需要它。它有效(除了连接丢失)

Things to note:There is just the one "connect" - i never close it. I never reopen.

注意事项:只有一个“连接”——我从不关闭它。我从来没有重新打开过。

I'm using mongoose, socketio.

我正在使用猫鼬,socketio。

/* constants */

var mongoConnect = 'myworkingconnectionstring-includingDBname';


/* includes */

/* settings */

/* Schema */

var db = mongoose.connect(mongoConnect);

    /* Socketio */

io.configure(function (){
    io.set('authorization', function (handshakeData, callback) {

    });
});

io.sockets.on('connection', function (socket) {

});//sockets

io.sockets.on('disconnect', function(socket) {
    console.log('socket disconnection')
});

/* The Routing */

app.post('/login', function(req, res){  

});

app.get('/invited', function(req, res){

});

app.get('/', function(req, res){

});

app.get('/logout', function(req, res){

});

app.get('/error', function(req, res){

});

server.listen(port);
console.log('Listening on port '+port);

db.connection.on('error', function(err) {
    console.log("DB connection Error: "+err);
});
db.connection.on('open', function() {
    console.log("DB connected");
});
db.connection.on('close', function(str) {
    console.log("DB disconnected: "+str);
});

I have tried various configs here, like opening and closing all the time - I believe though, the general consensus is to do as i am with one open wrapping the lot. ??

我在这里尝试了各种配置,比如一直打开和关闭 - 不过我相信,普遍的共识是像我一样做一个打开包装的东西。??

I have tried a connection tester, that keeps checking the status of the connection... even though this appears to say everthing's ok - the issue still happens.

我尝试了一个连接测试器,它会不断检查连接的状态......即使这似乎表明一切正常 - 问题仍然存在。

I have had this issue from day one. I have always hosted the MongoDB with MongoLab. The problem appears to be worse on localhost. But i still have the issue on Azure and now nodejit.su.

我从第一天起就有这个问题。我一直用 MongoLab 托管 MongoDB。本地主机上的问题似乎更糟。但是我在 Azure 和现在的 nodejit.su 上仍然有问题。

As it happens everywhere - it must be me, MongoDB, or mongolab.

因为它无处不在 - 必须是我、MongoDB 或 mongolab。

Incidentally i have had a similar experience with the php driver too. (to confirm this is on nodejs though)

顺便说一句,我对 php 驱动程序也有类似的经历。(不过要确认这是在 nodejs 上)

It would be great for some help - even if someone just says "this is normal"

提供一些帮助会很棒 - 即使有人只是说“这是正常的”

thanks in advance

提前致谢

Rob

采纳答案by rob_james

Thanks for all the help guys - I have managed to solve this issue on both localhost and deployed to a live server.

感谢所有帮助人员 - 我已经设法在本地主机上解决了这个问题并部署到了实时服务器。

Here is my now working connect code:

这是我现在工作的连接代码:

var MONGO = {
    username: "username",
    password: "pa55W0rd!",
    server: '******.mongolab.com',
    port: '*****',
    db: 'dbname',
    connectionString: function(){
        return 'mongodb://'+this.username+':'+this.password+'@'+this.server+':'+this.port+'/'+this.db;
    },
    options: {
        server:{
            auto_reconnect: true,
            socketOptions:{
                connectTimeoutMS:3600000,
                keepAlive:3600000,
                socketTimeoutMS:3600000
            }
        }
    }
};

var db = mongoose.createConnection(MONGO.connectionString(), MONGO.options);

db.on('error', function(err) {
    console.log("DB connection Error: "+err);
});
db.on('open', function() {
    console.log("DB connected");
});
db.on('close', function(str) {
    console.log("DB disconnected: "+str);
});

I think the biggest change was to use "createConnection" over "connect" - I had used this before, but maybe the options help now. This article helped a lot http://journal.michaelahlers.org/2012/12/building-with-nodejs-persistence.html

我认为最大的变化是使用“createConnection”而不是“connect”——我以前用过这个,但现在这些选项可能会有所帮助。这篇文章有很大帮助http://journal.michaelahlers.org/2012/12/building-with-nodejs-persistence.html

If I'm honest I'm not overly sure on why I have added those options - as mentioned by @jareed, i also found some people having success with "MaxConnectionIdleTime" - but as far as i can see the javascript driver doesn't have this option: this was my attempt at trying to replicate the behavior.

老实说,我不太确定为什么要添加这些选项 - 正如@jareed 所提到的,我还发现有些人在“MaxConnectionIdleTime”方面取得了成功 - 但据我所知,javascript 驱动程序没有有这个选项:这是我试图复制行为的尝试。

So far so good - hope this helps someone.

到目前为止一切顺利 - 希望这对某人有所帮助。

UPDATE: 18 April 2013note, this is a second app with a different setup

更新:2013 年 4 月 18 日注意,这是具有不同设置的第二个应用程序

Now I thought i had this solved but the problem rose it's ugly head again on another apprecently - with the same connection code. Confused!!!

现在我以为我已经解决了这个问题,但是最近在另一个应用程序上问题又出现了 - 使用相同的连接代码。使困惑!​​!!

However the set up was slightly different…

然而,设置略有不同......

This new app was running on a windows box using IISNode.I didn't see this as significant initially.

这个新应用程序运行在使用 IISNode 的 Windows 机器上。我最初并不认为这很重要。

I read there were possibly some issues with mongo on Azure (@jareed), so I moved the DB to AWS - still the problem persisted.

我读到 Azure (@jareed) 上的 mongo 可能存在一些问题,因此我将数据库移至 AWS - 问题仍然存在。

So i started playing about with that options object again, reading up quite a lot on it. Came to this conclusion:

所以我再次开始玩那个选项对象,阅读了很多关于它的内容。得出了这个结论:

options: {
    server:{
        auto_reconnect: true,
        poolSize: 10,
        socketOptions:{
            keepAlive: 1
        }
    },
    db: {
        numberOfRetries: 10,
        retryMiliSeconds: 1000
    }
}

That was a bit more educated that my original options object i state. However - it's still no good.

这比我声明的原始选项对象更具教育意义。但是 - 它仍然不好。

Now, for some reason i had to get off that windows box (something to do with a module not compiling on it) - it was easier to move than spend another week trying to get it to work.

现在,出于某种原因,我不得不离开那个窗口框(与未在其上编译的模块有关) - 移动比再花一个星期试图让它工作更容易。

So i moved my app to nodejitsu. Low and behold my connection stayed alive! Woo!

所以我将我的应用程序移至 nodejitsu。低,看哪,我的连接还活着!哇!

So…. what does this mean… I have no idea! What i do know is is those options seem to work on Nodejitsu…. for me.

所以…。这是什么意思……我不知道!我所知道的是这些选项似乎适用于 Nodejitsu ...... 为了我。

I believe IISNode uses some kind of "forever" script for keeping the app alive. Now to be fair the app doesn't crash for this to kick in, but i think there must be some kind of "app cycle" that is refreshed constantly - this is how it can do continuous deployment (ftp code up, no need to restart app) - maybe this is a factor; but i'm just guessing now.

我相信 IISNode 使用某种“永远”脚本来使应用程序保持活动状态。现在公平地说,应用程序不会崩溃,但我认为必须有某种“应用程序周期”不断刷新 - 这就是它如何进行持续部署(ftp 代码,无需重新启动应用程序) - 也许这是一个因素;但我现在只是猜测。

Of course all this means now, is this isn't solved. It's still not solved. It's just solved for me in my setup.

当然这一切都意味着现在,这还没有解决。它仍然没有解决。它刚刚在我的设置中为我解决了。

回答by jared

UPDATE: Our support article for this topic (essentially a copy of this post) has moved to our connection troubleshooting doc.

更新:我们针对该主题的支持文章(基本上是这篇文章的副本)已移至我们的连接故障排除文档

There is a known issue that the Azure IaaS network enforces an idle timeout of roughly thirteen minutes (empirically arrived at). We are working with Azure to see if we can't make things more user-friendly, but in the meantime others have had success by configuring their driver options to work around the issue.

有一个已知问题,即 Azure IaaS 网络强制执行大约 13 分钟的空闲超时(根据经验得出)。我们正在与 Azure 合作,看看我们是否不能让事情变得更加用户友好,但与此同时,其他人已经通过配置他们的驱动程序选项来解决这个问题,从而取得了成功。

Max connection idle time

最大连接空闲时间

The most effective workaround we've found in working with Azure and our customers has been to set the max connection idle time below four minutes. The idea is to make the driver recycle idle connections before the firewall forces the issue. For example, one customer, who is using the C# driver, set MongoDefaults.MaxConnectionIdleTimeto one minute and it cleared up their issues.

我们在与 Azure 和我们的客户合作时发现的最有效的解决方法是将最大连接空闲时间设置为四分钟以下。这个想法是让驱动程序在防火墙强制问题之前回收空闲连接。例如,一位使用 C# 驱动程序的客户设置MongoDefaults.MaxConnectionIdleTime为一分钟,这解决了他们的问题。

MongoDefaults.MaxConnectionIdleTime = TimeSpan.FromMinutes(1);

The application code itself didn't change, but now behind the scenes the driver aggressively recycles idle connections. The result can be seen in the server logs as well: lots of connection churn during idle periods in the app.

应用程序代码本身没有改变,但现在驱动程序在幕后积极回收空闲连接。结果也可以在服务器日志中看到:在应用程序空闲期间大量连接流失。

There are more details on this approach in the related mongo-user thread, SocketException using C# driver on azure.

在相关的 mongo-user 线程SocketException using C# driver on azure 中有关于此方法的更多详细信息。

Keepalive

活着

You can also work around the issue by making your connections less idle with some kind of keepalive. This is a little tricky to implement unless your driver supports it out of the box, usually by taking advantage of TCP Keepalive. If you need to roll your own, make sure to grab each idle connection from the pool every couple minutes and issue some simple and cheap command, probably a ping.

您还可以通过使用某种keepalive减少连接空闲来解决此问题。这实现起来有点棘手,除非您的驱动程序开箱即用地支持它,通常是通过利用TCP Keepalive。如果您需要自己动手,请确保每隔几分钟从池中获取每个空闲连接并发出一些简单而廉价的命令,可能是ping

Handling disconnects

处理断开连接

Disconnects can happen from time to time even without an aggressive firewall setup. Before you get into production you want to be sure to handle them correctly.

即使没有积极的防火墙设置,断开连接也会不时发生。在投入生产之前,您需要确保正确处理它们。

First, be sure to enable auto reconnect. How to do so varies from driver to driver, but when the driver detects that an operation failed because the connection was bad turning on auto reconnect tells the driver to attempt to reconnect.

首先,确保启用自动重新连接。如何这样做因驱动程序而异,但是当驱动程序检测到操作因连接不良而失败时,打开自动重新连接会告诉驱动程序尝试重新连接。

But this doesn't completely solve the problem. You still have the issue of what to do with the failed operation that triggered the reconnect. Auto reconnect doesn't automatically retry failed operations. That would be dangerous, especially for writes. So usually an exception is thrown and the app is asked to handle it. Often retrying reads is a no-brainer. But retrying writes should be carefully considered.

但这并不能完全解决问题。您仍然面临如何处理触发重新连接的失败操作的问题。自动重新连接不会自动重试失败的操作。那将是危险的,尤其是对于写入而言。所以通常会抛出异常并要求应用程序处理它。通常重试读取是轻而易举的。但是应该仔细考虑重试写入。

The mongo shell session below demonstrates the issue. The mongo shell by default has auto reconnect enabled. I insert a document in a collection named stuffthen find all the documents in that collection. I then set a timer for thirty minutes and tried the same find again. It failed, but the shell automatically reconnected and when I immediately retried my find it worked as expected.

下面的 mongo shell 会话演示了这个问题。默认情况下,mongo shell 已启用自动重新连接。我在名为的集合中插入一个文档,stuff然后查找该集合中的所有文档。然后我将计时器设置为 30 分钟并再次尝试相同的查找。它失败了,但外壳会自动重新连接,当我立即重试时,发现它按预期工作。

% mongo ds012345.mongolab.com:12345/mydatabase -u *** -p *** 
MongoDB shell version: 2.2.2 
connecting to: ds012345.mongolab.com:12345/mydatabase 
> db.stuff.insert({}) 
> db.stuff.find() 
{ "_id" : ObjectId("50f9b77c27b2e67041fd2245") } 
> db.stuff.find() 
Fri Jan 18 13:29:28 Socket recv() errno:60 Operation timed out 192.168.1.111:12345 
Fri Jan 18 13:29:28 SocketException: remote: 192.168.1.111:12345 error: 9001 socket exception [1] server [192.168.1.111:12345] 
Fri Jan 18 13:29:28 DBClientCursor::init call() failed 
Fri Jan 18 13:29:28 query failed : mydatabase.stuff {} to: ds012345.mongolab.com:12345 
Error: error doing query: failed 
Fri Jan 18 13:29:28 trying reconnect to ds012345.mongolab.com:12345 
Fri Jan 18 13:29:28 reconnect ds012345.mongolab.com:12345 ok 
> db.stuff.find() 
{ "_id" : ObjectId("50f9b77c27b2e67041fd2245") }

We're here to help

我们随时为您提供帮助

Of course, if you have any questions please feel free to contact us at [email protected]. We're here to help.

当然,如果您有任何疑问,请随时通过 [email protected] 与我们联系。我们是来帮忙的。

回答by Hector Correa

A couple of recommendations for people still having this issue:

给仍然有这个问题的人的一些建议:

  1. Make sure you are using the latest mongodb client for node.js. I noticed significant improvements in this area when migrating from v1.2.x to v1.3.10 (the latest as of today)

  2. You can pass an options object to the MongoClient.connect. The following options worked for me when connecting from Azure to MongoLab:

    options = { db: {}, server: { auto_reconnect: true, socketOptions: {keepAlive: 1} }, replSet: {}, mongos: {} };

    MongoClient.connect(dbUrl, options, function(err, dbConn) { // your code });

  3. See this other answer in which I describe how to handle the 'close' event which seems to be more reliable. https://stackoverflow.com/a/20690008/446681

  1. 确保您使用的是最新的 mongodb 客户端 node.js。从 v1.2.x 迁移到 v1.3.10(截至今天的最新版本)时,我注意到这方面的重大改进

  2. 您可以将选项对象传递给 MongoClient.connect。从 Azure 连接到 MongoLab 时,以下选项对我有用:

    options = { db: {}, server: { auto_reconnect: true, socketOptions: {keepAlive: 1} }, replSet: {}, mongos: {} };

    MongoClient.connect(dbUrl, options, function(err, dbConn) { // 你的代码 });

  3. 请参阅this other answer,其中我描述了如何处理似乎更可靠的“关闭”事件。https://stackoverflow.com/a/20690008/446681

回答by djebel

Increasing timeouts may help.

增加超时可能会有所帮助。

  • "socketTimeoutMS" : How long a send or receive on a socket can take before timing out.
  • "wTimeoutMS" : It controls how many milliseconds the server waits for the write concern to be satisfied.
  • "connectTimeoutMS" : How long a connection can take to be opened before timing out in milliseconds.

    $m = new MongoClient("mongodb://127.0.0.1:27017", array("connect"=>TRUE, "connectTimeoutMS"=>10, "socketTimeoutMS"=>10, "wTimeoutMS"=>10));

        $db= $m->mydb;
        $coll = $db->testData;
        $coll->insert($paramArr);
    
  • "socketTimeoutMS" :在超时之前,套接字上的发送或接收需要多长时间。
  • "wTimeoutMS" :它控制服务器等待写关注得到满足的毫秒数。
  • "connectTimeoutMS" :在以毫秒为单位超时之前打开连接需要多长时间。

    $m = new MongoClient("mongodb://127.0.0.1:27017", array("connect"=>TRUE, "connectTimeoutMS"=>10, "socketTimeoutMS"=>10, "wTimeoutMS"=>10));

        $db= $m->mydb;
        $coll = $db->testData;
        $coll->insert($paramArr);
    

回答by JohnnyHK

Enable the auto_reconnectServeroption like this:

启用这样的auto_reconnectServer选项:

var db = mongoose.connect(mongoConnect, {server: {auto_reconnect: true}});

The connection you're opening here is actually a pool of 5 connections (by default) so you're right to just connect and leave it open. My guess is that you intermittently lose connectivity with mongolab and your connections die when that occurs. Hopefully, enabling auto_reconnectresolves that.

您在此处打开的连接实际上是一个包含 5 个连接的池(默认情况下),因此您可以连接并保持打开状态。我的猜测是,您会间歇性地失去与 mongolab 的连接,并且在发生这种情况时您的连接就会中断。希望启用auto_reconnect可以解决这个问题。

回答by Mike M. Lin

I had a similar problem being disconnected from MongoDB periodically. Doing two things fixed it:

我有一个类似的问题,定期与 MongoDB 断开连接。做两件事修复了它:

  1. Make sure your computer never sleeps (that'll kill your network connection).
  2. Bypass your router/firewall (or configure it properly, which I haven't figured out how to do yet).
  1. 确保您的计算机从不休眠(这会导致您的网络连接中断)。
  2. 绕过你的路由器/防火墙(或正确配置它,我还没有想出如何去做)。