无论您多么努力,MongoDB和不适合RAM的数据集


12

这是非常依赖系统的,但是几乎可以肯定的是,我们一定会越过一些任意悬崖进入“真正的麻烦”。我很好奇,存在什么样的经验法则才能获得良好的RAM与磁盘空间比率。我们正在计划下一轮系统,需要就RAM,SSD以及每个新节点获得多少进行一些选择。

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

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

来自最终用户派生来源的随机查询不断打中整个数据集;尽管频率不规则,但是尺寸通常很小(每10个文档一组)。由于这是面向用户的,因此答复必须低于3秒的“立即无聊”阈值。这种访问模式不太可能位于缓存中,因此很可能会导致磁盘命中。

辅助处理工作流程是对以前处理运行的高度了解,它可能需要几天,几周甚至几个月的时间,并且运行频率不高,但仍然需要压缩。上一次处理中最多可以访问100%的文档。我怀疑没有多少缓存预热可以帮助解决这个问题。

成品文档的大小差异很大,但中位数约为8K。

正常项目处理中的高读取部分强烈建议使用副本服务器来帮助分配读取流量。我在其他地方读过,对于慢速磁盘,从1:10 RAM-GB到HD-GB是一个很好的经验法则,由于我们正在认真考虑使用速度更快的SSD,因此我想知道是否存在类似的规则快速磁盘的经验。

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


一个很难回答的问题。
gWaldo

听起来,老实说,您可能需要解决写锁定问题,然后才能进行大量的IO调整。如果您对数据库进行写操作,则可能会保持写锁定足够长的时间,以至于无论基础IO有多快,查询都将停止。诸如Fusion IO之类的东西可以减少写锁定,但这只是花费一些时间,并不是真正的解决方案。
MrKurt

@MrKurt除了要使单个副本节点更加强大之外,我还想弄清楚部分时间是何时需要分片。我的临时规格确实包含基于PCIe的SSD卡。
sysadmin1138

知道了 您可能从一开始就考虑分片,我们会做很多单服务器分片。它使您可以绕过写锁,并有效地将写操作扩展到总内核。另外,以后可以在服务器之间移动分片很容易。
MrKurt

Answers:


5

这将是一堆小问题。可惜,您的问题没有一个答案。

MongoDB允许OS内核处理内存管理。除了在问题上投入尽可能多的RAM之外,只能做几件事来“主动管理”工作集。

您可以优化写入的一件事是首先查询该记录(进行读取),以使其位于工作内存中。这样可以避免与进程范围的全局锁定(在v2.2中应该按数据库分配)相关的性能问题。

RAM与SSD的比率没有严格的规定,但是我认为SSD的原始IOPS应该允许您以更低的比率进行操作。1:3可能是我想去的最低点。但是,鉴于成本较高和容量较低,无论如何您都可能需要降低该比率。

关于“写入与读取阶段”,我是否正确地知道,一旦写入记录,就很少更新(“更新”)?如果是这样,则值得托管两个集群。普通写入群集,以及针对[X时间段]中未修改的“老化”数据的读取优化群集。我肯定会在该群集上启用从属读取。(就我个人而言,我可以通过在数据库的对象文档中包含一个日期修改后的值来进行管理。)

如果您有能力在进入Prod之前进行负载测试,请perf监视其中的情况。MongoDB的编写假设是它通常会部署在VM中(它们的参考系统在EC2中),因此不要担心分拆到VM。


在处理期间,将创建初始文档存根,然后在处理的第一部分中通过各个子阶段对其进行连续更新。我们一直在考虑在初始创建时进行一些手工填充以减少我们正在执行的扩展量的可能性,但是我们当前的写锁定百分比很低。
sysadmin1138

在写入记录以将其放入RAM之前先读取记录的建议不是一个好建议。从2.0(2011年中期)开始,如果要访问的数据不在RAM中,MongoDB就会屈服,因此如果没有这样做,您只是在没有充分理由的情况下导致额外的读取和服务器的往返,因为锁不会无论如何都不会被拘留。
Asya Kamsky 2014年

13

这旨在作为此处发布的其他答案的附录,这些答案讨论了此处要考虑的许多相关元素。但是,在随机访问类型的系统中,要有效地利用RAM,还有另一个通常被忽略的因素-预读。

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

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

blockdev --setra <value> <device name>

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

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

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

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

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

实际上,由于MongoDB索引存储区为8k,因此您永远都不想将readahead设置为低于16,否则将需要2次磁盘访问才能在一个索引存储区中进行读取。通常的良好做法是从当前设置开始,将其减半,然后重新评估您的RAM利用率和IO,然后从那里继续。


1
一旦我们拥有一些硬件,宝贵的信息肯定会派上用场。谢谢!
sysadmin1138

3

您应该考虑使用副本进行最终用户查询,并在其他计算机上完成工作流程。

使用1:10的经验法则,您正在寻找大约128GB的RAM和1TB的磁盘存储空间。尽管当今一些负担得起的SSD声称可以达到> 60K IOPS,但实际数字可能相差很大,以及是否将RAID与SSD结合使用,如果是,则RAID卡也非常重要。

在撰写本文时,从128GB的DDR3 ECC内存到256GB似乎在1U英特尔服务器上额外增加了2000美元,这将为您提供1:5的比例和1TB的数据,我认为这是更好的比例。如果您需要尽快完成工作量,那么肯定会提供更多的RAM,但这真的很紧急吗?

您还需要进行一些文件系统调整,例如ext4上的“ noatime,data = writeback,nobarrier”之类的内容,并且可能还需要进行一些内核设置调整,以充分利用您的性能。系统。

如果您要使用RAID,则RAID-10将是一个不错的选择,并且使用适当的RAID控制器将提供相当不错的性能,但可用空间减少一半。如果您希望在不将可用空间减半的情况下获得不错的性能,也可以考虑使用RAID50。运行RAID的风险是您将无法再访问驱动器上的TRIM,这意味着您不时需要移出数据,拆分RAID,对驱动器进行TRIM并重新创建RAID。

最终,您需要确定所需的复杂性,所需的花费以及所需的工作量。我还将评估MongoDB是否是理想的数据库,因为您仍然可以将Mongo用于需要快速响应的最终用户查询,但可以使用其他方法来处理您的数据,而这无需在几秒钟内准备就绪,还可以使您更轻松地将工作负载分散到多台计算机上。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.