10

昨晚在将集合转换为上限集合时,我的辅助设备的运行时间开始落后于主设备。它缓慢地前进,每隔几分钟几秒钟,最终掉出主节点的 oplog 窗口。根据此处的说明,我在辅助节点上停止了 mongod,删除了所有数据文件,然后重新启动它,尽管我忘记锁定主节点的写入。Secondary 经历了它的初始化阶段,这花费了相当长的时间,最终恢复了业务,但是当我登录时,复制现在更落后了。

毕竟,这是云,我创建了我的主映像(应该复制所有数据),尽管当时我无法运行 db.fsyncLock(),因为它正在执行一些写入操作。新镜像完成,我基于该镜像启动了一个新服务器,将其添加到我的副本集中,删除旧的辅助,生活很美好,对吧?不完全是 - 新的次要落后了大约一个小时,并且在一天中(和今晚)最终到达落后 14 小时的地步(尽管奇怪的是仍然在 oplog 窗口内)。

我从“重新同步过时的会员页面”开始下一步。关闭两台服务器上的 mongod,gzip 并将我的数据文件夹从主服务器复制到辅助服务器,解压缩,将它们都启动,db.fsyncLock() 我的主服务器。让我大吃一惊的是,即使使用相同的数据,在初始化后,我的辅助设备也说它落后了 1 小时。我将它重新添加到副本集中,它很快就落后了 5 分钟。

都很好,对吧?不 - 向前闪,二级正在缓慢推进,现在落后了 20 分钟。Mongostat 的次要锁定在 95+ %,iostat -xm 2 没有显示任何疯狂的情况 - 主要当前因不进行写入而处于空闲状态,次要绝对没有做太多事情(0.04 wMB/秒)。不确定是否值得一提,但主要目前感觉狗缓慢无响应地登录到 mongo shell 等。

什么给了,蒙戈?为什么你赶不上?我在试图让我的中学赶上时做错了什么?

编辑 回答问题:

  • 版本:2.0.4
  • 硬件:两个节点都是相同的硬件,据我所知 - 8GB RAM,四核 CPU。我认为它是虚拟化的。
  • 写入率:因人而异。如前所述,昨晚我正在转换为一个有上限的系列,这引发了整个事情。一夜之间,有一个过程每小时写几次大约几百个小文档(每个约 155 字节),所以我估计最多大约 100-200kbytes/小时。白天,处理更加紧张,更新了数十万个 500 字节的文档,并写了几十万个。仍然没有谈论庞大的数据量。编辑从今天早些时候发现了一些 iostat 输出:
设备:rrqm/s wrqm/sr/sw/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中吗?

  • 工作集:我仍然没有找到公认的计算工作集的方法,但如果它有帮助:
    “收藏”:21,
    “对象”:15540092,
    “avgObjSize”:325.26198326238995,
    “数据大小”:5054601144,
    “存储大小”:5874327552,
    “数量”:132,
    “索引”:43,
    “索引大小”:864366720,
    “文件大小”:10666115072,
    “nsSizeMB”:16,
    “好”:1

我无法想象那是压倒性的 8GB RAM,尽管我可能是错的。

  • 来自中学的一些最近的 mongostat 样本:
insert query update delete getmore 命令刷新映射的 vsize res 错误锁定 % idx 未命中 % 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 启动 A,它仍然比 B 的(现在是主要的)优化时间晚了 45 秒,它在世界标准时间 02:19:52 左右一直在闲逛。终于大约一个小时后,A 赶上了,所以我在 B 上调用 rs.stepDown()。立即,rs.status() 显示两台服务器在 UTC 04:08 左右都有优化,但 B(现在是次要的)再次滞后17 秒……然后 30 秒……现在 7 分钟……

编辑

在接受@matulef 的建议并在我的上限集合上重新创建索引以及重新启动辅助节点的 mongod 进程几分钟后,它的运行时间只增加了几秒钟。来自 mongostat 的次要锁定百分比仍在 95-104% 之间徘徊,有趣的是,res 大小从 100M 大幅波动到 2GB,然后又回到了 1GB 左右。

编辑(第二天晚上)

故事的结论 - @matulef 走在正确的轨道上,我应该更加小心地将复制的集合转换为有上限的集合。接下来是发生的事情,尽管我没有宣传这是数据安全 - 我坦率地承认我可能在这个过程中丢失了一些数据,所以 YMMV。

在主节点 (A) 上为上限集合创建索引并没有传播到辅助节点 (B),并且 A 碰巧发生了故障转移(不是故意的)。一旦 B 成为主要的,我就在那里手动创建了上限集合的索引,并且使 A 与 B 保持一致的重新同步操作开始快速移动。对我来说不幸的是,我的 oplog 窗口不再排列,所以我最终不得不将数据从 B 快照到 A。一旦我用相同的数据集重新启动 mongo,A 和 B 再次高兴,并且复制已经恢复从此同步。

4

1 回答 1

6

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

解决方案是在上限集合上创建一个 _id 索引。但是,如果您在主节点上创建索引,但您的从节点已经落后,它们将无法足够快地接收索引创建操作。相反,解决问题的最佳方法是首先一个接一个地修复每个滞后的次级。对于每一个,将其关闭并以独立模式重新启动(在不同的端口上,没有 --replSet 选项),构建 _id 索引,然后将其添加回集合中。最后,一旦二级节点修复完毕,您就可以降级主节点并重复该过程。

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

于 2012-07-12T06:54:07.773 回答