这非常依赖于系统,但几乎可以肯定我们会越过某个悬崖并陷入真正的麻烦。我很好奇对于良好的 RAM 与磁盘空间比率存在什么样的经验法则。我们正在规划我们的下一轮系统,需要就 RAM、SSD 以及每个新节点将获得多少做出一些选择。
但现在了解一些性能细节!
在单个项目运行的正常工作流程中,MongoDB 的写入百分比非常高 (70-80%)。一旦处理管道的第二阶段命中,它的读取量就非常高,因为它需要对在处理的前半部分识别的记录进行重复数据删除。这是“将您的工作集保存在 RAM 中”的工作流程,我们正在围绕该假设进行设计。
整个数据集不断受到来自最终用户派生源的随机查询的影响;尽管频率不规则,但大小通常很小(10 个文档为一组)。由于这是面向用户的,因此回复需要低于 3 秒的“现在无聊”阈值。这种访问模式不太可能在缓存中,因此很可能会导致磁盘命中。
二次处理工作流是对可能持续数天、数周甚至数月的先前处理运行的高度读取,并且运行频率不高,但仍需要快速。将访问上一次处理运行中最多 100% 的文档。我怀疑再多的缓存预热也无济于事。
完成的文档大小差异很大,但中值大小约为 8K。
正常项目处理的高读取部分强烈建议使用 Replicas 来帮助分配读取流量。我在别处读到1:10 RAM-GB 到 HD-GB 是慢速磁盘的一个很好的经验法则,因为我们正在认真考虑使用更快的 SSD,我想知道是否有类似的规则快速磁盘的拇指。
我知道我们使用 Mongo 的方式缓存一切都不会飞起来,这就是为什么我正在寻找方法来设计一个可以在这种使用中存活下来的系统。整个数据集可能会在半年内达到一个 TB 的大部分,并不断增长。
这旨在作为此处发布的其他答案的附录,其中讨论了此处要考虑的许多相关元素。然而,在涉及随机存取类型系统中的有效 RAM 使用时,还有另一个经常被忽视的因素 - 预读。
blockdev --report
您可以通过运行(通常需要 sudo/root 权限)来检查预读(在 Linux 上)的当前设置。这将为每个磁盘设备打印出一个包含一行的表格。RA 列包含预读的值。该值是每次读取的 512 字节扇区的数量(除非扇区大小不是默认值 - 请注意,在撰写本文时,即使具有更大尺寸的磁盘也被内核视为 512 字节扇区)磁盘访问。您可以通过运行以下命令为给定的磁盘设备设置预读设置:
使用基于软件的 RAID 系统时,请确保在每个磁盘设备以及与 RAID 控制器对应的设备上设置预读。
为什么这很重要?好吧,预读使用 MongoDB 尝试使用的相同资源,以优化顺序访问的读取 - RAM。当您在旋转磁盘(或表现得像旋转磁盘的设备 - EBS 我正在看着您)上进行顺序读取时,将附近的数据提取到 RAM 中可以极大地提高性能,节省您的搜索时间,并在合适的环境可以为您带来一些令人印象深刻的结果。
对于像 MongoDB 这样的系统,您的访问通常是跨数据集的随机访问,这只是在浪费内存,而这些内存本可以用在其他地方。正如其他地方提到的,该系统也为 MongoDB 管理内存,它将在请求时分配一块内存进行预读,从而为 MongoDB 有效使用留下更少的 RAM。
选择正确的预读大小很棘手,取决于您的硬件、配置、块大小、条带大小和数据本身。例如,如果您确实移动到 SSD,您将需要一个较低的设置,但低到什么程度取决于数据。
解释一下:您要确保预读足够高以提取完整的单个文档而不必返回到磁盘。让我们采用您提到的 8k 的中值大小 - 由于磁盘上的扇区通常为 512 字节,因此需要 16 次磁盘访问才能在没有预读的情况下读取整个文档。如果您有 16 个或更多扇区的预读,则只需访问磁盘一次即可读入整个文档。
实际上,由于 MongoDB 索引桶是 8k,无论如何你都不想将预读设置为低于 16,否则将需要 2 次磁盘访问才能读取一个索引桶。一般的好做法是从您当前的设置开始,将其减半,然后重新评估您的 RAM 利用率和 IO,并从那里继续。
这将是一堆小点。但是,很遗憾,您的问题没有单一的答案。
MongoDB 允许操作系统内核处理内存管理。除了在问题上投入尽可能多的 RAM 之外,只有少数几件事可以“主动管理”您的工作集。
您可以为优化写入做的一件事是首先查询该记录(执行读取),以便它在工作内存中。这将避免与进程范围的全局锁定相关的性能问题(在 v2.2 中应该成为 per-db)
RAM 与 SSD 的比率没有硬性规定,但我认为 SSD 的原始 IOPS 应该允许您采用更低的比率。在我的脑海中,1:3 可能是你想要的最低值。但考虑到更高的成本和更低的容量,您可能无论如何都需要降低该比率。
关于“写入与读取阶段”,我是否正确地读到记录一旦写入,就很少更新(“更新”)?如果是这样的话,托管两个集群可能是值得的;正常写入集群,以及针对[X 时间段] 内未修改的“老化”数据的读取优化集群。我肯定会在这个集群上启用 slave-read。(就个人而言,我会通过在您的数据库的对象文档中包含一个日期修改值来管理它。)
如果你有能力在进入 Prod 之前进行负载测试,那么 perf monitor 就可以了。MongoDB 的编写假设它通常会部署在 VM 中(它们的参考系统在 EC2 中),所以不要害怕分片到 VM。
您应该考虑使用副本进行最终用户查询,并在其他机器上完成您的工作流程。
使用 1:10 的经验法则,您正在寻找大约 128GB 的 RAM 用于 1TB 的磁盘存储;虽然今天一些经济实惠的 SSD 声称达到 >60K IOPS,但实际数字可能会有很大差异,以及您是否在 SSD 上使用 RAID,如果是,那么 RAID 卡也非常重要.
在这篇文章发布时,在 1U 英特尔服务器上,从 128GB 的 DDR3 ECC 内存增加到 256GB 似乎要多花 2000 美元,这将为您提供 1TB 数据的 1:5 比率,我觉得这将是一个甚至更好的比例。如果您需要尽快完成工作,更多 RAM 肯定会有所帮助,但真的有那么紧迫吗?
你还需要做一些文件系统调整,比如 ext4 上的“noatime,data=writeback,nobarrier”,你可能还需要做一些内核设置调整,以最大限度地发挥你的性能系统。
如果您要使用 RAID,RAID-10 将是一个不错的选择,并且使用适当的 RAID 控制器将提供相当大的性能提升,但可用空间减半。如果您想要在不将可用空间减半的情况下获得不错的性能提升,您也可以考虑使用 RAID50。运行 RAID 的风险在于您无法再访问驱动器上的 TRIM,这意味着您时常需要将数据移出、分解 RAID、TRIM 驱动器并重新创建 RAID。
最终,您需要决定您想要的复杂程度、您想要花费的资金以及您希望以多快的速度处理您的工作负载。我还会评估 MongoDB 是否是理想的数据库,因为您仍然可以将 Mongo 用于需要快速响应的最终用户查询,但使用其他东西来处理您的数据,这不需要在几秒钟内准备好,它还可以让您更轻松地将工作负载分散到多台机器上。