Slide 1

Slide 1 text

@coudenysj - jachim.be PHP OPCache, Realpath Cache and Preloading How to tune your PHP installation

Slide 2

Slide 2 text

@coudenysj - jachim.be New PHP versions go faster, but we can make them go even faster!

Slide 3

Slide 3 text

@coudenysj - jachim.be Some groundwork

Slide 4

Slide 4 text

@coudenysj - jachim.be PHP ● Scripting Language ● Fire and forget ● No "manual" compilation

Slide 5

Slide 5 text

@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

Slide 6

Slide 6 text

@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.

Slide 7

Slide 7 text

@coudenysj - jachim.be All set?

Slide 8

Slide 8 text

@coudenysj - jachim.be Jachim Coudenys

Slide 9

Slide 9 text

@coudenysj - jachim.be So this talk is about performance, right?

Slide 10

Slide 10 text

@coudenysj - jachim.be Right!

Slide 11

Slide 11 text

@coudenysj - jachim.be Realpath Cache

Slide 12

Slide 12 text

@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

Slide 13

Slide 13 text

@coudenysj - jachim.be php.net/manual/en/ref.filesystem.php ● realpath_cache_get() ● realpath_cache_size() ● realpath()

Slide 14

Slide 14 text

@coudenysj - jachim.be demo php realpath.php

Slide 15

Slide 15 text

@coudenysj - jachim.be

Slide 16

Slide 16 text

@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 )

Slide 17

Slide 17 text

@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 )

Slide 18

Slide 18 text

@coudenysj - jachim.be Realpath Cache: what can we tune?

Slide 19

Slide 19 text

@coudenysj - jachim.be php.net/manual/en/ini.core.php ● realpath_cache_size ● realpath_cache_ttl

Slide 20

Slide 20 text

@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.

Slide 21

Slide 21 text

@coudenysj - jachim.be https://engineering.facile.it/blog/eng/realpath-cache-is-it- all-php-opcache-s-fault/

Slide 22

Slide 22 text

@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

Slide 23

Slide 23 text

@coudenysj - jachim.be https://engineering.facile.it/blog/eng/realpath-cache-is-it- all-php-opcache-s-fault/

Slide 24

Slide 24 text

@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.

Slide 25

Slide 25 text

@coudenysj - jachim.be Vulcan Logic Dumper https://3v4l.org/A1B4H/vld

Slide 26

Slide 26 text

@coudenysj - jachim.be This can get big quite quickly ● Libraries ● Frameworks ● etc...

Slide 27

Slide 27 text

@coudenysj - jachim.be OPCodes (usually) don't change ● Let’s add in some cache!

Slide 28

Slide 28 text

@coudenysj - jachim.be OPCache ● Bunch of opcode cachers ○ APC ○ Turck MMCache ○ Zend Optimizer ○ etc... ● Zend Optimizer "donated" by Zend ● Since PHP 5.5

Slide 29

Slide 29 text

@coudenysj - jachim.be https://engineering.facile.it/blog/eng/realpath-cache-is-it- all-php-opcache-s-fault/

Slide 30

Slide 30 text

@coudenysj - jachim.be Shared memory ● Stored in the master process of FPM

Slide 31

Slide 31 text

@coudenysj - jachim.be OPCache Optimizer ● Gets better every release ● Optimizes: ○ Branches ○ Dead code ○ ++$a vs $a++

Slide 32

Slide 32 text

@coudenysj - jachim.be Optimized opcodes (example) https://3v4l.org/A1B4H/vld

Slide 33

Slide 33 text

@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()

Slide 34

Slide 34 text

@coudenysj - jachim.be demo php opcache.php

Slide 35

Slide 35 text

@coudenysj - jachim.be

Slide 36

Slide 36 text

@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 ) ...

Slide 37

Slide 37 text

@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 ) ...

Slide 38

Slide 38 text

@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 ) ) ...

Slide 39

Slide 39 text

@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)

Slide 40

Slide 40 text

@coudenysj - jachim.be Keys ● Full path to file ● Relative paths to files

Slide 41

Slide 41 text

