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

Preloading and Symfony, a love story

Preloading and Symfony, a love story

Preloading is a hot topic these days, yet the first versions of PHP 7.4 crashed when it was enabled. Since September with the first experiments (and crash reports), Nicolas is tracking the beast: PHP 7.4.5 finally makes it usable in all contexts and a 75% boost has been measured on a "Hello World" app. Can you expect the same benefits on your apps? Preloading comes with its own challenges. Let's review them and figure how you can get the most out of it for the benefit of your server's efficiency and response time.

First presented at https://online.live.symfony.com/

Nicolas Grekas

April 17, 2020

More Decks by Nicolas Grekas

Other Decks in Technology


  1. Lambda-style before it was hype • PHP has a run-and-forget

    execution model • Every request has to reload everything all-the-time • Memory leaks and shared state are hard problems • This is great for developer efficiency • This is great for robustness of apps • This makes hosting great • This makes scalability easy
  2. Shared memory (SHM) to the rescue • The code is

    immutable • The compilation steps can be cached • APC, eAccelerator, Turck MMCache, Zend OpCache FTW • But which compilation steps?
  3. Opcode caches • The source code is compiled into a

    list of instructions, the opcodes: • ADD, CONCAT, ASSIGN, …, DECLARE_CLASS, DECLARE_FUNCTION, DECLARE_INHERITED_CLASS, ADD_INTERFACE, etc. • Shared memory holds a hashmap map of (file => opcodes) pairs
  4. Opcode caches++ • PHP 5.4: interned strings • PHP 5.5:

    OPcache becomes open-source and builtin • PHP 5.6: array declarations stay in shared memory • PHP 7.0: • all static arrays stay in shared memory • post-compilation optimizations • PHP 7.1, 7.2, 7.3 • more post-compilation optimizations
  5. What remains before 7.4? • Check freshness • Transfer opcodes

    into each request’s memory • Link parent classes, interfaces and traits • Validate signatures, covariance and contravariance
  6. Out of scope • Bootstraping the kernel or equivalent •

    Loading the services (persistent connections) • Computing the response
  7. Preloading removes • Freshness checks • Everything related to loading

    and declaring classes and functions • Everything is available out-of-the-box, feels like native • (RIP function autoloading, you’ll never have any purpose)
  8. Preloading 101 • opcache.preload=/some/preloading/script.php in your php.ini opcache.preload_user=www-data if running

    as root (Docker anyone?) • Any classes or functions included by this script Any classes or functions opcache_compile_file()’ed • php-fpm / php -S will load them before serving any requests
  9. (symbol => opcodes) pairs in SHM • Incompatible with several

    apps on the same FPM server • Is really immutable: reboot the server to reload the code • opcache_get_status() gives all the info • Declarations nested in « if » statements are not preloaded • Only fully-resolved classes are preloaded (you can ignore the warnings) • (oh, it’s not available on Windows)
  10. opcache_compile_file()? 1. Deploy without preloading 2. Get some HTTP traffic

    3. Dump preload.php from opcache_get_status() 4. Restart prod with preloading 5. Automate for every deployment • Still loads too many classes (that’s theory) • Not practical – requires advanced tooling • Not compatible with class_alias()
  11. The obvious part: preload all services List all classes used

    by services (autoloading will cascade to parent classes/traits/interfaces)
  12. include() + autoloading! • The configuration drives the useful classes

    • Inline class_exists() declare local sidekicks • container.preload/.no_preload for fine tuning • Make cache warmers report their artifacts
  13. • opcache.preload=var/cache/prod/App_KernelProdContainer.preload.php • Profit • (optionally, fine tune with opcache_get_status()

    and commit the result) • (go patch open-source bundles and libs to maximize their preloading potential) include() + autoloading?
  14. Kudos Dmitry and Nikita • include() + autoloading • opcache_compile_file()

    • Hello World with Twig and without preloading: 360 req/s • with preloading, no cache warmers: 560 req/s (+55%) • with preloading, yes cache warmers: 630 req/s (+75%) • A typical app spends 15% loading code • It’s worth it! (but not worth a complex deployment process) PS: there is no memory to share when running on the CLI PPS: autoloading + Composer FTW and here to stay