php - MongoDB 功能测试设置和拆卸在 4.2 中使用 WiredTiger 慢 10 倍

标签 php mongodb doctrine doctrine-odm wiredtiger

我正在将我们的 MongoDB 从 3.4(使用 MMAPv1 存储引擎)升级到 4.2(使用 WiredTiger)。在这一点上,我遇到的一件几乎是阻碍的事情是我们的测试严重放缓。
长话短说(更多细节见下文)——MongoDB 4.2 WiredTiger 在测试中处理重复的数据库设置/拆卸需要更长的时间。 放缓幅度约为 10 倍 .测试过去运行大约 10 分钟,而 4.2 运行近 90 分钟。即使只有一小部分测试,这种减速也会重现,并且似乎来自测试的设置/拆卸阶段。

环境
关于我们的环境的几句话——我们使用 PHP 和 Doctrine ODM 来与 MongoDB 对话。我们有大约 3000 个测试,一些纯单元测试,一些(许多)功能测试,实际上使用了数据库。测试在 Dockerized 环境中运行 - 我们为每个管道启动一个新的 MongoDB Docker 容器,但是 我已经确认,即使在类似生产的裸机环境中也会发生同样的减速 .下面的实验是在裸机上完成的,以限制来自其他地方的问题。
每个功能测试首先删除数据库,然后将夹具加载到其中(+ 创建索引),然后执行实际的测试场景。
分析 PHP
运行一小部分测试并测量时间,我得到以下结果:

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()
documentation对于该功能说:

This method will apply logic that is specific to commands that write (e.g. » drop)


这让我认为设置/拆卸的数量(即删除集合、创建索引)将在这里发挥作用。
分析 MongoDB
分析 PHP 指出了 MongoDB 的放缓,所以我也分析了这一点。我运行的测试子集导致
  • 3.4 MMAPv1 的 1366 分析文档
  • 4.2 WiredTiger 的 2092 分析文档

  • 这些数字之间的大部分差异可归因于在 4.2 中没有 createIndexes 的文档这一事实。 (也许它们被添加到 3.4 后的分析中?我不知道)。
    我过滤了分析文件以仅显示那些使用 的文件。至少 1 毫秒 (>0) .有:
  • MongoDB 3.4 的 2 个此类文档(两个 drop 命令)
  • MongoDB 4.2 的 950 多个此类文档(209x 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)。对于测试可以创建的所有数据来说,这绝对足够大。它们确实是微不足道的,而且大部分时间都花在了数据库状态的设置/拆卸上。
    结论
    这是我第一次对我们的测试及其与数据库的交互进行概要分析。 drop-and-index-creation 与实际工作的比例肯定可以提高,但到目前为止它已经在 MMAPv1 和 MongoDB 3.4 上工作。 这种类型的放缓是否是 WiredTiger 所预期的?我可以做些什么来缓解这种情况?
    我现在害怕升级生产 MongoDB 实例,因为我不知道它们会如何表现。如果这主要与索引创建和数据库删除有关,那么我认为生产工作负载应该没问题,但我不想冒险。遗憾的是,我们是一家相当小的公司,没有对生产环境进行任何性能/压力测试。

    编辑
    使用 tmpfs由于我在 Docker 和 Docker supports tmpfs volumes out-of-the-box 中运行测试,我试了一下。使用 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 个索引,这就是导致速度下降的原因。我没有直接从 Mongo 找到具体的证据,但使用 WiredTiger 创建索引似乎比使用 MMAPv1 慢得多。从测试设置代码中删除索引创建显着加快了测试速度,让我们回到了升级前的时间。
    我们的绝大多数测试不需要索引,它们的创建时间比它们提供的查询加速要长得多。我实现了一个选项来强制为测试用例创建索引,开发人员知道他们需要它们。这对我们来说是一个可以接受的解决方案。

    最佳答案

    将数据库的数据放入内存中。在 Linux 上,我推荐 zram .
    根据我的经验,zram 在 raid 0 中是顶级 nvme ssd(我认为是三星 860 pro)的 2 倍,我认为是单个消费级笔记本电脑 ssd 的近 10 倍。对于旋转磁盘或通过网络访问的存储,差异应该更大。
    MongoDB 有各种其他存储引擎(我相信有一种称为“临时测试”),但它们不支持事务,因此如果您的应用程序使用 4.2(我认为甚至是 4.0)功能,则需要使用 WT。
    在生产中,您很可能不会删除每个请求的集合,因此 3.x 和 4.2 之间的实际性能差异应该更小。

    关于php - MongoDB 功能测试设置和拆卸在 4.2 中使用 WiredTiger 慢 10 倍,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/62940110/

    相关文章:

    symfony - Doctrine 2 : disable lazy loading/proxy generation.

    doctrine - 如何在 Doctrine 查询 symfony 1.4 中使用联合?

    javascript - 更改php while循环中值的颜色

    java - 如何使用 REPLICA_SET_SECONDARY 类型对 MongoDB 服务器执行写操作?

    php - 具体编号如何转换使用 imagemagick 从 .pdf 文件到 .png 图像的页面

    javascript - 通过 mongoose 更新 mongodb 内嵌套数组中的特定值

    mongodb - 如何在 pcf-dev(pivotal cloud foundry dev)中使用 postgres 或 mongodb 数据库?

    sql - 数组字段包含元素的 Doctrine

    PHP 关联数组值替换字符串变量

    php - 无法获取德语日期