@coudenysj - jachim.be Wasted memory ● Opcache doesn't do "defragmentation" ● File changes cause recompilation

Slide 42

Slide 42 text

@coudenysj - jachim.be Opcache restarts ● OOM Restarts ○ Memory ● Hash Restarts ○ Keys ● Manual Restarts ○ opcache_reset()

Slide 43

Slide 43 text

@coudenysj - jachim.be NEVER have a full cache!

Slide 44

Slide 44 text

@coudenysj - jachim.be APCu ● User Shared memory ● apc_* compatible

Slide 45

Slide 45 text

@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

Slide 46

Slide 46 text

@coudenysj - jachim.be demo php -d opcache.enable_cli=On -d opcache.file_cache="/tmp/opcache" opcache.php

Slide 47

Slide 47 text

@coudenysj - jachim.be

Slide 48

Slide 48 text

@coudenysj - jachim.be └╼ tree cache cache └── 26f7903bdd40555497c24242ea455a66 └── home └── jachim └── demo └── opcache.php.bin 4 directories, 1 file

Slide 49

Slide 49 text

@coudenysj - jachim.be PHPArch Opcache article https://www.phparch.com/article/diving-in-the -opcache/ ● Explores the option of using opcache file caching as pre-compiled PHP programs.

Slide 50

Slide 50 text

@coudenysj - jachim.be OPCache: what can we tune?

Slide 51

Slide 51 text

@coudenysj - jachim.be “Disaster Recovery” Scenarios ● Memory Full? ● Interned Strings Full? ● Key store full?

Slide 52

Slide 52 text

@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

Slide 53

Slide 53 text

@coudenysj - jachim.be Getting stats ● opcache_get_status()

Slide 54

Slide 54 text

@coudenysj - jachim.be https://github.com/rlerdorf/opcache-status

Slide 55

Slide 55 text

@coudenysj - jachim.be https://gist.github.com/ck-on/

Slide 56

Slide 56 text

@coudenysj - jachim.be Opcache Priming / Deployment Strategies ● opcache_compile_file() ● FPM Pools ● or…

Slide 57

Slide 57 text

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

Slide 58

Slide 58 text

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

Slide 59

Slide 59 text

@coudenysj - jachim.be OPCache on steroids

Slide 60

Slide 60 text

@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

Slide 61

Slide 61 text

@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

Slide 62

Slide 62 text

@coudenysj - jachim.be php.net/manual/en/opcache.configuration.php ● opcache.preload=/path/to/preload.php ● opcache_compile_file()

Slide 63

Slide 63 text

@coudenysj - jachim.be Unlinked classes aren’t preloaded

Slide 64

Slide 64 text

@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);

Slide 65

Slide 65 text

@coudenysj - jachim.be Caveats ● “Full server” (fpm) ○ php.ini setting ● Server restart

Slide 66

Slide 66 text

@coudenysj - jachim.be Composer ● Sounds like a job for composer, right? ● [RFC] Preloading support (https://github.com/composer/composer/issue s/7777)

Slide 67

Slide 67 text

@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';

Slide 68

Slide 68 text

@coudenysj - jachim.be Composer benchmarks https://github.com/composer/composer/issues/7777#issuecomment-440268416

Slide 69

Slide 69 text

@coudenysj - jachim.be Composer at the moment https://github.com/composer/composer/issues/7777#issuecomment-559725760

Slide 70

Slide 70 text

@coudenysj - jachim.be

Slide 71

Slide 71 text

@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

Slide 72

Slide 72 text

@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

Slide 73

Slide 73 text

@coudenysj - jachim.be Preload resources ● https://externals.io/message/103333 ● https://wiki.php.net/rfc/preload ● https://github.com/php/php-src/pull/3538

Slide 74

Slide 74 text

@coudenysj - jachim.be In conclusion

Slide 75

Slide 75 text

@coudenysj - jachim.be PHP Performance ● Know enough of PHP internals ● Know your application (use information functions) ● Finetune ● Repeat

Slide 76

Slide 76 text

@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

Slide 77

Slide 77 text

@coudenysj - jachim.be Thank you! @coudenysj - jachim.be