【发布时间】:2016-01-20 01:15:43
【问题描述】:
当我们进行大量并行连接时,我们遇到了关闭 mongodb 套接字的问题。
这是一个测试脚本:
var mongodb = require("mongodb");
var async = require("async");
mongodb.MongoClient.connect("mongodb://mongo-dev1:27017/test", function(err, db) {
if (err) { throw err; }
var calls = [];
var col = db.collection("test");
var count = 10000;
for(var i = 0; i < count; i++) {
(function(i) {
calls.push(function(cb) {
console.time("update_" + i);
col.update({ i : i }, { i : i }, { upsert : true }, function(err) {
console.timeEnd("update_" + i);
cb(err);
});
});
})(i);
}
async.parallel(calls, function(err) {
if (err) { throw err; }
console.log("done");
});
});
如果我运行该脚本,它将失败并出现以下错误MongoError: server mongo-dev1:27017 sockets closed
mongodb本身的日志输出是
SocketException handling request, closing client connection: 9001 socket exception [SEND_ERROR] server [192.168.1.111:53556]
我不知道是什么机制导致套接字关闭。我相信等式的节点方面已经挂起,因为我的事件时间显示节点关闭事件发生在 mongodb 日志中的 SocketException 之前几毫秒。我已经进入mongodb 包到mongodb-core 并做了一些console.log 并且事件的发起者是at TCP.close (net.js:485:12)。这告诉我套接字本身正在关闭。基于此,感觉就像 linux 本身正在关闭套接字或 mongoDB 主机盒,而不是 Node 或 MongoDB 正在这样做。我不确定如何证明这一点。
这是我考虑过但已排除的第一组选项:
套接字超时 - 如果是超时,则错误消息不同,我在构建连接时通过传递
socketTimeoutMS选项验证了这一点。如果我传递一些小的东西,我会收到超时错误。MongoDB 连接不足 - 如果我使用
db.serverStatus().connections监控 mongodb replset 上的连接,我仍然有大量可用连接。当我与本地主机非副本集通信时,此行为不会复制。这可能是 localhost 的事情,也可能是副本集的事情。
如果我将并行更改为 100 的并行限制,则它会顺利完成。由于 Node 使用连接池,无论我是并行发送 1000 个还是一次并行发送 100 个,它应该相当于 MongoDB 的相同流量,因为它们都被强制进入相同的 10 个套接字。这有助于指导我这是一个节点问题。
使用节点 10、节点 12 和 MongoDB 2.6
【问题讨论】:
-
我偶尔会在生产中遇到同样的异常(使用 Mongo 3.0.3 副本集)。到目前为止我还没有找到解决方案。一个观察结果是,当主服务器负载过重时,这些异常更有可能发生......
-
我也有类似的观察。如果我在我们的实时服务器上执行此测试,则在我开始关闭套接字之前的阈值大约是 1000 个并行,而在我们的开发环境中约为 7000 个,没有潜在负载。
-
我希望 MongoDB 团队中的某个人能对此有所了解。我个人认为 MongoDB 在收集触发每个副本集故障转移的数据方面需要做得更好。我希望有一个简单的命令可以在 Mongo 决定故障转移时转储所有关键资源的状态。目前很难判断特定硬件资源是否存在瓶颈、网络故障或某些疯狂查询等。
-
我有一个非常相似的情况,同样的套接字关闭问题,并且无法在任何地方找到一个好的答案。希望有人能解释一下。
-
在终端中放入 db.serverStatus().connections 会得到什么?