Symfony 4 在 DEV 中非常慢

Symfony 4 is painfully slow in DEV

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

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

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

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

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

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

手册中的注释:

For directories mounted with cached, the host’s view of the file system is authoritative; writes performed by containers are immediately visible to the host, but there may be a delay before writes performed on the host are visible within containers.

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

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

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

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

这是我添加到我的Docker文件中的内容:

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

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

VOLUME /symfony/var
VOLUME /symfony/vendor

这是我在通过 bin/console:

调用 composer update 或任何任务之前 添加 到我的启动脚本的内容
[ -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/[=72= 中的文件] 用于代码辅助或类似。在我的例子中,我能够拍摄这些文件的快照并将它们放入另一个文件夹中,该文件夹也与主机共享,但未被 Symfony/PSR 主动使用,例如vendor.dis/。此快照每 install/upgrade 手动拍摄一次,例如进入带有 shell 的 运行ning 容器,如下所示:

docker exec -it IDofContainer /bin/sh

然后在shell调用

cp -Lr vendor vendor.dis

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

在我使用 PhpStorm 的情况下,vendor.dis/ 由后台索引获取,并由代码检查和代码辅助遵守。 Visual Studio 代码有关于 git 的大量未跟踪更改的问题,所以我不得不明确地让 git 忽略这个快照,在 中添加它的名字。 git忽略 文件。

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

  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

The cached configuration provides all the guarantees of the delegated configuration, and some additional guarantees around the visibility of writes performed by containers. As such, cached typically improves the performance of read-heavy workloads, at the cost of some temporary inconsistency between the host and the container.

For directories mounted with cached, the host’s view of the file system is authoritative; writes performed by containers are immediately visible to the host, but there may be a delay before writes performed on the host are visible within containers.

这对 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 框中特别慢,例如使用 SQLITE 缓存:Symfony Sqlite Cache

  1. 对于 Windows 10 个用户:使用支持 WSL 2 的 Docker 桌面

使用支持 WSL 2 的 Docker 桌面,总体上可以显着提高性能:

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

容器的性能还有一个非常重要的事情。 必须检查 Dockerfile 是否包含不必要层的构建。

例如,

错误做法 -> 使用多个不必要的链接 运行

最佳实践 -> 尽可能多地使用 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 朋友!

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

您可以避免使用在 Mac 或 Windows 上非常慢的绑定装载,因为它们包含大量文件。

因此,您可以使用 Mutagen, it's almost as fast as native with Linux. A benchmark is available 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) 的完整配置,但它可以用于任何语言的任何类型的项目。

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

# 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 毫秒

唯一的缺点是你必须在 add/update 之后通过作曲家重建一些东西。但这还不算太糟糕。

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

Developing with docker under OSX/ Windows is a huge pain, since sharing your code into containers will slow down the code-execution about 60 times (depends on the solution). Testing and working with a lot of the alternatives made us pick the best of those for each platform, and combine this in one single tool: docker-sync.