假设您在由 3 个节点组成的网络中运行当前版本 (3.2) 的 MongoDB 作为副本集:
mongo1.local
mongo2.local
mongoarbiter.local
现在这些节点应该可以通过公共互联网访问(通过 FW 限制)。mongo1 和 mongo2 将在防火墙上获得 VIP 和一些有效的 A 记录:
mongo1.example.com
mongo2.example.com
仲裁者没有被暴露。
现在,如果您通过连接字符串传递外部 DNS 名称,某些客户端实现就可以正常工作(python)。但是其他客户端实现(Java)将无法连接,因为副本集只知道其内部名称。客户端将解析 rs 提供的节点列表,注意它所连接的外部名称不在列表中,并且会失败:
Monitor thread successfully connected to server with description ServerDescription{address=mongo1.example.com:27017, type=REPLICA_SET_PRIMARY, state=CONNECTED, ok=true, version=ServerVersion{versionList=[3, 0, 14]}, minWireVersion=0, maxWireVersion=3, maxDocumentSize=16777216, roundTripTimeNanos=5305689, setName='mongo-rs', canonicalAddress=mongo1.local:27017, hosts=[mongo2.local:27017, mongo1.local:27017], passives=[], arbiters=[mongo3.local:27017], primary='mongo1.local:27017', tagSet=TagSet{[]}, electionId=5821da77ccc118202cd2b75d, setVersion=3}
除了在客户端系统上弄乱 /etc/hosts 之外,还有其他解决方案吗?
顺便说一句:这可以解决 js 客户端库的问题,但看起来也有点脏:
replSet.connectWithNoPrimary
答案1
官方 MongoDB 驱动程序实现服务器发现和监控 (SDAM)规范,可在 GitHub 上的mongodb/specifications
存储库。SDAM 规范更详细地说明了驱动程序的预期行为和基本原理。
目前的预期是客户端将始终使用副本集配置中列出的主机名,而不是连接字符串中提供的种子列表。这样做的主要动机是根据商定的副本集配置(包括主机名和端口)启用自动故障转移和重新配置。
除了在客户端系统上弄乱 /etc/hosts 之外,还有其他解决方案吗?
如果您不需要故障转移,则可以连接到单个服务器,而不是使用副本集连接。独立/直接连接不应实现任何服务器发现。
但是,如果您要连接到独立服务器以外的任何设备,那么除了调整主机名解析以匹配副本集配置或扩展网络边界(例如使用 VPN)之外,目前没有其他解决方法。
值得点赞/关注的相关功能建议是:SERVER-1889:支持客户端和复制流量使用不同的网络/网卡. 这可以将副本集的内部网络通信与客户端连接分开。