6

我有一个由三个 mongod 服务器组成的小型副本集(每个 16GB RAM,至少 4 个 CPU 内核和真正的 HDD)和一个专用仲裁器。复制的数据目前大约有 100,000,000 条记录。几乎所有这些数据都在一个带有索引的集合中_id(自动生成的 Mongo ID)和date,这是一个原生的 Mongo 日期字段。我定期使用日期索引从该集合中删除旧记录,如下所示(来自 mongo shell):

db.repo.remove({"date" : {"$lt" : new Date(1362096000000)}})

这确实有效,但运行非常非常缓慢。我的一个节点的 I/O 比其他两个节点慢,只有一个 SATA 驱动器。当此节点为主节点时,删除以大约 5-10 个文档/秒的速度运行。通过使用 rs.stepDown(),我将这个较慢的主节点降级,并强制进行选举以获得具有更好 I/O 的主节点。在该服务器上,我得到大约 100 文档/秒。

我的主要问题是,我应该担心吗?我没有引入复制之前的数字,但我知道删除速度要快得多。我想知道副本集同步是否导致 I/O 等待,或者是否有其他原因。在删除语句完成之前,我对暂时禁用同步和索引更新非常满意,但我目前不知道有什么方法可以做到这一点。出于某种原因,当我禁用三个节点中的两个,只留下一个节点和仲裁器时,剩余的节点被降级并且无法写入(仲裁器不是应该解决这个问题吗?)。

为了让您了解一般性能,如果我删除并重新创建日期索引,扫描所有 100M 文档大约需要 15 分钟。

4

2 回答 2

12

这种情况正在发生,因为即使

db.repo.remove({"date" : {"$lt" : new Date(1362096000000)}})

看起来像一个命令,它实际上在许多文档上运行——只要满足这个查询。

当您使用复制时,每个更改操作都必须写入local数据库中的一个特殊集合,简称oplog.rs为 oplog。

oplog 必须为每个删除的文档都有一个条目,并且这些条目中的每一个都需要应用于每个辅助节点上的 oplog,然后它也可以删除相同的记录。

我可以建议您考虑的一件事是TTL 索引-它们将根据您设置的到期日期/值“自动”删除文档-这样您就不会进行大规模删除,而是能够随着时间的推移更多地分散负载.

于 2013-03-10T21:04:48.727 回答
2

另一个可能不适合您的建议,但对我来说是最佳解决方案:

  1. 从集合中删除索引
  2. 遍历集合的所有条目并将记录的 id 存储到内存数组中删除
  3. 每次数组足够大(对我来说是 10K 记录),我通过 ids 删除了这些记录
  4. 重建指数

这是最快的方法,但它需要停止系统,这对我来说很合适。

于 2014-06-06T15:58:36.313 回答