PHP OPCache, Realpath Cache and Preloading (PHPBenelux Conference 2020)

PHP OPCache, Realpath Cache and Preloading (PHPBenelux Conference 2020)

Everybody wants quick applications. A lot of that speed can be gained by the way you write your software, but a big chunk has to do with the way PHP is configured. As PHP matured, it got quicker, it used less memory and it accumulated a lot of settings which can be tuned for performance.

The biggest, and often most misunderstood, features for performance are OPCache (introduced in 5.5) and preloading (introduced in 7.4). This talk covers how both features work, how you can take advantage of them on your servers and during deployments, and tries to show all the ini settings relevant for performance.

4ce755c7f3ddf4e0c92e1aeaeea7677b?s=128

Jachim Coudenys

January 24, 2020
Tweet

Transcript

  1. 5.

    @coudenysj - jachim.be PHP-FPM • Only "relevant" SAPI nowadays :)

    • Master process • Dynamic worker child processes • Shared memory in the master jachimbe 24546 0.0 0.0 301644 10152 ? Ss 2019 1:04 php-fpm: master process (/conf/jachimbe/php/fpm.conf) jachimbe 21457 3.6 0.1 304680 35732 ? S 10:57 0:00 \_ php-fpm: pool jachimbe jachimbe 21458 3.3 0.1 304680 35672 ? S 10:57 0:00 \_ php-fpm: pool jachimbe jachimbe 21459 3.3 0.1 304680 35672 ? S 10:57 0:00 \_ php-fpm: pool jachimbe jachimbe 21460 4.0 0.1 304680 35672 ? S 10:57 0:00 \_ php-fpm: pool jachimbe
  2. 6.

    @coudenysj - jachim.be Shared memory??? In computer hardware, shared memory

    refers to a (typically large) block of random access memory (RAM) that can be accessed by several different central processing units (CPUs) in a multiprocessor computer system.
  3. 12.

    @coudenysj - jachim.be Realpath Cache • Is used to reduce

    IO • Caches all possible paths to dest path • explode('/') • No shared memory! Mem*Workers • 4M ◦ Prior to PHP 7.0.16 and 7.1.2, the default was "16K" • Helps a lot with NFS
  4. 15.

    @coudenysj - jachim.be <?php $presentation = file_get_contents( __DIR__ . '/../ffi.php'

    ); $presentation2 = file_get_contents( dirname(__DIR__) . '/ffi.php' ); $filesize = filesize( __DIR__ . '/../est.txt' ); print_r(realpath_cache_get());
  5. 16.

    @coudenysj - jachim.be [/home/jachim/demo] => Array ( [key] => 1.6354972010384E+19

    [is_dir] => 1 [realpath] => /home/jachim/demo [expires] => 1579859105 ) [/home] => Array ( [key] => 4353355791257440477 [is_dir] => 1 [realpath] => /home [expires] => 1579859105 ) [/home/jachim] => Array ( [key] => 5522554812971572568 [is_dir] => 1 [realpath] => /home/jachim [expires] => 1579859105 )
  6. 17.

    @coudenysj - jachim.be [/home/jachim/demo/../ffi.php] => Array ( [key] => 1.6164035761241E+19

    [is_dir] => [realpath] => /home/jachim/ffi.php [expires] => 1579859105 ) [/home/jachim/ffi.php] => Array ( [key] => 5100116734180765326 [is_dir] => [realpath] => /home/jachim/ffi.php [expires] => 1579859105 ) [/home/jachim/demo/realpath.php] => Array ( [key] => 1.8190176096283E+19 [is_dir] => [realpath] => /home/jachim/demo/realpath.php [expires] => 1579859105 )
  7. 20.

    @coudenysj - jachim.be OPCache OPcache improves PHP performance by storing

    precompiled script bytecode in shared memory, thereby removing the need for PHP to load and parse scripts on each request.
  8. 22.

    @coudenysj - jachim.be Throwaway language • Always performs same steps

    ◦ Read PHP code ◦ Lexing + Parsing: Tokens ◦ Compiling: Opcodes ◦ Executing • All information is discarded • Request per request
  9. 24.

    @coudenysj - jachim.be opcodes? In computing, an opcode (abbreviated from

    operation code) is the portion of a machine language instruction that specifies the operation to be performed.
  10. 26.

    @coudenysj - jachim.be This can get big quite quickly •

    Libraries • Frameworks • etc...
  11. 28.

    @coudenysj - jachim.be OPCache • Bunch of opcode cachers ◦

    APC ◦ Turck MMCache ◦ Zend Optimizer ◦ etc... • Zend Optimizer "donated" by Zend • Since PHP 5.5
  12. 31.

    @coudenysj - jachim.be OPCache Optimizer • Gets better every release

    • Optimizes: ◦ Branches ◦ Dead code ◦ ++$a vs $a++
  13. 33.

    @coudenysj - jachim.be php.net/manual/en/ref.opcache.php • Information ◦ opcache_get_configuration() ◦ opcache_get_status()

    ◦ opcache_is_script_cached() • Actions ◦ opcache_compile_file() ◦ opcache_invalidate() ◦ opcache_reset()
  14. 36.

    @coudenysj - jachim.be [opcache_enabled] => 1 [cache_full] => [restart_pending] =>

    [restart_in_progress] => [memory_usage] => Array ( [used_memory] => 9168648 [free_memory] => 125049080 [wasted_memory] => 0 [current_wasted_percentage] => 0 ) [interned_strings_usage] => Array ( [buffer_size] => 6291008 [used_memory] => 371880 [free_memory] => 5919128 [number_of_strings] => 7869 ) ...
  15. 37.

    @coudenysj - jachim.be [opcache_statistics] => Array ( [num_cached_scripts] => 1

    [num_cached_keys] => 2 [max_cached_keys] => 16229 [hits] => 0 [start_time] => 1579859174 [last_restart_time] => 0 [oom_restarts] => 0 [hash_restarts] => 0 [manual_restarts] => 0 [misses] => 1 [blacklist_misses] => 0 [blacklist_miss_ratio] => 0 [opcache_hit_rate] => 0 ) ...
  16. 38.

    @coudenysj - jachim.be [scripts] => Array ( [/home/jachim/demo/opcache.php] => Array

    ( [full_path] => /home/jachim/demo/opcache.php [hits] => 0 [memory_consumption] => 880 [last_used] => Fri Jan 24 10:46:14 2020 [last_used_timestamp] => 1579859174 [timestamp] => 1579858691 ) ) ...
  17. 39.

    @coudenysj - jachim.be Interned strings • Used in a lot

    of languages • Since PHP 5.4 • "Compression" for source code • In shared memory (FPM master process)
  18. 42.

    @coudenysj - jachim.be Opcache restarts • OOM Restarts ◦ Memory

    • Hash Restarts ◦ Keys • Manual Restarts ◦ opcache_reset()
  19. 45.

    @coudenysj - jachim.be Opcache File Cache • Read opcodes from

    disk • Can help busy sites • Supports CLI (used to be "fire and forget") • Cache to "user directory" opcache.file_cache=/var/tmp/php/opcache opcache.file_cache_only=1 # Useful for CLI opcache.file_cache_consistency_checks=1 # Adler checksum
  20. 48.

    @coudenysj - jachim.be └╼ tree cache cache └── 26f7903bdd40555497c24242ea455a66 └──

    home └── jachim └── demo └── opcache.php.bin 4 directories, 1 file
  21. 49.
  22. 52.

    @coudenysj - jachim.be php.net/manual/en/opcache.configuration.php • Memory ◦ opcache.memory_consumption ◦ opcache.interned_strings_buffer

    ◦ opcache.max_accelerated_files (keys) • Invalidation ◦ opcache.validate_timestamps ◦ opcache.revalidate_freq • Thresholds ◦ opcache.max_wasted_percentage
  23. 57.

    @coudenysj - jachim.be Preloading Preload PHP functions and classes once

    and use them in the context of any future request without overhead.
  24. 58.

    @coudenysj - jachim.be Preload PHP functions and classes once and

    use them in the context of any future request without overhead.
  25. 60.

    @coudenysj - jachim.be Preloading • PHP 7.4 • Part of

    opcache • Starts in master process before anything else • Loads code in memory "permanently" • No need to copy from shared memory to process memory
  26. 61.

    @coudenysj - jachim.be Preloading • Opcache only works per file

    • Preloading helps with class libraries • Code will perform as internal entities (e.g. strlen, etc...) • Simple file with autoloading magic
  27. 64.

    @coudenysj - jachim.be Preloading in the wild • github.com/brendt/laravel-preload/blob/master/preload.php •

    symfony.com/blog/new-in-symfony-4-4-preloading-symfony-applications-in-php -7-4 // var/cache/dev/srcApp_KernelDevDebugContainer.preload.php // This file has been auto-generated by the Symfony Dependency Injection Component // You can reference it in the "opcache.preload" php.ini setting on PHP >= 7.4 when preloading is desired use Symfony\Component\DependencyInjection\Dumper\Preloader; require dirname(__DIR__, 3).'/vendor/autoload.php'; require __DIR__.'/ContainerZxvZ783/srcApp_KernelDevDebugContainer.php'; $classes = []; $classes[] = 'App\Kernel'; Preloader::preload($classes);
  28. 66.

    @coudenysj - jachim.be Composer • Sounds like a job for

    composer, right? • [RFC] Preloading support (https://github.com/composer/composer/issue s/7777)
  29. 67.

    @coudenysj - jachim.be Composer benchmarks https://github.com/composer/composer/issues/7 777#issuecomment-440268416 • No preloading

    • Preloading only "hot" classes ◦ $files = opcache_get_status(true)['scripts']; • Preloading all the classes ◦ $files = require 'vendor/composer/autoload_classmap.php';
  30. 71.

    @coudenysj - jachim.be Preloading issues • There were some problems

    with using require() instead of opcache_compile_file() ◦ Should be fixed in latest release • Some issues in bugtracker, but not that bad ◦ https://bugs.php.net/search.php?cmd=display&search_for =preload
  31. 72.

    @coudenysj - jachim.be Performance • Is it worth the effort?

    • Depends on the situation • We mostly see an improvement • Stick with the hot classes • Currently looking at how we can apply it at scale for our customers at Combell • Some reports: ◦ https://stitcher.io/blog/php-preload-benchmarks ◦ https://ezplatform.com/blog/php-7.4-opcache-preloading-benchmark ◦ https://developer.happyr.com/php-74-preload
  32. 75.

    @coudenysj - jachim.be PHP Performance • Know enough of PHP

    internals • Know your application (use information functions) • Finetune • Repeat
  33. 76.

    @coudenysj - jachim.be Elastic Stack @ Combell • Gather realpath/opcache/etc...

    data from all accounts • Act upon that data (which is changing constantly) • Autotuning & autoconfigure preload