opcache & APCu
The opcache and APCu shares are derived from the box-wide RAM budget computed in
FPM capacity sizing. This page covers how they are sized,
what BOA writes into each phpNN.ini, the Valkey/Redis cache instance settings,
and the read-only sampling tools (fpm_tune + fpmreport) that guide manual
tuning.
opcache and APCu shares
After the RAM ladder sets _USE_PHP and _USE_FPM, the cache shares follow:
_USE_OPCtracks the budget tier from the RAM ladder (8192 / 4096 / 2048 / 1024 /_USE), overridden to 64 on_VMFAMILY=VZ._USE_APC = _USE_FPM— APCu is sized to the whole FPM-pool budget, not_USE_FPM / 2. APCu is a single shared memory segment for the entire pool, not a per-worker allocation; the old per-worker/2formula caused >90% saturation on large servers with complex codebases.
APCu phpNN.ini settings
APCu is written to the FPM phpNN.ini only (_fix_php_ini_apcu via
_apply_php_fpm_ini_fixes in lib/functions/php.sh.inc). Each version has two
inis — the FPM one at /opt/phpNN/etc/phpNN.ini and the CLI one at
/opt/phpNN/lib/php.ini — and _fix_php_ini_apcu runs against the FPM ini only;
_apply_php_cli_ini_fixes never calls it, so APCu is absent from the CLI ini.
It is also gated [ "${e}" -gt 56 ], so PHP 5.6 gets no APCu at all. (This
FPM-only placement is the basis of the CLI-vs-FPM cache distinction covered in
cache & cron tuning.) BOA writes:
extension=apcu.so
extension=igbinary.so
apc.serializer=igbinary
apc.shm_size=256M
apc.ttl=3600
apc.serializer=igbinary pairs with the explicitly-loaded igbinary.so for a
more compact serialization than the PHP default. apc.ttl=3600 bounds
entry lifetime so stale segments are not held indefinitely. apc.shm_size is the
per-version APCu segment. The 256M written here is only the template seed:
_tune_memory_limits rewrites every 256M in phpNN.ini to ${_USE_APC}M
(sed "s/256M/${_USE_APC}M/g", system.sh.inc), so on any tuned box the
effective apc.shm_size is the box-wide _USE_APC budget derived above, not a
flat 256 MB.
APCu is per-worker-process state living inside the FPM workers. It cannot be flushed remotely — a stale entry only clears when the worker is recycled. The graceful all-versions reload mechanism for clearing it is covered in cache & cron tuning.
Valkey / Redis cache instance
Valkey/Redis cache instances are run as a cache, not a persistence store:
- RDB snapshots disabled —
save "". - Eviction policy
maxmemory-policy volatile-lfu.
These are applied by _valkey_no_rdb in autoupboa and the matching
redis.conf / valkey.conf paths in system.sh.inc. The memory ceiling
(_MAX_MEM_VALKEY, default _RAM / 3 of usable RAM) and the password file
(/root/.valkey.pass.txt, or /root/.redis.pass.txt for the Redis variant) are
covered alongside the starvation diagnosis in
cache & cron tuning. Component versions track _PHP_APCU
(APCu 5.1.x) and _VALKEY_MAJOR_RELEASE (Valkey 9.x) — for pinned numbers see
the Reference appendix. For Redis/Valkey host tunables
see Host control files & INI reference.
Separately, autoupboa's _swap_purge_if_bloated purges swap (sync +
drop_caches, then swapoff/swapon when free RAM can absorb it) on each run
once swap usage reaches 50%. That 50% is a function-local default
(_SWAP_THRESHOLD, the first positional argument), not a barracuda.cnf
operator variable.
Adaptive sampling: fpm_tune + fpmreport
BOA samples live FPM behaviour to guide manual tuning. Both tools are strictly
read-only — they write no phpNN.ini, trigger no FPM restart, and change no
tuning.
fpm_tune.sh
fpm_tune.sh (aegir/tools/system/monitor/check/, launched from minute.sh)
self-throttles to roughly one run per 5 minutes via
/var/log/boa/fpm-tune/.last_run (--force overrides). Each run makes three
passes:
- Version discovery + per-version worker USS sweep — taken before any status traffic, so the workers spawned to serve the sampler's own requests do not dilute the average.
- Per-pool
pm.statusover each pool socket. - Per-version opcache/APCu probe via that version's
wwwNNsystem-pool socket (the shared segments read the same data for any pool of that version).
It appends one JSONL record per pool and per version to
/var/log/boa/fpm-tune/<date>.jsonl (_RETAIN_DAYS=30; older files pruned by a
find … -mtime +30 -delete on each run).
fpmreport
fpmreport (aegir/tools/bin/fpmreport) aggregates that JSONL into
per-version/per-pool findings: pool starvation, opcache/APCu growth or oversize,
file-cap proximity, memory_limit-approach flags, and idle versions with reclaim
estimates.
It also prints a per-pool configured / observed table for every non-idle
pool — full header: pool, ver, plan, eng, class, cfg_kids, cfg_mem, peak, p95, mcr/day. cfg_kids and cfg_mem are the currently configured
pm.max_children and memory_limit — read live from the pool conf, following
the include so dedicated pools show their inherited box-wide memory_limit —
next to the observed peak active children, p95 and max_children-hit rate. A
pool configured at 128 but only ever driven to 34 reads as cfg_kids 128 … peak 34 rather than a bare inferred figure.
plan and eng are the instance's plan (_CLIENT_OPTION) and engines count
(_CLIENT_CORES), read live by the cfg_plan() helper from
/root/.<oN>.octopus.cnf — the instance name is the pool name minus its .NN
version suffix (o8.84 → o8). /data/disk/<oN>/log/cores.txt overrides the
cnf cores value when present (matching the sizing path), engines default to 1
when neither source yields a number, and plan renders - when the cnf is
unreadable. They resolve the ambiguity of a bare cfg_kids: 16 could be the
POWER shared tier (8 × engines × 2) or a dedicated plan's dynamic calc landing
on 16 on a small box — with plan/eng beside it, the allocation is validated
at a glance against the inputs the sizing logic keys on. The same values reach
--json: each pool_summary record carries plan and engines alongside its
cfg_max_children and cfg_memory_limit_mb fields.
fpmreport # this node, all retained data
fpmreport --days 7 # window relative to the newest record
fpmreport --json # machine-readable, one finding per line
fpmreport --data DIR|FILE... # incl. off-node corpora
bash fpm_tune.sh --force --stdout # sample once, print + store records
These findings drive the manual capacity adjustments in
FPM capacity sizing (the _PHP_FPM_* override knobs); the
tools never apply changes themselves.
Related
- FPM capacity sizing — the RAM budget these shares derive from, and the override knobs.
- cache & cron tuning — Valkey starvation, APCu flush, and the cron/drush failure modes.
- Self-healing monitor stack —
minute.shcadence that launchesfpm_tune.sh. - Reference appendix —
_PHP_APCU,_VALKEY_MAJOR_RELEASE,_USE_*pinned values.