在让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的错误,还是我对replica sets功能的理解中的概念缺陷。从一些文档来看,他们似乎认为从次要数据读取基本上是一个坏主意,但这样做的原因通常是陈旧数据的问题。我的问题与过期日期没有任何关系,我无法找到一种方法来设置系统,以便我可以在不失去故障转移能力的情况下获得对辅助服务器的查询。

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

2。我的建议是使用secondaryPreferred而不是仅仅使用secondary,以便在没有辅助可用的情况下,将请求发送给主服务器。

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

  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地址重新启动连接。这导致它永远不会重新连接到与它失去联系的节点。这是可能的,我使用的主机名,应用程序可以达到它仍然会工作,但我认为这是一个最佳实践,使连接字符串和副本设置相同,以删除可能的错误的地方。

  4. 在您rs.initiate()的mongodb节点上,您可能需要更新主机名,使其成为所有盒子(其他mongodb和应用服务器可以到达)的值。默认情况下,它可能会以localhost这样的主机名结束,这在每台机器上意味着不同的东西。这可以从那个箱子里取出像这样的蒙古包壳。

的例子:

// 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
                }
        ]
}

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

当我的主服务器关闭或无法访问时,必须有另一个成员有资格成为主服务器。(我的集合中至少有2个成员的优先级>= 1)。如果我只有优先级为0的仲裁者、隐藏或成员,即使在我重新连接主服务器之后,查询也会卡住,我的客户端是无法完成写查询。读查询仍然可以工作,但是不会写。

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

最新更新