MongoDB和不适合内存的数据集,无论你多么努力

这是非常依赖系统的,但是几乎可以肯定的是,我们将经过一些任意的悬崖,进入真正的麻烦。 我很好奇,对于一个好的RAM与磁盘空间的比例,存在什么样的规则。 我们正在计划下一轮的系统,并且需要对内存,SSD以及每个新节点的数量做出select。

但现在有些performance细节!

在单个项目运行的正常工作stream程中,MongoDB的写入比例非常高(70-80%)。 一旦处理pipe道的第二阶段结束,读取的数据就非常高,因为它需要对在前半部分处理中标识的logging进行重复数据删除。 这是“让你的工作集在RAM中”的工作stream程,我们正在围绕这个假设进行devise。

整个数据集不断被来自最终用户派生源的随机查询命中; 虽然频率是不规则的,但大小通常很小(10个文件组)。 由于这是面向用户的,所以回复需要在3秒钟的“无聊 – 现在”阈值之下。 这种访问模式在caching中的可能性要小得多,所以很可能会产生磁盘命中。

二次处理工作stream程是先前的处理运行的高度读取,其可以是几天,几周甚至几个月,并且很less运行,但仍然需要快速。 以前的处理运行中的文件最多可以被访问100%。 我怀疑,没有任何数量的高速caching可以帮助解决这个问题。

完成的文件大小差别很大,但中大小约为8K。

正常项目处理的高读取部分强烈build议使用副本来帮助分发读取stream量。 我已经在其他地方看到,对于慢速磁盘,1:10的RAM-GB到HD-GB是一个很好的经验法则。由于我们正在认真考虑使用速度更快的SSD,我想知道是否有类似的规则的快速磁盘的拇指。

我知道我们正在使用Mongo的方式是caching – 一切真的不会飞,所以我正在寻找方法来devise一个系统,以保持这种使用。 整个数据集可能在半年内成为结核病的大部分,并持续增长。

这将是一个小点。 然而,可悲的是你的问题没有单一的答案。

MongoDB允许OS内核处理内存pipe理。 除了在这个问题上抛出尽可能多的RAM之外,只有几件事情可以用来“积极pipe理”你的工作集。

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

内存和固态硬盘的比例并没有硬性规定,但我认为固态硬盘的原始IOPS应该可以让您以较低的比率进行比较。 在我头顶,1:3可能是你想要的最低点。 但是考虑到成本较高和产能较低,您可能需要保持这一比例。

关于“写vs读”阶段,我是否正确阅读,一旦写入logging,它很less更新(“插入”)? 如果是这样的话,可能需要主办两个集群; 正常的写入群集以及在[X时间段]内未被修改的“老化”数据的读取优化群集。 我肯定会在这个集群上启用slave-read。 (就我个人而言,我会通过在你的数据库的对象文件中包含一个date修改的值来pipe理它。)

如果你在进入产品之前有能力进行负载testing,那么就应该监视它。 假设MongoDB经常被部署在虚拟机中(他们的参考系统在EC2中),所以不要害怕分散到虚拟机。

这是作为这里发布的其他答案的附录,其中讨论了这里要考虑的许多相关内容。 然而,在随机存取types系统中有效的RAM利用 – 另一个经常被忽视的因素是readahead。

您可以通过运行blockdev --report (通常需要sudo / root权限)来检查readahead的当前设置(在Linux上)。 这将为每个磁盘设备打印一行表。 RA列包含readahead的值。 该值是512字节扇区的数量(除非扇区大小不是默认值 – 请注意,在写这篇文章的时候,甚至有更大的磁盘被内核视为512字节扇区)磁盘访问。

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

 blockdev --setra <value> <device name> 

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

为什么这很重要? 那么,readahead使用相同的资源MongoDB试图用来优化顺序访问的读取 – 内存。 当你在旋转磁盘上进行连续读取时(或者反过来说是旋转磁盘的设备 – 我正在看你的EBS)时,将附近的数据提取到RAM中可以大大提高性能,节省你的search空间,正确的环境可以给你一些令人印象深刻的结果

对于像MongoDB这样的系统来说,你的访问通常是通过数据集进行随机访问的,这只是浪费在其他地方更好使用的内存。 在其他地方提到的系统也为MongoDBpipe理内存,在请求时将会分配一大块内存,以便为MongoDB留下更less的RAM以便有效使用。

select正确的预读大小是棘手的,取决于您的硬件,configuration,块大小,条带大小和数据本身。 例如,如果您确实转向固态硬盘,您将需要较低的设置,但取决于数据有多低。

解释一下:你要确保readahead足够高,可以放入一个完整的文档,而不必返回到磁盘。 让我们把你提到的8K的中值大小 – 因为磁盘上的扇区一般是512字节,所以需要16个磁盘访问来读取整个文档,而不需要预读。 如果您有16个扇区或更多的预读,您只需读取整个文档,只需一次访问磁盘。

实际上,由于MongoDB索引桶为8k,因此无论如何您都不希望将readahead设置为16以下,或者需要2个磁盘访问才能读取一个索引桶。 一般的良好做法是从当前设置开始,将其减半,然后重新评估内存使用率和IO,然后从此处继续。

您应该考虑使用复制副本进行最终用户查询,并在其他机器上完成您的工作stream程。

使用你的1:10经验法则,你需要为1TB的磁盘存储量寻找大约128GB的RAM; 虽然目前一些价格合理的固态硬盘据称达到了超过60K的IOPS,但真实世界的数字可能会有很大差别,以及您是否在使用SSD或者RAID,如果是的话,那么RAID卡也是非常重要的。

在这个post发布的时候,从128GB的DDR3 ECC内存到256GB似乎是在1U英特尔服务器上的2000美元左右,这会给你一个1:5的数据比例,我觉得这将是一个甚至更好的比例。 如果你需要尽可能快地完成你的工作量,更多的内存肯定会有所帮助,但这真的是那么紧迫吗?

你还需要做一些文件系统的调整,例如ext4上的“noatime,data = writeback,nobarrier”,你可能还需要做一些内核设置的调整,以便挤出你的最高性能系统。

如果你要使用RAID,RAID-10将是一个不错的select,使用适当的RAID控制器将会提供相当的性能提升,但将可用空间减半。 如果您希望在不减半可用空间的情况下获得体面的性能提升,还可以查看RAID50。 运行RAID的风险是,您不再需要在驱动器上访问TRIM,这意味着您现在需要将数据移出,分解RAID,重新整理驱动器并重新创buildRAID。

最终,您需要决定您需要多less复杂性,您想要花多less钱以及您希望如何快速处理工作负载。 我还会评估MongoDB是否是理想的数据库,因为您仍然可以使用Mongo作为需要快速响应的最终用户查询,但是使用其他方式来处理您的数据,而这些数据不需要在几秒钟之内准备就绪,而且还可以让您更轻松地将工作负载分散到多台机器上。