【问题标题】:Symfony 4 is painfully slow in DEVSymfony 4 在 DEV 中运行缓慢
【发布时间】:2018-07-28 13:21:22
【问题描述】:

我尝试在 docker 容器上运行一个简单的 Symfony 4 项目。 我已经测试了常规的 PHP 脚本,它们运行良好。但是,对于 Symfony 项目,执行变得非常缓慢。例如,没有任何重要内容的页面需要 5-6 秒。

我附上了 Symfony 性能分析器的屏幕截图。

您知道如何将执行时间减少到可接受的水平吗?

【问题讨论】:

  • 您的主机详细信息是什么? Docker for Mac + 文件系统同步在过去一直是一个已知的性能瓶颈。
  • 您在什么环境中运行它(即 Docker 主机是什么)? Docker 之外的相同配置的时间是什么时候?您的 Docker 配置是什么样的,尤其是您如何处理卷?
  • Windows 上的 docker 也是如此。 Windows 上的 Docker 在 VM 中运行,文件系统的挂载方式使得像 symfony 这样的文件系统繁重的应用程序非常缓慢
  • 它在 Docker for Mac 中运行。为什么我担心的是我运行(使用相同的设置)其他构建在另一个框架之上的 PHP 项目,而且速度要快得多:所有页面的运行时间都在 250 毫秒以下,包括生成大量报告的页面。

标签: php symfony docker symfony4


【解决方案1】:

似乎改变一致性级别大大提高了 Symfony 的性能。 (见Docker docs)

这是我的新 docker-compose.yml 文件。注意卷后的“:cached”。

version: '3'
services:
  web:
    image: apache-php7
    ports:
     - "80:80"
    volumes:
      - .:/app:cached
    tty: true

手册注释:

对于使用缓存挂载的目录,主机的文件视图 系统权威;容器执行的写入是 主机立即可见,但之前可能会有延迟 在主机上执行的写入在容器内是可见的。

【讨论】:

  • 谢谢,这为我节省了每个页面请求 2 秒的时间!现在可以使用了!
  • 谢谢 - 成就了我的一天!
【解决方案2】:

由于提供的答案仅适用于 macOSX,但适用于 Windows 的 Docker 也存在性能问题,并且首选答案对我的情况没有帮助。我在 SO 上对类似问题的回答中部分描述了不同的方法。

根据 Performance Best Practices Symfony 应用程序中负载较重的文件夹(例如 vendor 和 var)不应成为共享挂载的一部分。如果您需要保留这些文件夹,您应该改用卷。

为了防止干扰 /app 中的共享卷,我将这两个文件夹重新定位到容器中的单独文件夹 /symfony。在 Dockerfile 文件夹中还创建了 /symfony/var 和 /symfony/vendor。

在容器启动时运行的脚本将符号链接设置为从 /app/var 到 /symfony/var 和从 /app/vendor 到 /symfony/vendor。然后将这两个新文件夹安装到卷,例如在docker-compose.yml 文件中。

这是我添加到我的 Dockerfile 的内容:

RUN mkdir /app && mkdir /symfony/{var,vendor}

COPY setup-symfony.sh /setup-symfony.sh

VOLUME /symfony/var
VOLUME /symfony/vendor

这是我在调用composer update 或通过bin/console 执行任何任务之前添加到我的启动脚本中的内容:

[ -e /app/var ] || ln -s /symfony/var /app/var
[ -e /app/vendor ] || ln -s /symfony/vendor /app/vendor

这就是我的作文最终的样子:

version: "3.5"
services:
  database:
    build:
      context: docker/mysql
    volumes:
      - "dbdata:/var/lib/mysql"
    environment:
      MYSQL_ALLOW_EMPTY_PASSWORD: 1

  application:
    depends_on:
      - database
    build:
      context: docker/lamps
    ports:
      - "8000:8000"
    volumes:
      - ".:/app:cached"
      - "var:/symfony/var"
      - "vendor:/symfony/vendor"
    environment:
      DATABASE_URL: mysql://dbuser:dbuser@database/dbname

volumes:
  dbdata:
  var:
  vendor:

使用这种设置,Symfony 会在 500 毫秒内做出响应,而不是 4000 毫秒甚至更多。

更新:在使用 IDE 开发基于 Symfony 的应用程序(如 PhpStorm)时,您可能需要 vendor/ 中的文件来进行代码辅助或类似操作。在我的情况下,我能够拍摄这些文件的快照并将它们放入另一个文件夹中,该文件夹也与主机共享,但 Symfony/PSR 并未积极使用,例如vendor.dis/。此快照在每次安装/升级时手动拍摄一次,例如通过像这样使用 shell 进入正在运行的容器:

docker exec -it IDofContainer /bin/sh

然后在shell中调用

cp -Lr vendor vendor.dis

也许您必须修复路径名或确保先切换到包含您的应用的文件夹。

在我使用 PhpStorm 的情况下,vendor.dis/ 被后台索引拾取并通过代码检查和代码辅助来遵守。 Visual Studio 代码存在与 git 相关的大量未跟踪更改的问题,因此我必须明确地让 git 忽略此快照,并将其名称添加到 .gitignore 文件中。

2020 年更新: 更新的设置可能会在访问 /symfony/templates 或 /symfony/public 等文件夹时出现问题,例如关于预热缓存。这显然是由于上述重定位导致在/symfony/vendor 中存在的自动加载代码中使用了相对文件夹。作为一个选项,您可以直接在/app/var 和/app/vendor 中挂载额外的卷,而不是/symfony/var 和/symfony/vendor。在 /app/var.dis 和 /app/vendor.dis 中创建这些文件夹的深层副本会继续在主机文件系统中启用代码辅助和检查。

