$30 off During Our Annual Pro Sale. View Details »

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

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 OPCache, Realpath
    Cache and Preloading
    How to tune your PHP installation

    View Slide

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

    View Slide

  3. @coudenysj - jachim.be
    Some groundwork

    View Slide

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

    View Slide

  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

    View Slide

  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.

    View Slide

  7. @coudenysj - jachim.be
    All set?

    View Slide

  8. @coudenysj - jachim.be
    Jachim Coudenys

    View Slide

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

    View Slide

  10. @coudenysj - jachim.be
    Right!

    View Slide

  11. @coudenysj - jachim.be
    Why this
    presentation?

    View Slide

  12. @coudenysj - jachim.be
    80% of performance issues have nothing to do
    with your server!
    https://www.combell.com/en/performance-team

    View Slide

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

    View Slide

  14. @coudenysj - jachim.be
    https://gist.github.com/jboner/2841832

    View Slide

  15. @coudenysj - jachim.be
    How can we fix it?

    View Slide

  16. @coudenysj - jachim.be
    Disk IO

    View Slide

  17. @coudenysj - jachim.be

    View Slide

  18. @coudenysj - jachim.be

    View Slide

  19. @coudenysj - jachim.be

    View Slide

  20. @coudenysj - jachim.be
    Network File System (NFS)

    View Slide

  21. @coudenysj - jachim.be

    View Slide

  22. @coudenysj - jachim.be
    Tackle these
    challenges in PHP
    Realpath Cache
    OPCache
    Preloading

    View Slide

  23. @coudenysj - jachim.be
    Realpath Cache

    View Slide

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

    View Slide

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

    View Slide

  26. @coudenysj - jachim.be
    demo
    php realpath.php

    View Slide

  27. @coudenysj - jachim.be
    $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());

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  46. @coudenysj - jachim.be
    demo
    php opcache.php

    View Slide

  47. @coudenysj - jachim.be
    // php -d opcache.enable_cli=On opcache.php
    print_r(opcache_get_status());

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  58. @coudenysj - jachim.be
    // php -d opcache.enable_cli=On -d
    opcache.file_cache="/home/jachim/demo/cache" opcache.php
    print_r(opcache_get_status());

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  70. @coudenysj - jachim.be
    OPCache on steroids

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

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

    View Slide

  84. @coudenysj - jachim.be
    In conclusion

    View Slide

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

    View Slide

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

    View Slide

  87. @coudenysj - jachim.be
    Thank you!
    @coudenysj - jachim.be
    https://joind.in/talk/d1cfa

    View Slide