29

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

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

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

最终我得到一个像错误这样的响应:无法连接到 [ * .mongolab.com: * ] - ( * = masked values)

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

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

粗略的代码大纲:

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

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

我正在使用猫鼬,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。本地主机上的问题似乎更糟。但我在 Azure 和现在的 nodejit.su 上仍然存在问题。

就像它随处发生的那样——它一定是我、MongoDB 或 mongolab。

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

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

提前致谢

4

6 回答 6

31

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

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

最大连接空闲时间

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

MongoDefaults.MaxConnectionIdleTime = TimeSpan.FromMinutes(1);

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

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

活着

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

处理断开连接

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

首先,确保启用自动重新连接。如何做到这一点因驱动程序而异,但是当驱动程序检测到由于连接错误而导致操作失败时,打开自动重新连接会告诉驱动程序尝试重新连接。

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

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

% 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 与我们联系。我们是来帮忙的。

于 2013-01-18T23:42:05.837 回答
20

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

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

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 日 注意,这是第二个具有不同设置的应用程序

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

但是设置略有不同……</p>

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

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

所以我又开始玩那个选项对象,读了很多关于它的东西。得出了这样的结论:

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

这比我声明的原始选项对象更受过教育。然而——还是不行。

现在,由于某种原因,我不得不离开那个 windows 盒子(与未在其上编译的模块有关) - 移动比再花一周时间试图让它工作更容易。

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

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

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

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

于 2013-01-19T20:21:37.613 回答
6

对于仍然遇到此问题的人的一些建议:

  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

于 2013-06-27T02:49:48.837 回答
1

启用这样的auto_reconnect Server选项:

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

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

于 2012-12-22T03:21:27.693 回答
1

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

  • "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);
    
于 2014-02-18T10:53:24.020 回答
0

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

  1. 确保您的计算机永不休眠(这会破坏您的网络连接)。
  2. 绕过您的路由器/防火墙(或正确配置它,我还没有弄清楚如何去做)。
于 2013-01-16T17:46:29.050 回答