为什么我的MongoDB副本不断落后?

时间:2012-07-11 02:47:05

标签: mongodb replication

昨晚将收藏品转换为封顶收藏品时,我的二级运动时间开始落后于初级。它慢慢地前进,每隔几分钟几秒钟,最终落在主要的oplog窗口之外。根据说明here我在辅助节点上停止了mongod,删除了所有数据文件,然后重新启动它,尽管我忘了锁定主数据库。辅助设备经历了初始化阶段,这需要花费大量时间,最终重新开始运营,但是当我登录时,复制现在甚至落后了。

因为这是云,毕竟我创建了一个我的主映像(应该复制所有数据),虽然我当时无法运行db.fsyncLock(),因为它正在服用一些写道。新图像完成,我基于该图像启动一个新的服务器,将它添加到我的副本集,删除旧的二级,生活是好的,对吧?不完全 - 新的中学落后了大约一个小时,并且在一天中(和今晚)最终达到了落后14小时的程度(尽管在oplog窗口内仍然非常奇怪)。 / p>

我从"重新定位陈旧的成员页面"开始下一步。关闭两台服务器上的mongod,gzip并将我的数据文件夹从主数据库复制到辅助服务器,解压缩,将它们都解压缩,db.fsyncLock()我的主服务器。让我感到震惊的是,即使使用相同数据,在初始化之后,我的中学也说它落后了1个小时。我将它添加回副本集中,它很快赶上了5分钟。

一切都好,对吗?不 - 闪现前锋,中学正在向前推进,现在落后20分钟。 Mongostat次要挂钩95%锁定%,iostat -xm 2并没有显示出任何疯狂的内容 - 主要是因为没有写入而空闲,次要绝对没有做多少(.04 wMB /秒)。不确定它是否值得一提,但是主要目前感觉 dog slow 没有响应登录到mongo shell等。

什么给了,Mongo?为什么你不能赶上?我试图让我的二手陷入困境我做错了什么?

修改 回答问题:

  • 版本:2.0.4
  • 硬件:两个节点都是相同的硬件,接近我所知道的 - 8GB RAM,四核CPU。我认为这是虚拟化的东西。
  • 写入率:它有所不同。如上所述,昨晚我转换为一个上限集合,触发了整个事情。一夜之间,有一个过程每小时写几百个小文件(每个大约155个字节),所以我估计大约100-200kbytes /小时。在白天,处理更加激烈,更新了数十万个500字节的文档,并写了几十万个文档。仍然没有谈论庞大的数据量。 EDIT 今天早些时候发现了一些iostat输出:
Device:         rrqm/s   wrqm/s     r/s     w/s    rkB/s    wkB/s avgrq-sz avgqu-sz   await r_await w_await  svctm  %util
xvda              1.00  2564.50  243.50  282.50  8986.00 11388.00    77.47    11.32   21.46    2.36   37.93   0.50  26.50

那个以11 wMB / s特别突破,看到util%在7 wMB / s时达到34%,在52 rMB / s时达到72%。所以没有饱和,但绝对是早上读取繁重的工作量。尽管有obj,但它很有趣。大小〜5GB,以及~1GB索引(见下文),磁盘活动如此之多。难道不应该都在RAM中吗?

  • 工作集:我仍然没有找到计算工作集的公认方法,但如果有帮助的话:
    "collections" : 21,
    "objects" : 15540092,
    "avgObjSize" : 325.26198326238995,
    "dataSize" : 5054601144,
    "storageSize" : 5874327552,
    "numExtents" : 132,
    "indexes" : 43,
    "indexSize" : 864366720,
    "fileSize" : 10666115072,
    "nsSizeMB" : 16,
    "ok" : 1

我无法想象那8块内存的压倒性优势,但我可能错了。

  • 最近一些来自中学的mongostat样本:
insert  query update delete getmore command flushes mapped  vsize    res faults locked % idx miss %     qr|qw   ar|aw  netIn netOut  conn    set repl       time 
    *0     *0     *0     *0       0     1|0       0  22.2g  44.9g   912m      0     99.2          0       0|0     0|1     2k   303b   151 mySet  SEC   03:47:54 
    *0     *0     *0     *0       0     1|0       0  22.2g  44.9g  1.85g      0      101          0       0|0     0|1     3k   303b   151 mySet  SEC   03:48:04 

修改

尝试了更多的事情。我关闭了主要(现在称为A,辅助将是B),删除了它的数据,并解压缩了它的快照(现在已经有几个小时了,但是在这一点上,我们并没有写任何新的东西)。开始使用--fastsync,它仍然比B(现在的主要)optime落后45秒,后者在02:19:52UTC大约停留。最后大约一个小时后,A赶上,所以我在B上调用rs.stepDown()。当然,rs.status()告诉我两台服务器在04:08 UTC时都有运行时间,但B(现在是次要的)再次落后17秒......然后30秒......现在7分钟......

修改

在获取@matulef建议并在我的上限集合上重新创建索引几分钟后,以及重新启动二级mongod进程,其optime仅增加了几秒钟。来自mongostat的次要锁定%仍然在95-104%之间徘徊,有趣的是,res大小从100M大幅摆动到2GB并再次回到1GB左右。

编辑(第二天晚上)

故事的结论 - @matulef走在正确的轨道上,我应该更加谨慎地将复制的集合转换为上限集合。接下来是发生了什么,虽然我不会将其宣传为数据安全 - 我自由地承认我可能在这个过程中丢失了一些数据,所以YMMV。

为主要(A)上的上限集合创建索引并没有传播到次要(B),而A恰好是故障转移(非故意)。一旦B是主要的,我手动在那里的上限集合上创建了索引,并且使A与B一致的再同步操作开始快速移动。不幸的是,我的oplog窗口不再排队,所以我最终不得不将数据从B快照到A。一旦我用相同的数据集重新启动mongo,A& B再次感到高兴,从那时起复制就一直在恢复。

1 个答案:

答案 0 :(得分:6)

这里的问题是,上限集合默认情况下没有_id索引(并且“convertToCapped”命令实际上删除了该集合的所有索引)。这是一个问题,因为辅助节点通过从oplog应用ops来执行更新,oplog通过_ids引用文档。如果缺少_id索引,则每次更新都需要对辅助索引进行全表扫描,导致它们远远落后。

解决方案是在上限集合上创建_id索引。但是,如果您在主服务器上创建索引,但是您的辅助服务器已经落后,那么它们将不会足够快地接收索引创建操作。相反,解决问题的最佳方法是首先逐个修复每个滞后的辅助设备。对于每一个,将其关闭并以独立模式重新启动(在不同的端口上,不使用--replSet选项),构建_id索引,然后将其添加回集合中。最后,一旦修复了辅助副本,您就可以降低主要部分,并使用它重复该过程。

更新:在mongoDB 2.0.x及更早版本中,默认情况下,上限集合没有_id索引。但是,默认行为计划在mongoDB 2.2中更改,因此在2.2+中创建的上限集合将自动创建_id索引,就像使用非上限集合一样。对于在2.2之前创建的上限集合,您仍然需要使用上面列出的步骤手动创建_id索引,但新集合不应受到上述问题的影响。