NodeJS 中的 MongoDB 副本集连接问题

3

我的NodeJS客户端可以连接到MongoDB主服务器并按要求与之交互。

我使用以下代码构建服务器对象

var dbServer = new Server(
    host,  // primary server IP address
    port,  
    { 
        auto_reconnect: true,
        poolSize: poolSize   
    });

使用以下代码创建一个数据库对象:

var db = new Db(
    'MyDB',
    dbServer,
    { w: 1 }
);

我原本认为,在主节点宕机时,客户端会自动找到其中一个副本并选举其成为新的主节点进行通信。
但是当我手动关闭主服务器后,其中一个二级服务器确实成为了主服务器(可以从其mongo shell中观察到,并且它现在响应mongo shell命令),但客户端没有自动与其通信。如何配置NodeJS服务器以自动切换到二级服务器?
我需要在某处指定所有3个服务器地址吗?但这似乎不是一个好的解决方案,因为一旦主服务器重新上线,它的IP地址将与最初的地址不同。
我感觉自己缺少一些非常基础的东西,请给我指点。:)
谢谢, Gary
1个回答

4
您的理解已经有一部分正确,但仍存在一些问题。分配多个服务器连接的一般前提是,如果在连接时该服务器地址不可用,则会从“种子列表”中选择其他内容以建立连接。这样可以消除单点故障,例如此时“主服务器”不可用。
如果这是一个“副本集”,那么驱动程序将在连接后发现成员,然后“自动”切换到新的“主服务器”作为选定的成员。因此,这要求您的“副本集”实际上能够选举出新的“主服务器”以切换连接。此外,这并非“即时”的,因此在新的“主服务器”晋升并能够接受操作之前可能会有延迟。
您的“auto_reconnect”设置也没有按照您的想法运作。所有这些管理的只是,如果发生连接“错误”,则驱动程序将“自动”重试连接而不抛出异常。您真正想做的是自己处理这个问题,因为您可能会无限次地重试一个无法建立的连接。因此,良好的代码应该考虑到这一点,并使用一些合理的处理和日志记录来管理“重新连接”尝试。
您最后关于IP地址的观点通常是通过使用解析为IP地址的“主机名”来解决的,其中这些“主机名”从不更改,无论它们解析为什么。这对于驱动程序和“副本集”本身同样重要。因为如果服务器成员通过一个变化的IP地址寻找另一个成员,那么他们就不知道要找什么。
因此,驱动程序将“故障转移”或选择新的可用“主服务器”,但仅在服务器也可以彼此通信的相同容忍度内。您应该播种您的连接,因为在连接时您无法保证哪个节点是“主服务器”。最后,应该使用主机名而不是IP地址(如果后者有可能发生变化)。
驱动程序将进行“自我发现”,但是它只是使用副本集中可用的配置来这样做。如果该配置对于副本集无效,则对于驱动程序也无效。
示例:
MongoClient.connect("mongodb://member1,member2,member3/database", function(err,db) {

})

或者使用包含一组 Server 对象的数组。

Neil,感谢您的详细解释。我已按照您的建议进行了更改,现在当主服务器失败时,客户端会切换到备用服务器。如果您不介意,我有几个后续问题:1. 当我关闭了2个数据库服务器,只剩下一个时,客户端无法连接,您能否解释一下原因?此外,我正在AWS EC2上托管客户端服务器和Mongo服务器,所以我想我可以分配/分配一组内部IP地址,并在重新启动失败的服务器时将其分配给被关闭的服务器的IP。 - Gary Kipnis
关于auto_reconnect,既然客户端和数据库服务器都在AWS内部,我真的需要担心客户端无法连接到数据库服务器吗?我想,只有当所有复制成员死亡或AWS出现内部网络问题时才会发生这种情况。再次感谢您的反馈。 - Gary Kipnis
1
@GaryKipnis 两个问题都有点太宽泛了,但是杀死两个实例的一般情况让我相信剩下的成员不再能形成多数,因此没有“PRIMARY”了。其次,始终要考虑连接可能会消失。即使在AWS的同一地区,您也无法确定实例之间不会出现网络分区,甚至无法确定它们是否实际上驻留在同一个数据中心而没有特定的计划保证。您可能有更适合于dba.stackexchange.com关于复制的问题。 - Neil Lunn

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接