Upgrade to Pro — share decks privately, control downloads, hide ads and more …

PHP OPCache, Realpath Cache and Preloading (PHP...

PHP OPCache, Realpath Cache and Preloading (PHPUK 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.

Jachim Coudenys

February 21, 2020
Tweet

More Decks by Jachim Coudenys

Other Decks in Technology

Transcript

  1. @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. @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. @coudenysj - jachim.be 80% of performance issues have nothing to

    do with your server! https://www.combell.com/en/performance-team
  4. @coudenysj - jachim.be Latency Comparison Numbers (~2012) L1 cache reference

    0.5 ns Branch mispredict 5 ns L2 cache reference 7 ns 14x L1 cache Main memory reference 100 ns 20x L2 cache, 200x L1 Send 1K bytes over 1 Gbps network 10,000 ns 10 us Read 4K randomly from SSD* 150,000 ns 150 us ~1GB/sec SSD Read 1 MB sequentially from memory 250,000 ns 250 us Round trip within same datacenter 500,000 ns 500 us Read 1 MB sequentially from SSD* 1,000,000 ns 1,000 us 1 ms ~1GB/sec SSD, 4X memory Disk seek 10,000,000 ns 10,000 us 10 ms 20x datacenter roundtrip Read 1 MB sequentially from disk 20,000,000 ns 20,000 us 20 ms 80x memory, 20X SSD Send packet CA->Netherlands->CA 150,000,000 ns 150,000 us 150 ms
  5. @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
  6. @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());
  7. @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 )
  8. @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 )
  9. @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.
  10. @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
  11. @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.
  12. @coudenysj - jachim.be This can get big quite quickly •

    Libraries • Frameworks • etc...
  13. @coudenysj - jachim.be OPCache • Bunch of opcode cachers ◦

    APC ◦ Turck MMCache ◦ Zend Optimizer ◦ etc... • Zend Optimizer "donated" by Zend • Since PHP 5.5
  14. @coudenysj - jachim.be OPCache Optimizer • Gets better every release

    • Optimizes: ◦ Branches ◦ Dead code ◦ ++$a vs $a++
  15. @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()
  16. @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 ) ...
  17. @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 ) ...
  18. @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 ) ) ...
  19. @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)
  20. @coudenysj - jachim.be Opcache restarts • OOM Restarts ◦ Memory

    • Hash Restarts ◦ Keys • Manual Restarts ◦ opcache_reset()
  21. @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
  22. @coudenysj - jachim.be └╼ tree cache cache └── 26f7903bdd40555497c24242ea455a66 └──

    home └── jachim └── demo └── opcache.php.bin 4 directories, 1 file
  23. @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
  24. @coudenysj - jachim.be Preloading Preload PHP functions and classes once

    and use them in the context of any future request without overhead.
  25. @coudenysj - jachim.be Preload PHP functions and classes once and

    use them in the context of any future request without overhead.
  26. @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
  27. @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
  28. @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);
  29. @coudenysj - jachim.be Composer • Sounds like a job for

    composer, right? • [RFC] Preloading support (https://github.com/composer/composer/issue s/7777)
  30. @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';
  31. @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
  32. @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
  33. @coudenysj - jachim.be PHP Performance • Know enough of PHP

    internals • Know your application (use information functions) • Finetune • Repeat
  34. @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