在 Google Cloud Compute Engine 上,我们可以选择三种“机器系列”
- 一般用途
- 计算优化
- 内存优化
对于 MongoDB 实例来说,最佳选择是什么?
答案1
除了@John Hanley的评论外,我还发现了一篇非常有用的文章“MongoDB Sizing Guide”
动机
在使用 MongoDB 作为数据平台构建应用程序时,有时会出现这样的问题:我们应该从多大的 MongoDB 集群开始,以及当业务随时间增长时,集群大小会受到什么影响。需要多少 RAM、存储和 CPU?我们应该使用分片来扩展吗?如果是,我们需要多少分片?本文介绍如何估算 MongoDB 集群的大小。我将做几个假设,以便为我的计算提供基础。一个假设是所有索引都应该适合缓存。显然,世界不仅仅是黑白分明的,在许多情况下,我们需要调整我们的假设。对于我的估计,我将此作为起点,因为它在一定程度上保证了良好的查询性能。一旦您有更多数据/指标可用来调整集群大小,您就应该始终修改您的估计。硬件方面在确定 MongoDB 集群的大小时,我们需要考虑许多关键方面。首先是缓存。MongoDB 的性能严重依赖于缓存,因此内存是 MongoDB 最宝贵的硬件资源。任何 MongoDB 规模估算都应从内存估算开始。其次是存储。显然,存储是 MongoDB 部署的重要组成部分,因为它是我们保存数据的地方。幸运的是,与 RAM 相比,存储相对便宜。第三是 CPU,它用于 MongoDB 工作负载的许多方面。例如,如果我们在 MongoDB 中聚合数据,这会给 CPU 增加相当大的负载。所以 CPU 也很重要。最后但并非最不重要的是网络。MongoDB 是一个分布式数据库,因此大量数据需要通过网络传输。网络规模估算和监控不属于本文的一部分,因为它超出了本文的范围。一般来说,延迟差和带宽小会导致 MongoDB 性能不佳。
浆纱
根据我的经验,进行 MongoDB 大小估计的最佳方法是使用相当大的测试数据集。我们经常手头没有这样的测试数据集。在这种情况下,我通常先构建一个。我使用mgeneratejs或者mgenerate4j将虚拟数据生成到一个小的MongDB Atlas 集群MongoDB Atlas 非常方便,因为我可以快速启动 MongoDB 集群,而无需提供任何硬件和安装任何软件。通常我会生成目标数据集大小的 1-10%。然后,我会创建支持应用程序查询所需的索引。我们必须充分了解我们的应用程序将运行哪些查询以及如何使用索引支持这些查询。从生成的虚拟数据集中,我提取索引大小、存储大小和数据大小,并预测相应的目标大小。
示例:如果我有一个虚拟数据集,其大小为目标数据集大小的 1%:
目标指数规模 (TIS) = 虚拟指数规模 / 1%
目标存储大小 (TSC) = 虚拟存储大小 / 1%
目标数据集大小 (TDS) = 虚拟数据集大小 / 1%
接下来我计算我的工作集。这里我们需要对最常用的数据做出一些假设。例如,如果我们在 MongoDB 中保存了 1 年的数据,但只频繁查看过去 5 天的数据,而且可能根本不查看过去 5 天的数据,而只查看大约 40% 的子集。然后我按如下方式计算我的工作集:
每日最常使用的数据(FDD)= 5
总数据集天数 (TDSD) = 365
子集百分比(S%)= 40%
目标数据集大小 (TDS) = 100 GB
工作集 (WS) = FDD / TDSD * S% * TDS = 5 / 365 * 40% * 100 GB = 0.55 GB
然后我使用这些数字来计算我的 MongoDB 集群所需的内存、存储大小和分片数量。
内存
让我们从内存计算开始。在默认配置中,MongoDB 会从物理可用内存中保留 50% 用于WiredTiger 缓存。更准确地说,WiredTiger 缓存保留是可用内存减去 1 GB 除以 2。因此,如果我们有 64 GB 的 RAM,WiredTiger 缓存就是 31.5 GB。此行为可以更改,但在 99% 的使用情况下,此设置是正确的,不应更改。
WiredTiger 存储引擎有许多目标阈值要实现。其中一个阈值规定 WiredTiger 存储引擎将尝试将缓存保持在 80% 满的状态。一旦达到 80%,它就会开始从缓存中逐出块。这意味着实际上只有大约 40% 的可用内存用于缓存文档和索引。
为了实现良好的查询性能,我们应该允许所有索引加上工作集保留在 WiredTiger 缓存中。换句话说,良好性能所需的内存是所有索引和工作集总和的 250%。
这如何适用于分片?好吧,如果我们需要 128 GB 的 RAM,我们可以运行单个副本集每个主机/副本都有 128 GB RAM,或者我们可以运行带有两个分片的分片群集,每个分片在每个副本集主机上都有 64 GB RAM。这就引发了一个新问题:理想的分片大小和分片数量是多少?这又取决于许多因素。成本是其中之一。例如,MongoDB 企业许可证限制为 256 GB RAM。每个具有高达 256 GB RAM 的 MongoDB 实例都需要 1 个许可证。对于具有 300 GB RAM 的实例,需要 2 个许可证。因此,从许可角度来看,最佳点是每个分片具有 256 GB RAM 的倍数。但许可证成本并不是分片大小调整的唯一方面。并行性也是一个重要的考虑因素。使用更多分片,我们可以并行化磁盘 IO 和 CPU 使用率,从而扩展磁盘 IO 和 CPU 容量。这也会影响备份恢复时间,因为使用更多分片,我们可以更快地从备份中恢复。另一方面,分片越多,管理集群的复杂性就越高。组件之间的协调网络流量越多,组件发生故障的概率就越高。
总而言之,正确的分片数量取决于许多因素,而不仅仅是内存。我们需要根据具体情况考虑分片大小。为简单起见,本文末尾提供的尺寸表针对许可证成本进行了优化。
RAM 公式:
我使用的计算 MongoDB 所需 RAM 的简单公式如下:
总索引大小 (TIS) 工作集大小 (WS)
集群总内存(TCM)=(TIS + WS)* 250% + 1 GB
示例:如果我们的总索引大小为 180 GB,工作集为 20 GB。
TCM = (180 GB + 20 GB) * 250% + 1 GB = 501 GB
所需的 501 GB RAM 现在可以分配到多个大小相等的分片中。为了优化许可证成本,我们将部署 2 个分片,每个分片有 ~250GB RAM。
存储大小
存储大小估算非常简单。使用您的测试数据集作为基线,并查看您的 db-stats 存储大小。我在这里使用的公式如下:测试数据存储大小 (TDSS) 测试数据文档计数 (TSDC) 目标数据文档计数 (TADC) 缓冲区百分比 (B%) = 通常为 70%
总存储大小(TSS)= TDSS / TSDC * TADC / B%
示例:如果我的测试数据集中有 1000 万个文档,并且该数据集的总存储大小为 10 GB,而目标系统应该存储 10 亿个文档,那么它将需要约 1.4 TB 的磁盘空间。
TSS = 10 GB / 10'000'000 * 1'000'000'000 / 70% = 约 1.4 TB
注意:存储可以分布在多个分片上。作为基准,我每个分片最多使用 1 TB。因此,在这个例子中,我将部署至少 2 个分片,这显然还取决于所需的总集群内存 (TCM) 量。
为什么最大是 1 TB?好吧,我们可以再高一点。例如,MongoDB Atlas 允许每个分片最多 4 TB,但 1 TB 更容易管理,尤其是在备份恢复和初始同步。
存储 IOPS
如果我们使用 SSD,只要我们的查询被索引覆盖并且有足够的内存和 CPU,通常就不会遇到 [IOPS][8] 瓶颈。较便宜的 SSD 起步价约为 3500 IOPS。但在运行性能和压力测试时,我们仍然应该注意消耗的 IOPS。例如,如果读取 IOPS 一直很高并且接近磁盘支持的最大 IOPS,则可能是由于收集扫描或内存不足而从磁盘读取了不必要的数据。
中央处理器
不幸的是,CPU 的估算有点困难。我通常先从合理的基准开始
总集群核心数 (TCC) = TCM / 4
注意:这个公式不是我凭空想出来的,它是公式MongoDB Atlas标准集群层的用途。重要的是我们有一个合理的基准。下一步是运行性能和压力测试。确保平均 CPU 不会过高。我建议不要超过 33% 的平均 CPU 使用率。
结论
如果我们知道 MongoDB 缓存、索引和分片的工作原理,并且知道如何生成测试数据,那么 MongoDB 大小估算就没那么复杂了。我创建了一个 Google Sheet 形式的 [大小估算工具][9],可以将其用作进行 MongoDB 大小估算的起点。
值得一提的是,本文介绍了如何“估算” MongoDB 集群的“初始”大小。每个用例都略有不同,并且可能导致不同的负载模式和资源需求。正确确定 MongoDB 集群大小的唯一准确方法是反复测试、观察和改进。