我正在将MongoDB从3.4(使用MMAPv1存储引擎)升级到4.2(使用WiredTiger)。在这一点上,我遇到的一个阻碍因素是测试速度严重下降。
长话短说(下面有更多详细信息)-MongoDB 4.2 WiredTiger需要花费更长的时间来处理测试中重复的数据库设置/拆卸。减速幅度约为10倍。该测试过去通常运行约10分钟,而4.2则运行将近90分钟。即使仅进行了少量测试,此速度也会降低,并且似乎来自测试的设置/拆卸阶段。
关于我们的环境的几句话-我们将PHP与Doctrine ODM结合使用来与MongoDB进行通信。我们实际上有使用数据库的大约3000个测试,一些纯单元测试,一些(许多)功能。这些测试在Docker化环境中运行-我们为每个管道启动了一个新的MongoDB Docker容器,但是我已经确认即使在类似于生产的裸机环境中也会发生同样的减速。下面的实验是在裸机上进行的,以限制来自其他地方的问题。
每个功能测试首先删除数据库,然后将固定装置加载到数据库中(+创建索引),然后执行实际的测试方案。
运行一小部分测试并测量时序,我得到以下结果:
3.4:
real 0m12.478s
user 0m7.054s
sys 0m2.247s
4.2:
real 0m56.669s
user 0m7.488s
sys 0m2.334s
如您所见,测试所花费的实际CPU时间大致相同,而两者之间没有显着差异。但是,实时时间却大不相同,这意味着要等待很多时间(在这种情况下需要I / O?)。
我进一步剖析了PHP代码,从结果中可以看到,此函数花费的时间增加了9-10倍:
MongoDB\Driver\Manager::executeWriteCommand()
该函数的文档说:
此方法将应用特定于写入命令的逻辑(例如»drop)
这让我认为设置/拆卸的数量(即删除集合,创建索引)将在这里发挥作用。
对PHP进行性能分析指出MongoDB的速度下降,因此我也对此进行了介绍。我运行的测试子集导致
这些数字之间的大部分差异可以归因于以下事实:在4.2中没有文档createIndexes
(也许它们被添加到3.4后的性能分析中?我不知道)。
我过滤了分析文档,以仅显示花费至少1毫秒(> 0)的文档。曾经有:
drop
命令)drop
,715x createIndexes
,4x insert
,23x query
)如前所述,Mongo 3.4似乎没有createIndexes
在分析中报告。但是,让我们假设所有这些命令将花费与4.2一样的时间(不过,根据其余分析结果,它们可能会花费更短的时间)。
然后,所有这些drop
命令在4.2中每次操作最多花费15毫秒。在3.4中也有209个drop
命令,但是据报道几乎所有命令都持续了0毫秒。
插入和查询的数量很少,而且集合的大小只有很少的文档(每个集合少于10个,实际查询和插入的集合少于5个)。此速度下降不是由于缺少缓存或索引造成的。在这种情况下,即使进行全面扫描也很快。
我发现有关此问题的大多数讨论都是围绕为工作集设置适当的缓存大小。我在具有单核和4GB RAM,默认缓存大小(应为可用内存的50%,即2GB)的小型服务器上运行测试。对于测试可能创建的所有数据,绝对足够大。它们确实是微不足道的,并且花费在它们上的大部分时间都在建立/拆卸数据库状态上。
这是我第一次描述测试及其与数据库的交互。拖放创建与实际工作的比率可以肯定地得到改善,但是到目前为止,它已与MMAPv1和MongoDB 3.4一起使用。WiredTiger是否期望这种类型的减速?我有什么办法可以减轻这种情况?
我现在担心升级生产MongoDB实例,因为我不知道它们的行为。如果这主要与索引创建和数据库删除有关,那么我认为生产工作负载应该很好,但是我不想冒险。遗憾的是,我们是一家很小的公司,没有对生产环境进行任何性能/压力测试。
tmpfs
由于我正在Docker中运行测试,并且Docker支持tmpfs
开箱即用的卷,因此我尝试了一下。当使用支持RAM tmpfs
的MongoDB数据挂载时,我设法将测试时间减少了大约一半:
4.2:
real 0m56.669s
user 0m7.488s
sys 0m2.334s
4.2 - tmpfs:
real 0m30.951s
user 0m7.697s
sys 0m2.279s
这样做比较好,但是与在MMAPv1上运行所需的12秒相差甚远。有趣的是,tmpfs
与MMAPv1一起使用不会产生明显不同的结果。
事实证明,每次数据库清除时,我们的测试框架和夹具加载器都会为所有托管集合创建索引。这导致每个测试用例大约创建了100个索引,这就是导致速度下降的原因。我没有找到直接从蒙戈的具体证据,但似乎索引创建与WiredTiger是显著比MMAPv1慢。从测试设置代码中删除索引创建可以大大加快测试速度,使我们回到升级前的时间。
我们的绝大多数测试不需要索引,并且其创建所需的时间比提供查询的速度要长得多。我实现了一个选项,以在开发人员知道他们将需要测试用例的情况下强制创建索引。这是我们可以接受的解决方案。
将数据库的数据放入内存。在Linux上,我建议使用zram。
根据我的经验,zram的速度是raid 0中最高性能的nvme ssd(我认为是三星860 pro)的2倍,我认为它几乎快于单个消费级笔记本电脑ssd的10倍。对于旋转磁盘或通过网络访问的存储,差异应该更大。
MongoDB还有其他各种存储引擎(我相信有一个称为“临时测试”),但是它们不支持事务,因此,如果您的应用程序使用4.2(我认为甚至是4.0)功能,则需要使用WT。
在生产环境中,您很可能不会在每个请求中删除集合,因此3.x和4.2之间的实际性能差异应该较小。
本文收集自互联网,转载请注明来源。
如有侵权,请联系 [email protected] 删除。
我来说两句