当副本集组成发生变化时,pymongo 无法连接

pymongo fails to connect when replica set composition changes

从 mongoDB 副本集中删除主机,但不更改使用该副本集传递给 mongo_client(或 MongoReplicaSetClient)的主机字符串,似乎会在重新启动服务时中断 pymongo 连接。引发的异常是:

pymongo.errors.ServerSelectionTimeoutError: host4:27017: [Errno -2] 名称或服务未知...

问题可以提炼如下:

hosts1 = "host1, host2, host3, host4"  # where host1 and host2 are not available anymore
hosts2 = "host3, host4"  # only has valid hosts
hosts3 = ["host1", "host2", "host3", "host4"]  # expressed as a list

client = MongoClient(hosts1, 27017, replicaset="rs0")
db = client['admin']
db.authenticate('user', 'pass')

因此该脚本对于 hosts1 将失败,但适用于 host2 和 host3,即。

client = MongoClient(hosts2, 27017, replicaset="rs0")  # works

或:

client = MongoClient(hosts3, 27017, replicaset="rs0")  # works

这个问题是,这个问题在服务重新启动之前不会变得明显,这可能会在副本集成员更改后很久才发生。

它与 hosts2 一起使用的事实表明所使用的主机格式字符串是有效的。那为什么第一个重启服务就失败了呢?

答案可以在解析器的 pymongo 连接 split_hosts 过程中找到 here

解析器不会忽略间距,即使 URI 规范 (RFC2396) 指定 spaces 应该被排除并且 spaces 可以用作分隔符(第 2.3 节)。 4).在主机名中包含 spaces 会导致联网 错误。

host2 字符串起作用的原因是列表中的第一个主机仍然有效,因为它不是以 space 开头并且可以正确解析。其他两个是错误的,但是 pymongo 驱动程序只需要一个就可以找到一个正常运行的主机,这 然后它可以使用查找所有其他人。

于是,问题的答案就是把逗号后面的space去掉。

hosts1 = "host1,host2,host3,host4"

修复很简单,但是,这种情况最大的问题是直到服务重新启动后问题才变得明显,这可能 在副本集的成员更改后很长时间。