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=igbinarypairs with the explicitly-loadedigbinary.sofor a more compact serialization than the PHP default.apc.ttl=3600bounds entry lifetime so stale segments are not held indefinitely.apc.shm_sizeis 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.
Swap purge
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- 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.