2013-03-10 99 views
5

我有一个小副本组三个mongod的服务器(每个16GB RAM,至少4个CPU核心和真正的硬盘驱动器)和一个专门的仲裁机构。目前复制的数据约有100,000,000条记录。几乎所有这些数据都在一个集合中,索引号为_id(自动生成的Mongo ID)和date,这是一个本地Mongo日期字段。我会定期删除这个集合使用日期索引,这样的事情(从蒙戈外壳)的旧记录:MongoDB的速度很慢删除

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

这并不工作,但它的运行速度非常,非常缓慢。其中一个节点的I/O比另外两个节点慢,只有一个SATA驱动器。当这个节点是主节点时,删除以大约5-10个文档/秒运行。通过使用rs.stepDown()我已经降级了这个较慢的主服务器,并强制选举来获得具有更好I/O的主服务器。在该服务器上,我获得大约100个文档/秒。

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

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

+0

您无法禁用四个节点中的两个的原因是,如果没有大多数可用集合,则无法创建主节点。顺便说一下,你为什么有四名成员?副本集中不需要具有三个节点的仲裁器。 – 2013-03-10 21:06:11

+0

Gotcha - 我目前只有四个节点,因为第五个节点缺少硬盘驱动器,我将它从群集中删除了:)具有讽刺意味的是,我提出了一个仲裁器来帮助保证在大选中总会有一个胜利者。无论如何,仲裁器是一个小虚拟机,我也用于其他低成本的东西,比如其他分片集群中的配置服务器。 – SteveK 2013-03-10 22:02:52

+0

当你有四个节点(有五张选票)时,你需要一个仲裁器,但是当你从副本集中删除第五个节点时,你应该删除仲裁器,这样你将剩下三个成员。 – 2013-03-10 23:06:46

回答

7

发生这种情况,因为即使

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

看起来像它的许多文件实际运行一个命令 - 多达满足这个查询。

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

的OPLOG必须为每个已删除文档的条目,需要应用到OPLOG每个二次这些条目中的每一个之前它也可以删除相同的记录。

我建议您考虑的一件事是TTL indexes - 他们将根据您设置的过期日期/值“自动”删除文档 - 这样您就不会有一次大规模删除,而是可以分散负载随着时间的推移。

+0

感谢您的解释,这很有道理。我也不知道TTL索引 - 看起来像一个很棒的功能! – SteveK 2013-03-10 21:32:25

+0

我不确定这个解决方案是否准确。在https://docs.mongodb.org/manual/core/index-ttl/上的Mongo文档中,它指出:“在副本集上,TTL后台线程仅删除主文档,但TTL后台线程运行次要成员从主要复制删除操作。“那么这是否意味着与手动操作相比,TTL的oplog性能没有差别? – Nucleon 2016-03-16 18:39:55

+0

区别在于TTL线程每分钟运行一次查找文件即可删除。在这种情况下,用户正在运行一次巨大的删除,一次删除它们。 TTL只是将删除时间延长一段时间,因此您每分钟都会执行较小的区块。假设到期时间是“准确到分钟”的字段。 – 2016-03-16 18:43:54

1

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

  1. 下降的indeces
  2. 叠代的记录,收集和存储的ID的所有条目删除到存储阵列
  3. 每次数组足够大(对我来说是10K记录),我用的ID删除这些记录
  4. 重建的indeces

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