mongoDB是否重新连接问题或者我做错了吗?

时间:2012-12-20 20:48:07

标签: node.js mongodb azure mongoose mlab

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

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

我的问题:如果我暂时不使用连接(我说同时,因为时间范围变化5分钟以上)似乎停滞不前。我没有解决断线事件 - 它只是挂起。

最终我收到错误回复:无法连接到[* .mongolab.com:*] - (* =屏蔽值)

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

这就是我认为这是“唤醒”问题的原因。

代码粗略概述:

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

注意事项:只有一个“连接” - 我永远不会关闭它。我再也不会重开了。

我正在使用猫鼬,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);
});

我在这里尝试过各种各样的配置,比如一直打开和关闭 - 我相信,尽管如此,普遍的共识是要做,因为我是一个开放的包装。 ??

我已经尝试过连接测试仪,它会不断检查连接的状态......即使这看起来似乎没问题 - 问题仍然存在。

从第一天起我就遇到过这个问题。我一直用MongoLab托管MongoDB。 localhost上的问题似乎更糟。但我仍然在Azure和现在的nodejit.su上有问题。

随处可见 - 它必须是我,MongoDB或mongolab。

顺便说一下,我也有过与php驱动程序相似的经历。 (虽然确认这是在nodejs上)

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

提前致谢

罗布

6 个答案:

答案 0 :(得分:28)

更新:我们针对此主题的支持文章(基本上是此帖子的副本)已移至our connection troubleshooting doc

有一个已知问题,即Azure IaaS网络强制执行大约十三分钟的空闲超时(凭经验到达)。我们正在与Azure合作,看看我们是否能够使用户更友好,但与此同时,其他人通过配置驱动程序选项来解决问题也取得了成功。

最长连接空闲时间

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

MongoDefaults.MaxConnectionIdleTime = TimeSpan.FromMinutes(1);

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

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

<强>的Keepalive

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

处理断开连接

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

首先,请务必启用自动重新连接。如何执行此操作因驱动程序而异,但当驱动程序检测到操作失败,因为连接错误时,自动重新连接会导致驱动程序尝试重新连接。

但这并不能完全解决问题。您仍然遇到如何处理触发重新连接的失败操作的问题。自动重新连接不会自动重试失败的操作。这将是危险的,特别是对于写作。因此通常会抛出异常并要求应用程序处理它。通常重试读取是很容易的。但是应该仔细考虑重试写入。

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

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

我们随时为您提供帮助

当然,如果您有任何疑问,请随时通过support@mongolab.com与我们联系。我们来帮忙。

答案 1 :(得分:18)

感谢所有帮助人员 - 我已设法在localhost上解决此问题并部署到实时服务器。

这是我现在正在使用的连接代码:

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

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

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

到目前为止一直很好 - 希望这有助于某人。

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

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

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

这个新应用程序在使用IISNode的Windows机器上运行。我最初没有看到这个重要。

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

所以我开始再次使用该选项对象,阅读相当多的内容。得出这个结论:

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

我的原始选项对象更加受到教育。 但是 - 它仍然没有用。

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

所以我把我的应用程序移到了nodejitsu。 低,看到我的联系还活着!呜!

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

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

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

答案 2 :(得分:6)

针对仍有此问题的人提出了一些建议:

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

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

    options = {   D b: {},   服务器:{     auto_reconnect:true,     socketOptions:{keepAlive:1}   },   replSet:{},   mongos:{} };

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

  3. 请参阅另一个答案,其中我将介绍如何处理似乎更可靠的'close'事件。 https://stackoverflow.com/a/20690008/446681

答案 3 :(得分:1)

启用auto_reconnect Server选项,如下所示:

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

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

答案 4 :(得分:1)

增加超时可能有所帮助。

  • “socketTimeoutMS”:套接字上的发送或接收可以使用多长时间 在超时之前。
  • “wTimeoutMS”:它控制服务器等待的毫秒数 写作关注得到满足。
  • “connectTimeoutMS”:连接可以打开多长时间 在以毫秒为单位超时之前。

      

    $ m =新的MongoClient(“mongodb://127.0.0.1:27017”,   array(“connect”=&gt; TRUE,“connectTimeoutMS”=&gt; 10,“socketTimeoutMS”=&gt; 10,   “wTimeoutMS”=大于10));

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

答案 5 :(得分:0)

我有一个类似的问题是disconnected from MongoDB periodically。做两件事就解决了这个问题:

  1. 确保您的计算机永远不会睡觉(这会扼杀您的网络连接)。
  2. 绕过你的路由器/防火墙(或正确配置它,我还没知道怎么做)。