无休止恢复中学

时间:2015-05-15 03:04:34

标签: mongodb replication

我在MongoDB 3.0.2上构建了一个包含一个主服务器,一个辅助服务器和一个仲裁服务器的复制集。主服务器和仲裁服务器位于同一主机上,辅助服务器位于另一台主机上。

随着写入过载的增加,二级不能跟随主要步骤进入恢复状态。主服务器可以连接到辅助服务器,因为我可以通过主服务器上的Mongo shell登录到辅助服务器。

我停止所有操作并使用命令rs.status()观察辅助状态,并在辅助节点上键入命令rs.syncFrom("primary's ip:port")

然后rs.status()命令的结果显示辅助的optimeDate远远落后于主要的optimeDate,并且间歇性地出现一条消息,如下所示:

"set" : "shard01", "date" : ISODate("2015-05-15T02:10:55.382Z"), "myState" : 3, "members" : [ { "_id" : 0, "name" : "xxx.xxx.xxx.xxx:xxx", "health" : 1, "state" : 1, "stateStr" : "PRIMARY", "uptime" : 135364, "optime" : Timestamp(1431655856, 6), "optimeDate" : ISODate("2015-05-15T02:10:56Z"), "lastHeartbeat" : ISODate("2015-05-15T02:10:54.306Z"), "lastHeartbeatRecv" : ISODate("2015-05-15T02:10:53.634Z"), "pingMs" : 0, "electionTime" : Timestamp(1431520398, 2), "electionDate" : ISODate("2015-05-13T12:33:18Z"), "configVersion" : 3 }, { "_id" : 1, "name" : "xxx.xxx.xxx.xxx:xxx", "health" : 1, "state" : 7, "stateStr" : "ARBITER", "uptime" : 135364, "lastHeartbeat" : ISODate("2015-05-15T02:10:53.919Z"), "lastHeartbeatRecv" : ISODate("2015-05-15T02:10:54.076Z"), "pingMs" : 0, "configVersion" : 3 }, { "_id" : 2, "name" : "xxx.xxx.xxx.xxx:xxx", "health" : 1, "state" : 3, "stateStr" : "RECOVERING", "uptime" : 135510, "optime" : Timestamp(1431602631, 134), "optimeDate" : ISODate("2015-05-14T11:23:51Z"), "infoMessage" : "could not find member to sync from", "configVersion" : 3, "self" : true } ], "ok" : 1

  

“infoMessage”:“无法找到要同步的成员”

主要和仲裁者都可以。我想知道此消息的原因以及如何将辅助状态从“恢复”更改为“辅助”。

3 个答案:

答案 0 :(得分:9)

问题(最有可能)

主要的最后一次操作来自“2015-05-15T02:10:56Z”,而次要的最后一次操作来自“2015-05-14T11:23:51Z”,这是一个大约15个小时的差异。该窗口可能会超出复制oplog窗口(oplog中第一个和最后一个操作条目的时间之间的差异)。简而言之,对于辅助设备而言,主设备上的操作太多了。

更详细一点(尽管简化):在初始同步期间,辅助同步的数据是给定时间点的数据。当同步该时间点的数据时,辅助连接到oplog并应用在所述时间点之间和现在根据oplog条目进行的更改。只要oplog在所提到的时间点之间保存所有操作,这就可以正常工作。但是oplog的大小有限(它是一个所谓的capped collection)。因此,如果在初始同步期间主要操作上发生的操作多于oplog可以保持的操作,则最旧的操作将“淡出”。二级认识到并非所有操作都可用于“构建”与主要数据相同的数据并且拒绝完成同步,并保持RECOVERY模式。

解决方案

问题是一个已知的问题,而不是一个错误,而是MongoDB内部工作的结果和开发团队做出的几个故障安全假设。因此,有几种方法可以处理这种情况。遗憾的是,由于您只有两个数据承载节点,所有都涉及停机时间。

选项1:增加oplog大小

这是我首选的方法,因为它只处理一次问题,并为所有人处理(种类)。不过,它比其他解决方案要复杂一些。从高层次的角度来看,这些是您采取的步骤。

  1. 关闭主要
  2. 使用直接访问数据文件创建oplog的备份
  3. 以独立模式重新启动mongod
  4. 将当前的oplog复制到临时集合
  5. 删除当前的oplog
  6. 使用所需大小重新创建oplog
  7. 将oplog条目从临时集合复制回闪亮的新oplog
  8. 重新启动mongod作为副本集的一部分
  9. 在进行初始同步之前,不要忘记增加辅助操作的oplog,因为它可能会在将来的某个时间成为主要内容!

    有关详细信息,请阅读"Change the size of the oplog" in the tutorials regarding replica set maintenance

    选项2:在同步期间关闭应用程序

    如果选项1不可行,唯一真正的其他解决方案是关闭应用程序,从而导致副本集上的负载,重新启动同步并等待它太完整。根据要传输的数据量,计算几个小时。

    个人笔记

    oplog窗口问题是一个众所周知的问题。虽然使用MongoDB可以轻松设置副本集和分片集群,但是需要相当多的知识和一些经验来正确维护它们。在没有了解基础的情况下,不要运行具有复杂设置的数据库这样重要的东西 - 如果发生了错误(tm),可能会导致情况FUBAR。

答案 1 :(得分:9)

另一个选项(假设主数据包含健康数据)是简单地删除辅助mongo数据文件夹中的数据并重新启动。这将使其同步回主服务器,就像您刚刚将其添加到副本集一样。

答案 2 :(得分:0)

向副本集添加第四个新节点。同步后,请重置失效的辅助服务器。