Mongodb 服务器套接字在 replSet 上关闭

Nuc*_*eon 5 sockets mongodb node.js

当我们并行进行大量连接时,我们会遇到 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");
    });
});
Run Code Online (Sandbox Code Playgroud)

如果我运行该脚本,它将失败并出现以下错误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]

我无法弄清楚是什么机制导致套接字关闭。我相信等式的 Node 端挂起,因为我的事件计时显示 Node close 事件发生在 mongodb 日志中的 SocketException 之前几毫秒。我已经进入mongodbmongodb-core并做了一些console.log,该事件的发起者是at TCP.close (net.js:485:12)。这告诉我套接字本身正在关闭。基于此,确实感觉 Linux 本身正在关闭套接字或 mongoDB 主机箱,而不是 Node 或 MongoDB 正在这样做。但我不确定如何证明这一点。

这是我考虑过但已排除的第一组选项:

  1. 套接字超时 - 如果是超时,错误消息会有所不同,我通过socketTimeoutMS在构造连接时传递选项来验证这一点。如果我传递一些小东西,我会收到超时错误。

  2. MongoDB 失去连接 - 如果我使用监控 mongodb replset 上的连接,db.serverStatus().connections我仍然有大量可用连接。

  3. 当我与本地主机非副本集通信时,不会复制此行为。这可能是本地主机的事情,也可能是副本集的事情。

  4. 如果我将并行更改为 parallelLimit 100,则可以顺利完成。由于 Node 使用连接池,无论我并行发送 1000 个连接还是一次并行发送 100 个连接,它都应该向 MongoDB 提供相同的流量,因为它们都被强制进入相同的 10 个套接字。这有助于指导我这是一个节点问题。

使用节点 10、节点 12 和 MongoDB 2.6

小智 2

我在重负载下遇到了同样的问题,但是当深入研究 mongodb 驱动程序时,我发现 socketTimeout 和 connectTimeout 的默认值设置为 30000 ms。

提高它们都解决了我的问题:

mongodb://m1.url.xyz:27017,m2.url.xyz:27017/test?replicaSet=myset&connectTimeoutMS=300000&socketTimeoutMS=300000&readPreference=secondary
Run Code Online (Sandbox Code Playgroud)

(确保 ulimit 设置和 net.ipv4.tcp_keepalive_time 针对 mongodb 进行了优化) http://docs.mongodb.org/manual/faq/diagnostics/