无法让Mongoose重新连接节点并向辅助节点发送请求

时间:2014-05-10 02:20:47

标签: node.js mongodb mongoose

连接到副本集的mongoose的公共连接字符串如下所示

var connection = mongoose.createConnection("mongodb://db_1:27017/client_test,mongodb://db_2:27017/client_test", { 
    replSet : { rs_name : "rs0", poolSize : 5, socketOptions : { keepAlive : 1 } }
}, function(err) {
    if (err) { throw err; }
});

问题是如果两台主机中的一台出现故障,那么它将无法连接。如果您只指定一个主机,则最终没有请求被发送到辅助服务器。

这是我对该声明的证明。如果指定一个主机,并设置副本集以便有一个主节点和一个仲裁器,然后执行查询,例如

myApi.find({}).slaveOk().read("s").exec(function(err, docs) { 
    console.log(docs) 
})

它将返回结果。好吧,既然我指定了“s”(辅助),那么这个查询应该抛出一个错误,因为没有运行的辅助代码。此外,如果您将辅助邮件联机,然后执行db.currentOp(true),您将永远不会看到任何实际查询。

当您更改连接字符串以指定每个主机时,您将看到连接转到辅助节点。困境是,现在,因为您必须在连接字符串中指定其他主机,如果辅助服务器处于脱机状态,它将无法连接,我们现在已经丢失了故障转移(或整个指向副本集)

我无法确定这是否是我的配置错误,Mongoose中的错误,或者是我对副本设置功能的理解方面的概念缺陷。从一些文档中,他们似乎表示从二级读取基本上是一个坏主意,但这样做的原因通常是陈旧数据的问题。我的问题与陈旧的日期没有任何关系,我无法找到一种设置系统的方法,这样我就可以在不损失故障转移容量的情况下查询辅助设备。

3 个答案:

答案 0 :(得分:0)

1.连接字符串只定义种子服务器,mongodb驱动程序尝试连接到这些服务器并获取有关replicaSet中其他服务器的信息(通过调用rs.status())。您可以拥有5个节点的replicaSet,但在连接字符串中只指定一个,但如果连接字符串中的服务器可用,则驱动程序将能够找到其他四个节点。

2.我的提议是使用secondaryPreferred而不仅仅是secondary,以便在没有辅助可用的情况下,请求将对主要用户进行。

答案 1 :(得分:0)

好的,我相信我已经解决了所有问题。这是我学到的。

  1. 在连接字符串中指定所有可能的副本节点,否则Mongoose将永远不会在那里发送请求。 Mongoose有一个特定的格式,它与node-mongodb-native驱动程序不同。以下示例。

  2. 如果其中一个节点在启动时关闭,为了防止它永远挂起,您需要在' replset'中指定connectTimeoutMS。选项,那么它只会在初始连接上等待来自每个节点的响应。如果节点以后联机,它仍然可用。

  3. 您的mongodb副本设置中的主机名条目需要与您应用程序的连接字符串中的主机名条目匹配,并且所有主机名都需要可以从所有各方访问(mongo到mongo和应用于mongo)。在我的情况下,我将主机名从mongo别名为mongo mongo1:27017mongo2:27017mongo3:27017。我的应用程序服务器使用了带IP的连接字符串。 Mongoose试图使用mongo1:27017主机名(我的应用程序服务器无法访问)而不是我在连接字符串中指定的IP地址重新启动连接。这导致它永远不会重新连接到它失去联系的节点。如果我使用应用程序可以访问它的主机名是可能的,但是我认为最好的做法是使连接字符串和副本设置相同以删除可能出错的地方。

    < / LI>
  4. rs.initiate()可能的mongodb节点上,需要将主机名更新为所有框(其他mongodbs和应用程序服务器可以访问)的值。默认情况下,它可能会以localhost之类的主机名结尾,这意味着每台机器上都有不同的名称。这可以是从那个mongo shell那样的盒子。

  5. 示例:

    // from mongo shell
    conf = rs.conf()
    conf.members[0].host = "mongo1:27017"
    rs.reconfig(conf)
    

    在节点之间成功进行故障转移的最终功能连接字符串,包括如果查询发往某个辅助节点但没有辅助节点则抛出错误。

    var connection = mongoose.createConnection("mongodb://mongo1:27017/client_test,mongo2:27017/client_test,mongo3:27017/client_test", { 
        replset : { rs_name : "rs0", poolSize : 5, socketOptions : { keepAlive : 1, connectTimeoutMS : 1000 } },
    }, function(err) {
        if (err) { throw err; }
    });
    

    工作副本设置

    {
            "_id" : "rs0",
            "version" : 4,
            "members" : [
                    {
                            "_id" : 0,
                            "host" : "mongo1:27017"
                    },
                    {
                            "_id" : 1,
                            "host" : "mongo2:27017"
                    },
                    {
                            "_id" : 2,
                            "host" : "mongo3:27017",
                            "arbiterOnly" : true
                    }
            ]
    }
    

答案 2 :(得分:0)

在处理副本时,我遇到了类似于你的问题,在我的情况下,我有1个主节点,优先级为10,1个次要优先级为0(用于分析)和仲裁器。 重新连接主实例后,我的写入会失败,我经历了很多尝试修复它的问题,这是我学到的最重要的事情:

  

当我的主要人员失败或无法办理时,必须有另一名成员有资格成为主要成员。(我的集合中至少有2名成员必须具有优先级&gt; = 1)。    如果我只有仲裁者,隐藏者或优先级为0的成员,   即使在我重新连接我的主服务器后,查询也会卡住,我的客户端是   无法完成写入查询。读取查询仍然有效,但是   写不会。

这就是我面对的猫鼬,即使有keepalive,autoreconnect以及所有套接字和连接超时MS设置。

希望这有帮助。