Skip to content

perf(php): stop OPcache timestamp checks and size it for Symfony apps - #59

Merged
guillaume-sainthillier merged 1 commit into
mainfrom
perf/opcache
Oct 12, 2026
Merged

guillaume-sainthillier merged 1 commit into
mainfrom
perf/opcache

Conversation

@guillaume-sainthillier

Copy link
Copy Markdown
Member

OPcache no longer checks file timestamps by default (Apache and FrankenPHP images). opcache.validate_timestamps now reads PHP_OPCACHE_VALIDATE_TIMESTAMPS, set to 0 in the Dockerfiles. Before, revalidate_freq = 0 made PHP stat() every included file on every request. Set PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 for bind-mounted sources edited in place (documented in a new README Configuration section).

Cache sized for a Symfony app with its vendors: max_accelerated_files 10000 → 20000, interned_strings_buffer 8 → 16 MB, memory_consumption 128 → 256 MB.

Benchmark

symfony/skeleton in prod (one route returning ok, ~2,300 PHP files, classmap-authoritative, cache warmed), copied into the image, ab -n 4000 -c 8 run inside the container, --cpus=2, 3 runs each:

Image req/s mean latency
published 8.5-symfony 2,835 – 3,204 2.50 – 2.82 ms
this PR, PHP_OPCACHE_VALIDATE_TIMESTAMPS=1 3,056 – 3,227 2.48 – 2.62 ms
this PR, default 4,636 – 5,136 1.56 – 1.73 ms

The new sizes alone don't change this small app (it fits in the old limits); they prevent cache eviction on larger ones.

Notes

  • Deploy = restart: with the default, updated PHP files are ignored until PHP restarts. That is already how these images are meant to be used (code baked into the image), but anything changing PHP files at runtime (cache:clear on a live container, mounted sources) needs PHP_OPCACHE_VALIDATE_TIMESTAMPS=1.
  • Legacy folders get the new php.ini through update.sh but no ENV; an unset variable also reads as off. They aren't rebuilt by CI.
  • CI images don't load conf/php.ini and are unchanged.
  • PHP 8.6 (#57) gets the same change in its own PR.

opcache.validate_timestamps is now driven by PHP_OPCACHE_VALIDATE_TIMESTAMPS,
0 by default in the Apache and FrankenPHP images: with revalidate_freq = 0,
PHP was stat()ing every included file on every request. Set it to 1 when the
sources are mounted and edited in place.

The cache is also sized for a Symfony app and its vendors:
max_accelerated_files 10000 -> 20000, interned_strings_buffer 8 -> 16 MB,
memory_consumption 128 -> 256 MB.

On a symfony/skeleton app in prod (2,300 PHP files, ab -c 8 inside the
container, 2 CPUs), 8.5-symfony goes from ~3,000 to ~4,800 requests/s.
guillaume-sainthillier added a commit that referenced this pull request Oct 12, 2026
Same changes as #58 (Apache logs on stdout/stderr, php.ini-production,
X-Forwarded-Proto, no health check in the CI image, Composer through
install-php-extensions) and #59 (OPcache timestamps and sizing), so the
8.6 folders match 8.5 apart from the base image.

conf/ is copied from _shared/ as it will be once both are merged; until
then, running update.sh on this branch alone would revert it.
@guillaume-sainthillier
guillaume-sainthillier merged commit e32b965 into main Oct 12, 2026
25 checks passed
@guillaume-sainthillier
guillaume-sainthillier deleted the perf/opcache branch October 12, 2026 13:25
guillaume-sainthillier added a commit that referenced this pull request Oct 12, 2026
* feat: add PHP 8.6 release candidate images

Add the 8.6, 8.6-ci and 8.6-symfony variants, copied from 8.5 and built
from the upstream php:8.6-rc-apache / php:8.6-rc-alpine images (8.6.0RC3
today). They are published as silarhi/php-apache:8.6* and listed in the CI
matrix and the Makefile; latest stays on 8.5 until 8.6.0 is released.

FrankenPHP variants are not added yet: dunglas/frankenphp has no PHP 8.6
tag so far.

* fix: apply the image and OPcache fixes to the PHP 8.6 images

Same changes as #58 (Apache logs on stdout/stderr, php.ini-production,
X-Forwarded-Proto, no health check in the CI image, Composer through
install-php-extensions) and #59 (OPcache timestamps and sizing), so the
8.6 folders match 8.5 apart from the base image.

conf/ is copied from _shared/ as it will be once both are merged; until
then, running update.sh on this branch alone would revert it.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant