Enhance OPcache configuration and documentation - #704
Conversation
- Updated default OPcache settings for production mode in various documentation files, emphasizing the importance of `PHP_OPCACHE_ENABLE` and its impact on performance. - Added a new guide on PHP OPcache tuning, detailing how to measure and adjust OPcache settings for optimal application performance. - Clarified the behavior of `PHP_OPCACHE_VALIDATE_TIMESTAMPS` and its implications for development and production environments. - Adjusted Dockerfiles across multiple variations to reflect new OPcache defaults, including increased memory consumption and maximum accelerated files. - Improved scripts and entrypoint messages to provide clearer guidance on OPcache usage and best practices for deployment.
Deploying serversideup-php with
|
| Latest commit: |
84fe9fa
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://aaa7f3ed.serversideup-php.pages.dev |
| Branch Preview URL: | https://opcache-improvements.serversideup-php.pages.dev |
Images for PR #704
No images were published from this run. View the run for details. All images with sizesSizes are compressed, per architecture.
Updated on every push to this PR. |
There was a problem hiding this comment.
First of all i truly appreciate the effort behind this PR
I would suggest the following:
This page should be targeted for the person who want to start to use the serversideup docker images for production only.
I would start by calling it "Getting started for production"
Naming it like that Because the production related configs are not strictly bounded to opcache only, it could be opcache, php, caddy, nginx or any production configs that the consumer must check their values before going to production.
For example the PHP_UPLOAD_MAX_FILE_SIZE its really needed to be set on demand set by the consumer to make sure its value proper with his application needs. and so on with other configs.
This page could have the configs grouped into sections like opcache/php/caddy/... etc for proper readibility and navigation.
Also add octane based section to point out the amount of octane workers configs and how to set them properly.
It also can be as Sub page under each image flavor so its scoped accordengly.
There was a problem hiding this comment.
Also i would suggest adding the following configs to check/tune on demand before going to production as it mostly coupled by the application code and business logic:
- PHP_DATE_TIMEZONE
- PHP_MEMORY_LIMIT
- PHP_MAX_EXECUTION_TIME
- PHP_UPLOAD_MAX_FILE_SIZE
- PHP_SESSION_COOKIE_SECURE
- PHP_REALPATH_CACHE_TTL
| | Variable | Default | What it controls | | ||
| |----------|---------|------------------| | ||
| | `PHP_OPCACHE_VALIDATE_TIMESTAMPS` | `0` | Whether OPcache checks if a file changed. `0` means files are cached until the container restarts. | | ||
| | `PHP_OPCACHE_REVALIDATE_FREQ` | `2` | How many seconds between change checks. Ignored unless timestamps are validated. | |
There was a problem hiding this comment.
We are focusing on production configs only, if its always ignored, its better to not mention them at all.
And as far as i know the PHP_OPCACHE_VALIDATE_TIMESTAMPS should always remain false in production.
Maybe mention the PHP_OPCACHE_REVALIDATE_FREQ as a not within the the What it controls column, but not as something needed for production (by giving it full row in the table)
|
|
||
| ## What production mode gives you | ||
|
|
||
| When `PHP_OPCACHE_ENABLE=1`, these are the defaults you get: |
There was a problem hiding this comment.
Its better to point out that they can be tuned as needed
| | `PHP_OPCACHE_INTERNED_STRINGS_BUFFER` | `16` | Megabytes reserved inside that segment for interned strings. | | ||
| | `PHP_OPCACHE_MAX_ACCELERATED_FILES` | `20000` | Maximum number of files that can be cached. | | ||
| | `PHP_OPCACHE_FORCE_RESTART_TIMEOUT` | `180` | Seconds to wait for a stuck cache restart before OPcache forces it. | | ||
| | `PHP_OPCACHE_SAVE_COMMENTS` | `1` | Keep PHPDoc comments in the cache. Required by Doctrine, PHPUnit, and many Laravel packages. | |
There was a problem hiding this comment.
I prefer this to be disabled be default for production.
The production defaults should be optimized at maximum for the most common apps, and any thing effects that should be set intentionally and be aware of (not hidden in default configs), also enabling this would not throw any error or anything, the dock blocks will waste a debatable amount of opcache memory space.
- PHPUnit: is for development"
- Doctrine: i don't know about symphony but i checked the latest laravel 13 (with AI) nothing in the stock skeleton's production tree needs opcache.save_comments to be true.
- many Laravel packages: not everyone uses every package.
| `PHP_OPCACHE_ENABLE` sets both `opcache.enable` and `opcache.enable_cli`, so CLI commands such as `php artisan` also run with OPcache. This helps long-running CLI processes like queue workers and Horizon. | ||
| :: | ||
|
|
||
| ## What production mode gives you |
There was a problem hiding this comment.
I would relabel this to be Configs to check and tune and guide on each how to set it properly. for example the PHP_OPCACHE_MAX_ACCELERATED_FILES, could be helpful to tell you need to count the amount of php files in production installation to set properly.
| ## Measuring what your app needs | ||
|
|
||
| Guessing is unnecessary. PHP tells you exactly how full the cache is. Drop this into a route or run it through the web server, since the CLI has its own separate cache: | ||
|
|
||
| ```php [public/opcache-status.php] | ||
| <?php | ||
| $status = opcache_get_status(false); | ||
|
|
||
| echo 'Cache full: ' . ($status['cache_full'] ? 'yes' : 'no') . PHP_EOL; | ||
| echo 'Cached files: ' . $status['opcache_statistics']['num_cached_keys'] . ' of ' . $status['opcache_statistics']['max_cached_keys'] . PHP_EOL; | ||
| echo 'Memory used: ' . round($status['memory_usage']['used_memory'] / 1048576) . ' MB' . PHP_EOL; | ||
| echo 'Memory free: ' . round($status['memory_usage']['free_memory'] / 1048576) . ' MB' . PHP_EOL; | ||
| echo 'Interned strings free: ' . round($status['interned_strings_usage']['free_memory'] / 1048576) . ' MB' . PHP_EOL; | ||
| echo 'Out of memory restarts: ' . $status['opcache_statistics']['oom_restarts'] . PHP_EOL; | ||
| echo 'Hash restarts: ' . $status['opcache_statistics']['hash_restarts'] . PHP_EOL; | ||
| ``` | ||
|
|
||
| ::caution | ||
| Remove this file before deploying, or protect it. It exposes the full path of every cached file. | ||
| :: |
There was a problem hiding this comment.
I really would like a ready made larave command or a script that prints these measures directly, or even set them.
So it can run in these ways:
- manually one time to set the values.
- CI/CD pipelines to check if the settings needs to be increased on every code changes.
- Container entrypoint to set them on demand with consediration of the available cpu/memory resources.
| What to look for after your application has served real traffic for a while: | ||
|
|
||
| - **Cache full is `yes`** or **out of memory restarts** is climbing: raise `PHP_OPCACHE_MEMORY_CONSUMPTION`. | ||
| - **Cached files** is close to the maximum or **hash restarts** is climbing: raise `PHP_OPCACHE_MAX_ACCELERATED_FILES`. | ||
| - **Interned strings free** is near zero: raise `PHP_OPCACHE_INTERNED_STRINGS_BUFFER`. | ||
|
|
||
| Restarts are the thing to avoid. When OPcache runs out of room it throws the entire cache away and recompiles everything, which shows up as a latency spike. |
There was a problem hiding this comment.
Can we determine these before serving real traffic ?
There was a problem hiding this comment.
And whats the way to "look for" ? manually ssh to the server or ?
…tion performance tuning guide
…rove CLI handling, and clarify production settings
|
@Abdulmajeed-Jamaan You beat me to it 😃 I came back with another pass this morning. I appreciate your feedback. Take a look at this: https://opcache-improvements.serversideup-php.pages.dev/open-source/docker-php/docs/guide/production-performance-tuning |
|
I have another branch that depends on this being merged into my release branch. I am going to merge this, but I am still open to improving this. I think this is a good start and we can continue to improve it if needed |
ed8141b
into
release/webserver-improvements-and-fixes
Why we created this PR
PHP_OPCACHE_ENABLE=0is our default so your edits show up instantly in development. That stays the same.The problem is
PHP_OPCACHE_ENABLE=1. We call it the production setting, but behind it were PHP's stock defaults from 2013. OPcache checked every file for changes every two seconds, the memory sizes were too small for a modern Laravel or Symfony app, andPHP_OPCACHE_FORCE_RESTART_TIMEOUTnever reachedphp.ini.If you flip one switch for production, the settings behind it should be the ones you would pick yourself. This PR makes that true.
How we approached it
PHP_OPCACHE_ENABLEis a mode switch.0is development: OPcache off, mounted code updates instantly.1is production: code is built into the image, so cache it once and stop checking the filesystem.For each setting we asked what PHP recommends for immutable containers, what a real app needs, and what it costs if we are wrong. Anything we could not justify stayed at PHP's default.
How to test
View the testing images →
docker run --rm -e PHP_OPCACHE_ENABLE=1 serversideup/php-dev:704-8.4-cli \ php -r 'echo ini_get("opcache.validate_timestamps"), " ", ini_get("opcache.memory_consumption"), " ", ini_get("opcache.max_accelerated_files");'Expect
0 256 20000and a production mode notice in the startup banner.What this PR does
Changed defaults (only when
PHP_OPCACHE_ENABLE=1)PHP_OPCACHE_VALIDATE_TIMESTAMPS10PHP_OPCACHE_MEMORY_CONSUMPTION128256PHP_OPCACHE_INTERNED_STRINGS_BUFFER816PHP_OPCACHE_MAX_ACCELERATED_FILES1000020000Kept on purpose: JIT off (little gain for web apps, conflicts with Xdebug),
SAVE_COMMENTS=1(Doctrine and PHPUnit need it),ENABLE_FILE_OVERRIDE=0(lies about deleted files when timestamps are off).New variables
PHP_OPCACHE_PRELOAD""PHP_OPCACHE_PRELOAD_USER""Fixes
PHP_OPCACHE_FORCE_RESTART_TIMEOUTnow reachesphp.ini. The ini line was commented out.PHP_OPCACHE_SAVE_COMMENTSdoc said "remove comments" for a variable that keeps them.Also
scripts/test-image.shruns every image withPHP_OPCACHE_ENABLE=1, so CI proves OPcache starts with the new sizes on Debian, Alpine, amd64, and arm64.Compatibility
This is 5.0 because
PHP_OPCACHE_VALIDATE_TIMESTAMPS=0is breaking for one group: people who setPHP_OPCACHE_ENABLE=1with code mounted as a volume. Edits will not show up until the container restarts. That includes WordPress on a volume updated withgit pullor WP-CLI (admin updates still work), anddocker exec ... artisan optimizeagainst a live container.Fix: restart the container after code changes, or set
PHP_OPCACHE_VALIDATE_TIMESTAMPS=1for the old behavior. Nothing changes withPHP_OPCACHE_ENABLE=0.