无论您多么努力,都无法放入 RAM 中的 MongoDB 和数据集

sys*_*138 12 capacity-planning mongodb

这是非常依赖于系统的,但很有可能我们会跨越某个任意的悬崖并进入真正的麻烦。我很好奇对于良好的 RAM 与磁盘空间比率存在什么样的经验法则。我们正在计划我们的下一轮系统,需要就 RAM、SSD 以及每个新节点将获得多少做出一些选择。

但是现在要了解一些性能细节!

在单个项目运行的正常工作流中,MongoDB 的写入百分比非常高(70-80%)。一旦处理管道的第二阶段命中,它的读取量就会非常高,因为它需要对处理的前半部分中识别的记录进行重复数据删除。这是“将您的工作集保存在 RAM 中”的工作流程,我们正在围绕该假设进行设计。

整个数据集不断受到来自最终用户派生源的随机查询的影响;尽管频率不规则,但大小通常很小(10 个文档为一组)。由于这是面向用户的,因此回复需要低于 3 秒的“现在无聊”阈值。这种访问模式在缓存中的可能性要小得多,因此很可能会导致磁盘命中。

二次处理工作流是对可能长达数天、数周甚至数月的先前处理运行的大量读取,并且不经常运行但仍需要快速运行。将访问上次处理运行中多达 100% 的文档。我怀疑,再多的缓存预热也无济于事。

完成的文档大小差异很大,但平均大小约为 8K。

正常项目处理的高读取部分强烈建议使用副本来帮助分配读取流量。我在别处读到1:10 RAM-GB 到 HD-GB 是慢磁盘的一个很好的经验法则,因为我们正在认真考虑使用更快的 SSD,我想知道是否有类似的规则快速磁盘的拇指。

我知道我们使用 Mongo 的方式是缓存所有东西真的不会飞,这就是为什么我正在寻找方法来设计一个可以在这种使用中幸存下来的系统。在整个数据集将可能是最结核病的半年内,并保持增长。

Ada*_*m C 13

这旨在作为此处发布的其他答案的附录,其中讨论了此处要考虑的许多相关要素。然而,当涉及到随机访问类型系统中 RAM 的高效利用时,还有另一个经常被忽视的因素——预读。

您可以通过运行blockdev --report(通常需要 sudo/root 权限)检查预读(在 Linux 上)的当前设置。这将为每个磁盘设备打印出一行。RA 列包含预读值。该值是 512 字节扇区的数量(除非扇区大小不是默认值 - 请注意,在撰写本文时,即使是更大尺寸的磁盘也被内核视为 512 字节扇区),在每个磁盘访问。

您可以通过运行以下命令为给定的磁盘设备设置预读设置:

blockdev --setra <value> <device name>
Run Code Online (Sandbox Code Playgroud)

使用基于软件的 RAID 系统时,请确保在每个磁盘设备以及与 RAID 控制器对应的设备上设置预读。

为什么这很重要?好吧,预读使用 MongoDB 试图使用的相同资源来优化您的顺序访问读取 - RAM。当您在旋转磁盘(或行为类似于旋转磁盘的设备 - EBS 我正在看着您)上进行顺序读取时,将附近的数据提取到 RAM 中可以极大地提高性能,节省您的搜索和高预读设置合适的环境可以为您带来一些令人印象深刻的结果。

对于像 MongoDB 这样的系统,您的访问通常是对数据集的随机访问,这只是浪费在其他地方更好地使用的内存。正如其他地方提到的,该系统也为 MongoDB 管理内存,将在请求时分配一块内存以进行预读,从而为 MongoDB 有效使用留出更少的 RAM。

选择正确的预读大小很棘手,取决于您的硬件、配置、块大小、条带大小和数据本身。例如,如果您确实转移到 SSD,您将需要一个低设置,但多低将取决于数据。

解释一下:您要确保预读足够高以提取完整的单个文档,而不必返回磁盘。让我们以您提到的 8k 的中位数大小为例 - 由于磁盘上的扇区通常为 512 字节,因此需要 16 次磁盘访问才能读取整个文档而无需预读。如果您有 16 个或更多扇区的预读,您只需访问一次磁盘即可阅读整个文档。

实际上,由于 MongoDB 索引桶是 8k,因此无论如何您都不会希望将预读设置为低于 16,否则将需要 2 次磁盘访问才能读取一个索引桶。一般的好做法是从您当前的设置开始,将其减半,然后重新评估您的 RAM 利用率和 IO 并从那里继续。


gWa*_*ldo 5

这将是一堆小点。遗憾的是,您的问题没有唯一的答案。

MongoDB 允许操作系统内核处理内存管理。除了在问题上投入尽可能多的内存之外,只有少数事情可以“主动管理”您的工作集。

您可以为优化写入做的一件事是首先查询该记录(进行读取),以便它在工作内存中。这将避免与进程范围的全局锁相关的性能问题(在 v2.2 中应该成为 per-db)

RAM 与 SSD 的比率没有硬性规定,但我认为 SSD 的原始 IOPS 应该允许您使用低得多的比率。在我的脑海里,1:3 可能是你想要的最低水平。但考虑到更高的成本和更低的容量,您可能无论如何都需要保持该比率较低。

关于“写入与读取阶段”,我是否正确阅读了记录写入后很少更新(“更新”)?如果是这种情况,托管两个集群可能是值得的;正常写入集群和读取优化集群,用于在[X 时间段] 内未修改的“老化”数据。我肯定会在这个集群上启用从读取。(就我个人而言,我会通过在您的数据库的对象文档中包含一个日期修改的值来管理它。)

如果你有能力在进入 Prod 之前进行负载测试,那么性能监控就可以了。MongoDB 的编写假设它经常部署在 VM 中(它们的参考系统在 EC2 中),所以不要害怕分片到 VM。