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

Posted

技术标签:

【中文标题】mongoDB有重新连接问题还是我做错了?【英文标题】:Does mongoDB have reconnect issues or am i doing it wrong? 【发布时间】:2012-12-08 10:46:51 【问题描述】:

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

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

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

最终我得到一个响应,例如 Error: failed to connect to [ * .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 上)

如果有人只是说“这很正常”,那就太好了

提前致谢

罗伯

【问题讨论】:

不确定 MongoDB,但在大多数(传统数据库)中,最好按需打开/关闭连接(即每次您需要访问它时)而不是让它永远打开。数据库驱动程序通常经过优化以在后台创建和管理池连接,因此这(打开/关闭)往往非常快。我也很想听听有真正 MongoDB 经验的人对这个问题的看法。 谢谢赫克托 - 是的,同意,只有我在调查时看到的所有地方都说按照我的方式去做(除非我理解不正确) 我在 MongoHQ 和 MongoLab 实例上都遇到了同样的问题——不仅来自我的 Node 应用程序,还来自 mongo 命令行客户端。 MongoHQ 支持建议我在应用程序或驱动程序级别处理此问题,方法是在发生这种情况时重试。在应用程序级别处理这个问题真是太痛苦了,我很惊讶 mongodb 驱动程序或 mongoose 还没有处理这个问题。 有人知道这个吗?我有完全相同的配置和完全相同的问题。本地主机上的情况更糟,但仍然发生在云中。您基本上可以从重新启动中获得一个会话。在这一点上,MongoLab 似乎对我来说几乎无法在 Azure 上使用 :( 也有这个问题,但在私人托管解决方案中。似乎与Mongo连接和keepAlive有关。 【参考方案1】:

像这样启用auto_reconnect Server 选项:

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

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

【讨论】:

好吧,酷。我会试一试,让你知道。我以为自动重新连接已经启用?而且我没有触发任何断开连接的事件 - 我会试一试。 不,抱歉 - MongoDB 一直在 mongoLab。但是我的代码已经在本地、Azure 和 nodejit.su 上托管——也许是 mongoLab,但如果这很常见,我不敢相信他们能够提供服务。这就是为什么我认为它一定是我。 auto_reconnect: true不是默认的吗? @UpTheCreek 不符合the docs,没有。不知道为什么。 @UpTheCreek @JohnnyHK auto_reconnect 在使用 Mongoose 时默认为 true:mongoosejs.com/docs/connections.html【参考方案2】:

disconnected from MongoDB periodically 我遇到了类似的问题。做两件事修复它:

    确保您的计算机永不休眠(这会中断您的网络连接)。 绕过您的路由器/防火墙(或正确配置它,我还没有弄清楚如何去做)。

【讨论】:

【参考方案3】:

更新:我们对此主题的支持文章(本质上是这篇文章的副本)已移至our connection troubleshooting doc。

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

最大连接空闲时间

我们在与 Azure 和我们的客户合作时发现的最有效的解决方法是将最大连接空闲时间设置为低于 4 分钟。这个想法是让驱动程序在防火墙强制问题之前回收空闲连接。例如,一位使用 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 的集合中插入一个文档,然后找到该集合中的所有文档。然后我设置了一个三十分钟的计时器,并再次尝试同样的发现。它失败了,但是 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 与我们联系。我们随时为您提供帮助。

【讨论】:

您链接到的支持文章不再可用。 很抱歉。我已经更新了帖子。不过,你没有错过任何东西。如您所见,文档本质上是这篇文章的内容,格式略有不同。 好的!谢谢!很遗憾 MaxConnectionIdleTime 选项在 PyMongo 驱动程序中不可用(还)。 @jared node.js mongodb原生驱动支持maxIdleTimeMS吗? 根据driver docs 没有 maxIdleTimeMS,但 server.socketOptions.keepAlive 可能是您正在寻找的。​​span> 【参考方案4】:

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

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

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 (@jareed) 上的 mongo 可能存在一些问题,因此我将数据库移至 AWS - 问题仍然存在。

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

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

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

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

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

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

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

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

【讨论】:

相当古怪,这就是为我做的:使用mongoose.createConnection 而不是connect 无论如何,非常感谢。 @rob_james - 您链接到的文章似乎缺少示例。你知道替代副本吗?谢谢 @UpTheCreek 对不起,我没有。 我使用了与此类似的设置,由于我的“零停机时间部署”(复制集群然后更改 DNS)我最终与 mongodb 建立了数百个连接,这完全减慢了我的生产环境。现在试图清除 SIGINT/SIGQUIT 上的连接,试图摆脱页面错误...... mongodb 连接地狱【参考方案5】:

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

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

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

    选项 = D b: , 服务器: 自动重新连接:真, 套接字选项:keepAlive:1 , 复制集:, 蒙哥: ;

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

    请参阅这个其他答案,其中我描述了如何处理似乎更可靠的“关闭”事件。 https://***.com/a/20690008/446681

【讨论】:

【参考方案6】:

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

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

【讨论】:

以上是关于mongoDB有重新连接问题还是我做错了?的主要内容,如果未能解决你的问题,请参考以下文章

Sed 不匹配反斜杠文字还是我做错了啥?

重新加载 ng-repeat 数据失败,我做错了啥?

订阅者缺少消息;这是 Rx 的错误还是我做错了?

淘汰赛验证异步验证器:这是一个错误还是我做错了啥?

Gmail API 中的 VacationSettings.endTime 转换为错误的日期 - 是错误还是我做错了啥?

是我做错了,还是在使用数组作为字段名时 CodeIgniter 表单验证库中存在错误?