一次 MongoDB 选主失败经历

MongoDB 选主机制较为复杂,需要考虑各种可能性,选举机制可参考>>。这样在某些特定情况下,则可能导致选主失败,从而使得整个集群中无主,也就无法提供写操作,进而影响到服务的可用性。本文便记录了一次在特殊场景下所导致的选主失败经历。

架构背景

MongoDB 版本为2.6,架构上采用复制集模式,一主四从,其中一从用作为跨机房数据灾备。具体如下:

{
    "_id" : "db_rs",
    "version" : 1,
    "members" : [
        {
            "_id" : 1, // 主节点
            "host" : "idc0-db0:27017",
            "priority" : 2
        },
        {
            "_id" : 2, // 从节点
            "host" : "idc0-db1:27017"
        },
        {
            "_id" : 3, // 从节点
            "host" : "idc0-db2:27017"
        },
        {
            "_id" : 4, // 从节点,灾备节点
            "host" : "idc1-db3:27017",
            "votes" : 0,
            "priority" : 0,
            "hidden" : true
        }
    ]
}

其中主节点的被选举权重为2(默认为1),目的是使得 idc0-db0:27017 能“固定”为主节点,方便管理。灾备节点无投票权、无被选举权、为隐藏节点。

问题描述

因为运维需要做了一些操作,并且触发了集群选举,触发后出现所有写操作失败,查看集群发现整个集群全为 SECONDORY,无 PRIMARY。继而查看 idc0-db0:27017 节点的 mongodb.log 日志文件,出现如下日志:

2016-12-19T10:49:41.330+0800 [rsMgr] not electing self, idc1-db0:27017 would veto with 'idc0-db0:27017 is trying to elect itself but idc0-db1:27017 is already primary and more up-to-date'
2016-12-19T10:52:16.782+0800 [rsHealthPoll] replset info idc1-db3:27017 thinks that we are down
2016-12-19T10:52:49.348+0800 [rsMgr] not electing self, idc1-db3:27017 would veto with 'I don't think idc0-db0:27017 is electable'

2016-12-19T10:52:43.604+0800 [rsMgr] not electing self, idc0-db2:27017 would veto with 'idc0-db1:27017 has lower priority than idc0-db0:27017'

原因分析

通过上述日志分析得出,灾备节点 idc1-db3:27017 能连上 idc0-db1:27017 但不能连上老的主节点 idc0-db0:27017(经排查是因为网络配置问题,限制了访问)。idc1-db3:27017 由于无法连接上 idc0-db0:27017,导致其给老的主节点投了 veto(否决票),从而使得老的主节点无法提升为主。同时 idc0-db2:27017 认为当前“主” idc0-db1:27017 的 priority 小于 idc0-db0:27017,从而使得 idc0-db1:27017 也无法成为主。结果就导致了整个集群无法选举出 PRIMARY 出来。

其中灾备节点 idc1-db3:27017 能连上 idc0-db1:27017 但不能连上老的主节点 idc0-db0:27017,经过排查是因为疏忽,在网络安全访问配置上出了问题,限制了访问,后做了修正。

解决方案

  1. 将灾备节点 idc1-db3:27017 临时 kill 掉,即解决了 idc1-db3:27017 给 idc0-db0:27017节点投否决票问题。因为 MongoDB 的选举具有在隔断时间后自动再重新进行一次选举机制。没了“否决票”问题后,自然就能正常地选举出 PRIMARY 来。
  2. 在问题解决好后先打通跨机房灾备节点 idc1-db3:27017 能连接上 idc0-db0:27017,再启动该节点的服务;
  3. 下次再操作可能触发选举的情况下,先 kill 掉备份节点(防止因为跨机房网络不稳定导致的各种问题)。

扩展

votes:0 代表阻止这些成员在选举中投主动票,但是他们仍然可以投否决票(veto)。 【Non-voting members do not vote in elections, but can veto an election and become primary】。只要一个节点被其他节点投了否决票,则它基本就没有可能性被选举成为 PRIMARY 了。

添加新评论