From 6ecf5584f9bea6adebadf8f1fb5dd590c31b1c39 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 29 Jan 2018 12:40:30 +0100 Subject: [PATCH 1/4] Updated the main performance article to make it more actionable --- performance.rst | 289 ++++++++++++++++++++++++------------------------ 1 file changed, 143 insertions(+), 146 deletions(-) diff --git a/performance.rst b/performance.rst index 22b918c1852..635e08be903 100644 --- a/performance.rst +++ b/performance.rst @@ -1,205 +1,205 @@ .. index:: - single: Tests + single: Performance; Byte code cache; OPcache; APC Performance =========== -Symfony is fast, right out of the box. Of course, if you really need speed, -there are many ways that you can make Symfony even faster. In this article, -you'll explore some of the ways to make your Symfony application even faster. +Symfony is fast, right out of the box. However, you can make it faster if you +optimize your servers and your applications as explained in the following +performance checklists. -.. index:: - single: Performance; Byte code cache +Symfony Application Checklist +----------------------------- + +#. :ref:`Install APCu Polyfill if your server uses APC ` +#. :ref:`Enable APC Caching for the Autoloader ` +#. :ref:`Use Bootstrap Files ` + +Production Server Checklist +--------------------------- + +#. :ref:`Use the OPcache byte code cache ` +#. :ref:`Configure OPcache for maximum performance ` +#. :ref:`Don't check PHP files timestamps ` +#. :ref:`Configure the PHP realpath Cache ` +#. :ref:`Optimize Composer Autoloader ` + +.. _performance-install-apcu-polyfill: -Use a Byte Code Cache (e.g. OPcache) ------------------------------------- +Install APCu Polyfill if your Server Uses APC +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -The first thing that you should do to improve your performance is to use a -"byte code cache". These caches store the compiled PHP files to avoid having -to recompile them for every request. +If your production server still uses the legacy APC PHP extension instead of +OPcache, install the `APCu Polyfill component`_ in your application to enable +compatibility with `APCu PHP functions`_ and unlock support for advanced Symfony +features, such as the APCu Cache adapter. -There are a number of `byte code caches`_ available, some of which are open -source. As of PHP 5.5, PHP comes with `OPcache`_ built-in. For older versions, -the most widely used byte code cache is `APC`_. +.. _performance-autoloader-apc-cache: -.. tip:: +Enable APC Caching for the Autoloader +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - If your server still uses the legacy APC PHP extension, install the - `APCu Polyfill component`_ in your application to enable compatibility with - `APCu PHP functions`_ and unlock support for advanced Symfony features, such - as the APCu Cache adapter. +The class autoloading mechanism is one of the slowest parts in PHP applications +that make use of lots of classes, such as Symfony. A simple way to improve its +performance is to use the :class:`Symfony\\Component\\ClassLoader\\ApcClassLoader`, +which caches the location of each class after it's located the first time. -Using a byte code cache really has no downside, and Symfony has been designed -to perform really well in this type of environment. +To use it, adapt your front controller file like this:: -Monitoring Source File Changes -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + // app.php + // ... -Most byte code caches monitor the source files for changes. This ensures that if -the source of a file changes, the byte code is recompiled automatically. -This is really convenient, but it adds overhead. + $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; -For this reason, some byte code caches offer an option to disable these checks. -For example, to disable these checks in APC, simply add ``apc.stat=0`` to your -``php.ini`` configuration. + // Change 'sf' by something unique to this app to prevent + // conflicts with other applications running in the same server + $loader = new ApcClassLoader('sf', $loader); + $loader->register(true); -When disabling these checks, it will be up to the server administrators to -ensure that the cache is cleared whenever any source files change. Otherwise, -the updates you've made in the application won't be seen. + // ... -For the same reasons, the byte code cache must also be cleared when deploying -the application (for example by calling ``apc_clear_cache()`` PHP function when -using APC and ``opcache_reset()`` when using OPcache). +For more details, see :doc:`/components/class_loader/cache_class_loader`. .. note:: - In PHP, the CLI and the web processes don't share the same OPcache. This - means that you cannot clear the web server OPcache by executing some command - in your terminal. These are some of the possible solutions: + When using the APC autoloader, if you add new classes, they will be found + automatically and everything will work the same as before (i.e. no + reason to "clear" the cache). However, if you change the location of a + particular namespace or prefix, you'll need to flush your APC cache. Otherwise, + the autoloader will still be looking at the old location for all classes + inside that namespace. - #. Restart the web server; - #. Call the :phpfunction:`apc_clear_cache` or :phpfunction:`opcache_reset` - functions via the web server (i.e. by having these in a script that - you execute over the web); - #. Use the `cachetool`_ utility to control APC and OPcache from the CLI. +.. _performance-use-bootstrap-files: -Optimizing all the Files Used by Symfony -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Use Bootstrap Files +~~~~~~~~~~~~~~~~~~~ -By default, PHP's OPcache saves up to 2,000 files in the byte code cache. This -number is too low for the typical Symfony application, so you should set a -higher limit with the `opcache.max_accelerated_files`_ configuration option: +The Symfony Standard Edition includes a script to generate a so-called +`bootstrap file`_, which is a large file containing the code of the most +commonly used classes. This saves a lot of IO operations because Symfony no +longer needs to look for and read those files. -.. code-block:: ini +If you're using the Symfony Standard Edition, then you're probably already +using the bootstrap file. To be sure, open your front controller (usually +``app.php``) and check to make sure that the following line exists:: - ; php.ini - opcache.max_accelerated_files = 20000 + require_once __DIR__.'/../app/bootstrap.php.cache'; -Configure the PHP realpath Cache --------------------------------- +Note that there are two disadvantages when using a bootstrap file: -PHP uses an internal cache to store the result of mapping file paths to their -real and absolute file system paths. This increases the performance for -applications like Symfony that open many PHP files, especially on Windows -systems. +* the file needs to be regenerated whenever any of the original sources change + (i.e. when you update the Symfony source or vendor libraries); -Consider increasing the ``realpath_cache_size`` and ``realpath_cache_ttl``: +* when debugging, one will need to place break points inside the bootstrap file. -.. code-block:: ini +If you're using the Symfony Standard Edition, the bootstrap file is automatically +rebuilt after updating the vendor libraries via the ``composer install`` command. - ; php.ini - ; 4096k is the default value in PHP 7.2 - realpath_cache_size=4096K - realpath_cache_ttl=600 +.. note:: -.. index:: - single: Performance; Autoloader + Even when using a byte code cache, performance will improve when using a + bootstrap file since there will be fewer files to monitor for changes. Of + course, if this feature is disabled in the byte code cache (e.g. + ``apc.stat=0`` in APC), there is no longer a reason to use a bootstrap file. -Use Composer's Class Map Functionality --------------------------------------- +.. _performance-use-opcache: -By default, the Symfony Standard Edition uses Composer's autoloader -in the `autoload.php`_ file. This autoloader is easy to use, as it will -automatically find any new classes that you've placed in the registered -directories. +Use the OPcache Byte Code Cache +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -Unfortunately, this comes at a cost, as the loader iterates over all configured -namespaces to find a particular file, making ``file_exists()`` calls until it -finally finds the file it's looking for. +OPcache stores the compiled PHP files to avoid having to recompile them for +every request. There are some `byte code caches`_ available, but as of PHP +5.5, PHP comes with `OPcache`_ built-in. For older versions, the most widely +used byte code cache is `APC`_. -The simplest solution is to tell Composer to build an optimized "class map", -which is a big array of the locations of all the classes and it's stored -in ``vendor/composer/autoload_classmap.php``. +.. _performance-configure-opcache: -The class map can be generated from the command line, and might become part of -your deploy process: +Configure OPcache for Maximum Performance +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -.. code-block:: bash +The default OPcache configuration is not suited for Symfony applications, so +it's recommended to change these settings as follows: - $ composer dump-autoload --optimize --no-dev --classmap-authoritative +.. code-block:: ini -``--optimize`` - Dumps every PSR-0 and PSR-4 compatible class used in your application. -``--no-dev`` - Excludes the classes that are only needed in the development environment - (e.g. tests). -``--classmap-authoritative`` - Prevents Composer from scanning the file system for classes that are not - found in the class map. + ; php.ini + ; maximum memory that OPcache can use to store compiled PHP files + opcache.memory_consumption=256M -Caching the Autoloader with APC -------------------------------- + ; maximum number of files that can be stored in the cache + opcache.max_accelerated_files=20000 -Another solution is to cache the location of each class after it's located -the first time. Symfony comes with a class - :class:`Symfony\\Component\\ClassLoader\\ApcClassLoader` - -that does exactly this. To use it, just adapt your front controller file. -If you're using the Standard Distribution, this code should already be available -as comments in this file:: +.. _performance-dont-check-timestamps: - // app.php - // ... +Don't Check PHP Files Timestamps +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ - $loader = require_once __DIR__.'/../app/bootstrap.php.cache'; +In production servers, PHP files should never change, unless a new application +version is deployed. However, by default OPcache checks if cached files have +changed their contents since they were cached. This check introduces some +overhead that can be avoided as follows: - // Use APC for autoloading to improve performance - // Change 'sf2' by the prefix you want in order - // to prevent key conflict with another application - /* - $loader = new ApcClassLoader('sf2', $loader); - $loader->register(true); - */ +.. code-block:: ini - // ... + ; php.ini -For more details, see :doc:`/components/class_loader/cache_class_loader`. + ; after each deploy, call `opcache_reset()` or restart the web server + ; to empty the cache and regenerate the cached files. Otherwise you won't + ; see the updates made in the application + opcache.validate_timestamps=0 .. note:: - When using the APC autoloader, if you add new classes, they will be found - automatically and everything will work the same as before (i.e. no - reason to "clear" the cache). However, if you change the location of a - particular namespace or prefix, you'll need to flush your APC cache. Otherwise, - the autoloader will still be looking at the old location for all classes - inside that namespace. + The OPcache is different for the web server and the command console. + You cannot clear the web server OPcache by executing some command + in your terminal. You either need to restart the web server or call the + ``opcache_reset()`` function via the web server (i.e. by having this in + a script that you execute over the web). -.. index:: - single: Performance; Bootstrap files +.. _performance-configure-realpath-cache: -Use Bootstrap Files -------------------- +Configure the PHP realpath Cache +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -To ensure optimal flexibility and code reuse, Symfony applications leverage -a variety of classes and 3rd party components. But loading all of these classes -from separate files on each request can result in some overhead. To reduce -this overhead, the Symfony Standard Edition provides a script to generate -a so-called `bootstrap file`_, consisting of multiple classes definitions -in a single file. By including this file (which contains a copy of many of -the core classes), Symfony no longer needs to include any of the source files -containing those classes. This will reduce disc IO quite a bit. +When a relative path is transformed into its real and absolute path, PHP +caches the result to improve performance. The default config of this cache +is not suited for applications that open many PHP files, such as Symfony. +It's recommended to change these settings as follows: -If you're using the Symfony Standard Edition, then you're probably already -using the bootstrap file. To be sure, open your front controller (usually -``app.php``) and check to make sure that the following line exists:: +.. code-block:: ini - require_once __DIR__.'/../app/bootstrap.php.cache'; + ; php.ini + ; maximum memory allocated to store the results + realpath_cache_size=4096K -Note that there are two disadvantages when using a bootstrap file: + ; save the results for 10 minutes (600 seconds) + realpath_cache_ttl=600 -* the file needs to be regenerated whenever any of the original sources change - (i.e. when you update the Symfony source or vendor libraries); +.. _performance-optimize-composer-autoloader: -* when debugging, one will need to place break points inside the bootstrap file. +Optimize Composer Autoloader +~~~~~~~~~~~~~~~~~~~~~~~~~~~~ -If you're using the Symfony Standard Edition, the bootstrap file is automatically -rebuilt after updating the vendor libraries via the ``composer install`` command. +The class loader used while developing the application is optimized to find +new and changed classes. In production servers, PHP files should never change, +unless a new application version is deployed. That's why you can optimize +Composer's autoloader to scan the entire application once and build a "class map", +which is a big array of the locations of all the classes and it's stored +in ``vendor/composer/autoload_classmap.php``. + +Execute this command to generate the class map (and make it part of your +deployment process too): -Bootstrap Files and Byte Code Caches -~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +.. code-block:: bash + + $ composer dump-autoload --optimize --no-dev --classmap-authoritative -Even when using a byte code cache, performance will improve when using a bootstrap -file since there will be fewer files to monitor for changes. Of course, if this -feature is disabled in the byte code cache (e.g. ``apc.stat=0`` in APC), there -is no longer a reason to use a bootstrap file. +* ``--optimize`` dumps every PSR-0 and PSR-4 compatible class used in your + application; +* ``--no-dev`` excludes the classes that are only needed in the development + environment (e.g. tests); +* ``--classmap-authoritative`` prevents Composer from scanning the file + system for classes that are not found in the class map. Learn more ---------- @@ -209,10 +209,7 @@ Learn more .. _`byte code caches`: https://en.wikipedia.org/wiki/List_of_PHP_accelerators .. _`OPcache`: http://php.net/manual/en/book.opcache.php -.. _`opcache.max_accelerated_files`: http://php.net/manual/en/opcache.configuration.php#ini.opcache.max-accelerated-files +.. _`Composer's autoloader optimization`: https://getcomposer.org/doc/articles/autoloader-optimization.md .. _`APC`: http://php.net/manual/en/book.apc.php .. _`APCu Polyfill component`: https://github.com/symfony/polyfill-apcu .. _`APCu PHP functions`: http://php.net/manual/en/ref.apcu.php -.. _`autoload.php`: https://github.com/symfony/symfony-standard/blob/master/app/autoload.php -.. _`bootstrap file`: https://github.com/sensiolabs/SensioDistributionBundle/blob/master/Composer/ScriptHandler.php -.. _`cachetool`: https://github.com/gordalina/cachetool From 6d43df8f639a9ed1965d1481dae111dafb0aa86f Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 29 Jan 2018 12:53:05 +0100 Subject: [PATCH 2/4] Added back a note about bootstrap files and PHP 7 --- performance.rst | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/performance.rst b/performance.rst index 635e08be903..164f7da8581 100644 --- a/performance.rst +++ b/performance.rst @@ -74,6 +74,12 @@ For more details, see :doc:`/components/class_loader/cache_class_loader`. Use Bootstrap Files ~~~~~~~~~~~~~~~~~~~ +.. caution:: + + Thanks to the optimizations introduced in PHP 7, bootstrap files are no + longer necessary when running your Symfony applications with PHP 7 or a + newer PHP version. + The Symfony Standard Edition includes a script to generate a so-called `bootstrap file`_, which is a large file containing the code of the most commonly used classes. This saves a lot of IO operations because Symfony no From fe4f0320a6c67c03dfecff029ff36a2468a520b1 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 29 Jan 2018 13:02:33 +0100 Subject: [PATCH 3/4] Better explain how to empty cache after each deploy --- performance.rst | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/performance.rst b/performance.rst index 164f7da8581..26a1c180934 100644 --- a/performance.rst +++ b/performance.rst @@ -148,19 +148,18 @@ overhead that can be avoided as follows: .. code-block:: ini ; php.ini - - ; after each deploy, call `opcache_reset()` or restart the web server - ; to empty the cache and regenerate the cached files. Otherwise you won't - ; see the updates made in the application opcache.validate_timestamps=0 -.. note:: +After each deploy, you must empty and regenerate the cache of OPcache. Otherwise +you won't see the updates made in the application. Given than in PHP, the CLI +and the web processes don't share the same OPcache, you cannot clear the web +server OPcache by executing some command in your terminal. These are some of the +possible solutions: - The OPcache is different for the web server and the command console. - You cannot clear the web server OPcache by executing some command - in your terminal. You either need to restart the web server or call the - ``opcache_reset()`` function via the web server (i.e. by having this in - a script that you execute over the web). +1. Restart the web server; +2. Call the ``apc_clear_cache()`` or ``opcache_reset()`` functions via the + web server (i.e. by having these in a script that you execute over the web); +3. Use the `cachetool`_ utility to control APC and OPcache from the CLI. .. _performance-configure-realpath-cache: @@ -219,3 +218,4 @@ Learn more .. _`APC`: http://php.net/manual/en/book.apc.php .. _`APCu Polyfill component`: https://github.com/symfony/polyfill-apcu .. _`APCu PHP functions`: http://php.net/manual/en/ref.apcu.php +.. _`cachetool`: https://github.com/gordalina/cachetool From c00cf2c91b2fd6cccbe18bfc04e2bb5bc2603cb3 Mon Sep 17 00:00:00 2001 From: Javier Eguiluz Date: Mon, 29 Jan 2018 13:11:30 +0100 Subject: [PATCH 4/4] Added a missing reference --- performance.rst | 1 + 1 file changed, 1 insertion(+) diff --git a/performance.rst b/performance.rst index 26a1c180934..fbf5ea980e9 100644 --- a/performance.rst +++ b/performance.rst @@ -214,6 +214,7 @@ Learn more .. _`byte code caches`: https://en.wikipedia.org/wiki/List_of_PHP_accelerators .. _`OPcache`: http://php.net/manual/en/book.opcache.php +.. _`bootstrap file`: https://github.com/sensiolabs/SensioDistributionBundle/blob/master/Composer/ScriptHandler.php .. _`Composer's autoloader optimization`: https://getcomposer.org/doc/articles/autoloader-optimization.md .. _`APC`: http://php.net/manual/en/book.apc.php .. _`APCu Polyfill component`: https://github.com/symfony/polyfill-apcu