【讨论】:

    【解决方案3】:
    1. 不同步供应商文件夹

    在您的 docker 文件中,您可以阻止供应商文件夹与容器同步。这对性能的影响最大,因为文件夹变得非常大:

    #DockerFile:
    
      volumes:
        - /local/app:/var/www/html/app
        - /var/www/html/app/vendor # ignore vendor folder
    

    这将导致您需要在构建后和更新作曲家依赖项时手动将供应商文件夹复制到容器中:

    docker cp  /local/app/vendor <CONTAINER_ID>:/var/www/html/app/
    
    1. 不同步缓存文件夹

    在你的 src/Kernel.php:

    public function getCacheDir()
    {
        // for docker performance
        if ($this->getEnvironment() === 'test' || $this->getEnvironment() === 'dev') {
            return '/tmp/'.$this->environment;
        } else {
            return $this->getProjectDir().'/var/cache/'.$this->environment;
        }
    
    }
    
    1. 以缓存模式同步应用文件夹

    在开发环境中使用缓存模式安装卷:http://docs.docker.oeynet.com/docker-for-mac/osxfs-caching/#delegated

    缓存配置提供了委托的所有保证 配置,以及围绕可见性的一些额外保证 由容器执行的写入。因此,缓存通常会提高 读取繁重工作负载的性能,代价是一些临时的 主机和容器不一致。

    对于使用缓存挂载的目录,主机的文件视图 系统权威;容器执行的写入是 主机立即可见,但之前可能会有延迟 在主机上执行的写入在容器中是可见的。

    这对 dev envrionemtns 很有意义,因为通常您使用主机上的 IDE 更改代码,而不是在容器中并同步到容器中。 #Docker 文件:

      volumes:
        - /local/app:/var/www/html/app:cached
    
    1. 禁用 Docker 调试模式

    检查 Docker 是否处于调试模式:

    docker info
    # It Should display: Debug Mode: false
    

    在 docker-config 中禁用:

    {
      
      "debug": false,
    } 
    
    1. 不要使用文件缓存

    这在 docker box 中非常慢,例如使用 SQLITE 缓存:Symfony Sqlite Cache

    1. 适用于 Windows 10 用户:使用支持 WSL 2 的 Docker Desktop

    使用支持 WSL 2 的 Docker Desktop,总体上可以极大地提升性能:

    https://docs.docker.com/docker-for-windows/wsl/

    【讨论】:

      【解决方案4】:

      对于容器的性能来说,还有一件非常重要的事情。 检查 Dockerfile 是否包含不必要的层的构建非常重要。

      例如,

      Bad Practice -> 使用多个不必要的链式 RUN

      最佳实践 -> 尽可能频繁地使用 shell 中的 && 进行连接命令

      例如,例如

      我们可以写在我们的 Dockerfile 中:

      RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf
          && apt-get update &&  apt-get install -y --no-install-recommends \
              locales apt-utils git \
          \
          && echo "en_US.UTF-8 UTF-8" > /etc/locale.gen  \
          && echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen \
          &&  locale-gen \
      

      而不是:

      RUN echo "ServerName localhost" >> /etc/apache2/apache2.conf 
      RUN apt-get update &&  apt-get install -y --no-install-recommends \
          locales apt-utils git 
      
      RUN  echo "en_US.UTF-8 UTF-8" > /etc/locale.gen  \
           && echo "fr_FR.UTF-8 UTF-8" >> /etc/locale.gen 
      RUN  locale-gen
      

      更多层可以改善容器的缓慢性...检查您的服务器 Dockerfiles 朋友!

      我希望这条评论对某个地方的人有所帮助!

      【讨论】:

      • 对我的 Akeneo 4.0 安装工作就像一个魅力。
      【解决方案5】:

      当它们包含大量文件时,您可以避免使用在 Mac 或 Windows 上极其缓慢的绑定挂载。

      因此,您可以使用Mutagen 在主机和容器卷之间同步文件,这几乎与使用 Linux 的本机一样快。基准测试可用here。

      这里是 Mutagen 的基本配置:

      sync:
          defaults:
            ignore:
              vcs: true
            permissions:
              defaultFileMode: 644
              defaultDirectoryMode: 755
          codebase:
            alpha: "./app" # dir of your app
            beta: "docker://project_container_1/var/www" # targets an absolute path in the container named project_container_1
            mode: "two-way-resolved"
      

      This repository 展示了一个简单 PHP 项目 (Symfony 5) 的完整配置,但它可以用于任何语言的任何类型的项目。

      【讨论】:

        【解决方案6】:

        防止供应商目录与容器同步:

        # docker-compose.yml:
        
        volumes:
            - ./app:/var/www
            - /var/www/vendor # ignore vendor map
        

        在构建 Dockerfile 时,将供应商地图复制到容器位置:

        # Dockerfile
        
        COPY app/vendor /var/www/vendor
        
        

        Sebastian Viereck 他的回答帮助我解决了这个问题。 Symfony 5.3 上的平均加载时间从 14000 到 500 毫秒

        唯一的缺点是您必须在通过 composer 添加/更新某些内容后重新构建。但这还不是很糟糕。

        【讨论】:

          【解决方案7】:

          我建议使用docker-sync。我自己使用过它,它减少了我基于 Laravel 的应用程序的加载时间。

          在 OSX/Windows 下使用 docker 开发非常痛苦,因为将代码共享到容器中会使代码执行速度减慢大约 60 倍(取决于解决方案)。测试和使用许多替代方案使我们为每个平台选择了最好的替代方案,并将其组合到一个工具中:docker-sync。

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 2012-10-20
            • 1970-01-01
            • 2017-02-24
            • 1970-01-01
            • 2015-12-19
            • 2021-11-25
            • 2020-07-22
            相关资源
            最近更新 更多