2014-05-10 25 views
1

的猫鼬连接到副本集的一个常见的连接字符串是一样的东西如下麻烦猫鼬重新连接到节点和发送请求到次级

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中的错误,或者是我理解副本集函数方式的概念缺陷。从一些文档中,他们似乎认为从二手文字阅读基本上是一个坏主意,但这样做的原因通常是陈旧数据的问题。我的问题与过时的日期没有任何关系,我无法找到一种设置系统的方式,以便我可以在不损失故障切换容量的情况下查询辅助数据。

回答

0

好吧,我相信我解决了我所有的问题。这是我学到的东西。

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

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

  3. 在MongoDB的副本设置的主机名条目需要从你的应用程序和匹配连接字符串中的主机名条目所有主机名必须是可访问的各方(蒙戈以蒙戈和应用,以蒙戈)。在我的情况下,我已经将mongo的主机名别名为mongo,分别为mongo1:27017,mongo2:27017mongo3:27017。我的应用程序服务器使用连接字符串与IP。 Mongoose试图使用主机名(我的应用服务器无法访问)而不是我在连接字符串中指定的IP地址重新启动连接。这导致它不会重新连接到它失去联系的节点。我有可能使用了应用程序可以达到的主机名,但它仍然可以工作,但我认为最好的做法是使连接字符串和副本设置完全相同,以便删除可能发生错误的位置。

  4. 在你rs.initiate()可能需要更新的主机名是所有箱子(其他mongodbs和应用服务器可以达到)值MongoDB的节点。默认情况下,它最终可能会有一个主机名,如localhost,这意味着每台机器上都有不同的东西。这可以从mongo shell那样的盒子中得到。

实施例:它成功地故障转移节点,包括如果查询注定用于二次但目前还没有次级引发错误之间

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

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

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

+0

这是有道理的,除非我指定一个种子服务器,请求不会最终转到辅助(不管我是否使用'sp'或's')。 “次要”的用法是为了证明这一点,因为没有第二次就会失败。 – Nucleon

0

我不得不与你类似的一些问题,在处理副本,在我来说,我有1个主节点为10的优先级,0 1个次要地位(对分析)和仲裁者。 我写将重新连接主实例失败后,我经历了很多尝试修复,这是我学到的最重要的事情:

当我的主服务器停机或unreacheable,必须有资格另一名成员成为主要成员(我的集体中至少有2名成员的优先级大于等于1)。 如果我只有仲裁者,隐藏或优先级为0的成员,则 即使在我重新连接主服务器后,查询也会卡住,但我的客户端无法完成写查询,因此我的客户端为 。阅读查询仍然有效,但 写不会。

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

希望这会有所帮助。

+0

deb2fast - 你是如何解决这个问题的? – user3658423

+0

@ user3658423我在上面发布了我的答案,你是否面临类似的问题?你可以发布一个链接到你的问题,我会检查出来。 – deb2fast