【发布时间】:2015-08-08 12:55:24
【问题描述】:
我正在尝试使用 WiredTiger 将大约 2.5 亿个文档插入到 MongoDB 3.0 中,每个文档大约 400 字节。我只需要搜索一个短字符串键_user_lower。虽然我现在用的是WiredTiger,比MMAPv1好很多,但我确实先用过MMAPv1,也遇到过类似的问题。
我的服务器(一个非常便宜的 VPS)有:
- 250 GB 磁盘
- 1 GB 内存
- 2 GB 交换
- 2.1 GHz 单核 CPU
我知道这台机器真的很慢,我要求它做一些有点不切实际的事情。但我很困惑它是如何从一个索引开始如此之快的,而第二个却破坏了性能:
我插入了我当时拥有的所有数据(大约 2.5 亿行)除了_id 之外没有任何索引。考虑到我糟糕的硬件,这表现得非常好:
- 大约 每秒 5000 次插入(完全可以接受)
- 在完成所需的 14 小时内,该速率几乎保持不变
- 完成后
_id上的索引大小接近 2.5GB。请注意,这是我的物理 RAM 的两倍多。 - 根据 mongostat,进程的 RES 不超过 450 MB。
- 无交换
-
top似乎表明 CPU 时间并没有全部花在等待磁盘上(因此大量时间花在了用户空间,大概是snappy代码中的 WiredTiger)
然后我在我需要查询的唯一字段_user_lower 上建立了一个(非唯一)索引。这花了 7.7 小时,这很好,因为这是一次性交易。该索引最终为 1.6 GB,与_id 索引相比,这对我来说似乎非常低。 RES 增加到大约 750 MB。
然后,我下载了要加载的新数据集。它只有 102 MB(238 K 文档)。我以同样的方式加载它,使用mongoimport,但这次:
- 仅 每秒 80 次插入(有时较慢)
- RES 保持在 750 MB 左右
-
top表示几乎 100% 的 CPU 用于等待 IO - 当然,负载会通过屋顶。
我可以理解一个相当大的性能损失,因为该索引必须更新。但我没想到这么多。我已经阅读了所有我的索引应该适合 RAM 的地方,但是在初始插入期间性能非常好,索引很快就超出了我的记忆。
我可以优化_user_index 索引吗?我不知道这甚至意味着什么,但也许只索引前几个字符?我绝对愿意将查询性能减半以换取三倍的插入性能。
是什么造成了巨大的性能损失?在没有新硬件的情况下如何解决?我并没有真正依赖 MongoDB,所以没有这些性能特征的替代品很好。我有一个想法,只使用可能会工作的平面文件,但我不想编写所有代码。
【问题讨论】:
-
_id索引是什么样的,即什么数据类型以及数据是如何分布的? -
就是这样:docs.mongodb.org/manual/reference/object-id(MongoDB 开箱即用)
-
好吧,
ObjectIds 是单调地创建的,并且不断增加。这意味着使索引保持最新非常容易,因为可以这么说,我们总是一边写一边写。当然,B-Tree 需要时不时地进行平衡,但是与将随机值(名称)插入到散布在磁盘周围且无法保存在 RAM 中的索引中相比,这应该会导致更少磁盘读取。如果主内存引用需要 100 秒 (gist.github.com/hellerbarde/2843375),单次磁盘读取大约需要 20 周时间,仅此一项就可能导致问题。 -
@mnemosyn 你可以扩展它并将其添加为答案然后我会接受吗?我实际上认为它们是故意随机帮助分片的,但我错了。
标签: performance mongodb indexing bulkinsert