feat(litespeed): wire up dynamic LSAPI tuning + idle reduction
All checks were successful
Cloud Apache Container / Build-and-Push (74) (push) Successful in 1m18s
Cloud Apache Container / Build-and-Push (80) (push) Successful in 2m14s
Cloud Apache Container / Build-and-Push (81) (push) Successful in 3m21s
Cloud Apache Container / Build-and-Push (82) (push) Successful in 2m18s
Cloud Apache Container / Build-and-Push (83) (push) Successful in 2m15s
Cloud Apache Container / Build-and-Push (84) (push) Successful in 2m11s
Cloud Apache Container / Build-and-Push (85) (push) Successful in 2m22s
Cloud Apache Container / Build-FPM-Images (74) (push) Successful in 4m22s
Cloud Apache Container / Build-FPM-Images (80) (push) Successful in 3m46s
Cloud Apache Container / Build-FPM-Images (81) (push) Successful in 1m17s
Cloud Apache Container / Build-FPM-Images (82) (push) Successful in 1m21s
Cloud Apache Container / Build-FPM-Images (83) (push) Successful in 2m15s
Cloud Apache Container / Build-FPM-Images (84) (push) Successful in 2m21s
Cloud Apache Container / Build-FPM-Images (85) (push) Successful in 3m29s
Cloud Apache Container / Build-LiteSpeed-Images (81) (push) Successful in 31s
Cloud Apache Container / Build-LiteSpeed-Images (82) (push) Successful in 31s
Cloud Apache Container / Build-LiteSpeed-Images (83) (push) Successful in 30s
Cloud Apache Container / Build-LiteSpeed-Images (84) (push) Successful in 32s
Cloud Apache Container / Build-LiteSpeed-Images (85) (push) Successful in 31s
Cloud Apache Container / Build-Shared-httpd (push) Successful in 1m33s
All checks were successful
Cloud Apache Container / Build-and-Push (74) (push) Successful in 1m18s
Cloud Apache Container / Build-and-Push (80) (push) Successful in 2m14s
Cloud Apache Container / Build-and-Push (81) (push) Successful in 3m21s
Cloud Apache Container / Build-and-Push (82) (push) Successful in 2m18s
Cloud Apache Container / Build-and-Push (83) (push) Successful in 2m15s
Cloud Apache Container / Build-and-Push (84) (push) Successful in 2m11s
Cloud Apache Container / Build-and-Push (85) (push) Successful in 2m22s
Cloud Apache Container / Build-FPM-Images (74) (push) Successful in 4m22s
Cloud Apache Container / Build-FPM-Images (80) (push) Successful in 3m46s
Cloud Apache Container / Build-FPM-Images (81) (push) Successful in 1m17s
Cloud Apache Container / Build-FPM-Images (82) (push) Successful in 1m21s
Cloud Apache Container / Build-FPM-Images (83) (push) Successful in 2m15s
Cloud Apache Container / Build-FPM-Images (84) (push) Successful in 2m21s
Cloud Apache Container / Build-FPM-Images (85) (push) Successful in 3m29s
Cloud Apache Container / Build-LiteSpeed-Images (81) (push) Successful in 31s
Cloud Apache Container / Build-LiteSpeed-Images (82) (push) Successful in 31s
Cloud Apache Container / Build-LiteSpeed-Images (83) (push) Successful in 30s
Cloud Apache Container / Build-LiteSpeed-Images (84) (push) Successful in 32s
Cloud Apache Container / Build-LiteSpeed-Images (85) (push) Successful in 31s
Cloud Apache Container / Build-Shared-httpd (push) Successful in 1m33s
Two correctness fixes and a tuning improvement.
CORRECTNESS:
1. Strip the stock 'extProcessor lsphp' from httpd_config.conf before
appending ours. Previously the stock block (hard-coded
PHP_LSAPI_CHILDREN=10 regardless of container memory) always won
because our APPEND fragment didn't include an extProcessor block.
detect-memory-litespeed.sh was computing LSAPI_CHILDREN but never
plumbing it anywhere — silent dead code.
2. Bump LSPHP_WORKER_ESTIMATE_MB from 96 → 115 per the 2026-06-02
memory-sizing finding (vantagehealth OOM-spawn loop). Each lsphp
carries ~115 MB shmem-rss accounted per worker. 115 MB matches the
real per-worker baseline.
TUNING (idle reduction, the original ask):
- LSAPI_MAX_IDLE_CHILDREN=2 (was CHILDREN/2 = 5 default)
- LSAPI_MAX_IDLE=60s (was 300s default)
- PHP_LSAPI_MAX_REQUESTS=500 (recycle workers, prevents bloat)
- memSoftLimit=1024M / memHardLimit=1500M per worker (RLIMIT_AS;
catches runaway scripts at the worker level, cgroup still backstops
the container)
Effective LSAPI_CHILDREN per container:
2 GiB → ~17 (was 10 — brain-jar was saturating)
1 GiB → ~8
512 MiB → ~3 (cap-marginal per the memory note; bump container if
site grows)
Dropped LSAPI_MEM_SOFT/HARD computation in detect-memory: AVAILABLE/CHILDREN
was conflating VSZ with RSS-budget arithmetic and would have killed
legitimate workers. The 1024/1500 hard-coded values in the template
comfortably fit typical Divi/WooCommerce VSZ (280-365 MB).
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,7 +7,8 @@
|
|||||||
## append pattern too (see setup_docker.sh in litespeedtech/ols-dockerfiles).
|
## append pattern too (see setup_docker.sh in litespeedtech/ols-dockerfiles).
|
||||||
##
|
##
|
||||||
## Rendered at container start by scripts/create-vhost-litespeed.sh via
|
## Rendered at container start by scripts/create-vhost-litespeed.sh via
|
||||||
## envsubst. Templated vars: $user $domain $vhost_map_aliases.
|
## envsubst. Templated vars: $user $domain $vhost_map_aliases $PHPVER
|
||||||
|
## $LSAPI_CHILDREN (computed by detect-memory-litespeed.sh)
|
||||||
|
|
||||||
## --- our listeners (replace stock Default :8088) ---
|
## --- our listeners (replace stock Default :8088) ---
|
||||||
listener HTTP {
|
listener HTTP {
|
||||||
@@ -30,6 +31,53 @@ listener HTTPS {
|
|||||||
map siteVH *
|
map siteVH *
|
||||||
}
|
}
|
||||||
|
|
||||||
|
## --- lsphp extProcessor (overrides the stock one which is hard-coded to
|
||||||
|
## PHP_LSAPI_CHILDREN=10 regardless of container memory).
|
||||||
|
##
|
||||||
|
## Sized dynamically by detect-memory-litespeed.sh based on the cgroup cap:
|
||||||
|
## 2 GiB container → LSAPI_CHILDREN ≈ 17 (was stuck at 10)
|
||||||
|
## 1 GiB container → LSAPI_CHILDREN ≈ 8
|
||||||
|
## 512 MiB → LSAPI_CHILDREN ≈ 3
|
||||||
|
##
|
||||||
|
## Idle-reduction knobs (the question that motivated this whole block):
|
||||||
|
## LSAPI_MAX_IDLE_CHILDREN=2 default was CHILDREN/2 (so 10/2=5)
|
||||||
|
## LSAPI_MAX_IDLE=60 default was 300 (5 min)
|
||||||
|
## Together: max 2 idle workers kept alive, anything idle >60s gets reaped.
|
||||||
|
## Trade-off: cold-start of an extra worker after idle reaping costs ~50-100ms
|
||||||
|
## on the first request to it. Worth it for shadowdao-sized low-traffic sites
|
||||||
|
## where the difference is "30 MB idle" vs "200 MB idle".
|
||||||
|
##
|
||||||
|
## memSoftLimit/memHardLimit: per-worker RLIMIT_AS catches a runaway PHP
|
||||||
|
## script before it hogs the whole pool's memory. Cgroup is still the host
|
||||||
|
## backstop (one-customer-per-container), but the per-worker cap protects
|
||||||
|
## the OTHER workers in the same pool from a bad-actor script. 1024M soft
|
||||||
|
## comfortably accommodates typical Divi/WooCommerce VSZ (~280-365 MB).
|
||||||
|
extProcessor lsphp {
|
||||||
|
type lsapi
|
||||||
|
address uds://tmp/lshttpd/lsphp.sock
|
||||||
|
maxConns ${LSAPI_CHILDREN}
|
||||||
|
env PHP_LSAPI_CHILDREN=${LSAPI_CHILDREN}
|
||||||
|
env LSAPI_MAX_IDLE_CHILDREN=2
|
||||||
|
env LSAPI_MAX_IDLE=60
|
||||||
|
env PHP_LSAPI_MAX_REQUESTS=500
|
||||||
|
env LSAPI_AVOID_FORK=200M
|
||||||
|
initTimeout 60
|
||||||
|
retryTimeout 0
|
||||||
|
persistConn 1
|
||||||
|
pcKeepAliveTimeout 30
|
||||||
|
respBuffer 0
|
||||||
|
autoStart 1
|
||||||
|
path /usr/local/lsws/lsphp${PHPVER}/bin/lsphp
|
||||||
|
backlog 100
|
||||||
|
instances 1
|
||||||
|
runOnStartUp 1
|
||||||
|
priority 0
|
||||||
|
memSoftLimit 1024M
|
||||||
|
memHardLimit 1500M
|
||||||
|
procSoftLimit 400
|
||||||
|
procHardLimit 500
|
||||||
|
}
|
||||||
|
|
||||||
## --- our vhost via vhTemplate (upstream's working pattern) ---
|
## --- our vhost via vhTemplate (upstream's working pattern) ---
|
||||||
## The template file is /usr/local/lsws/conf/templates/site.conf — written
|
## The template file is /usr/local/lsws/conf/templates/site.conf — written
|
||||||
## by create-vhost-litespeed.sh at the same time as this fragment.
|
## by create-vhost-litespeed.sh at the same time as this fragment.
|
||||||
|
|||||||
@@ -45,9 +45,12 @@ cp /usr/local/lsws/.conf/httpd_config.conf "$LSWS_CONF/httpd_config.conf"
|
|||||||
|
|
||||||
## Strip the stock blocks we replace. Use awk: easier than sed range-deletes
|
## Strip the stock blocks we replace. Use awk: easier than sed range-deletes
|
||||||
## to skip a NAMED block of arbitrary length terminated by a top-level `}`.
|
## to skip a NAMED block of arbitrary length terminated by a top-level `}`.
|
||||||
|
## extProcessor lsphp is stripped because the stock one hard-codes
|
||||||
|
## PHP_LSAPI_CHILDREN=10 regardless of container size — our appended
|
||||||
|
## extProcessor scales it from detect-memory-litespeed.sh.
|
||||||
awk '
|
awk '
|
||||||
BEGIN { skip = 0 }
|
BEGIN { skip = 0 }
|
||||||
/^listener HTTP \{/ || /^listener HTTPS \{/ || /^vhTemplate docker \{/ { skip = 1; next }
|
/^listener HTTP \{/ || /^listener HTTPS \{/ || /^vhTemplate docker \{/ || /^extProcessor lsphp\{/ || /^extProcessor lsphp \{/ { skip = 1; next }
|
||||||
skip && /^\}/ { skip = 0; next }
|
skip && /^\}/ { skip = 0; next }
|
||||||
!skip { print }
|
!skip { print }
|
||||||
' "$LSWS_CONF/httpd_config.conf" > "$LSWS_CONF/httpd_config.conf.new"
|
' "$LSWS_CONF/httpd_config.conf" > "$LSWS_CONF/httpd_config.conf.new"
|
||||||
@@ -58,7 +61,7 @@ SENTINEL="## ---- cac-litespeed append (do not edit below) ----"
|
|||||||
{
|
{
|
||||||
echo ""
|
echo ""
|
||||||
echo "$SENTINEL"
|
echo "$SENTINEL"
|
||||||
envsubst '${user} ${domain} ${vhost_map_aliases}' < "$TPL_DIR/httpd_config.tpl"
|
envsubst '${user} ${domain} ${vhost_map_aliases} ${PHPVER} ${LSAPI_CHILDREN}' < "$TPL_DIR/httpd_config.tpl"
|
||||||
} >> "$LSWS_CONF/httpd_config.conf"
|
} >> "$LSWS_CONF/httpd_config.conf"
|
||||||
|
|
||||||
## --- write our vhost template to /usr/local/lsws/conf/templates/site.conf ---
|
## --- write our vhost template to /usr/local/lsws/conf/templates/site.conf ---
|
||||||
|
|||||||
@@ -47,9 +47,16 @@ if [ "$AVAILABLE_MB" -lt 60 ]; then
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
## ---- LSAPI children (analogous to PHP_FPM_MAX_CHILDREN) ----
|
## ---- LSAPI children (analogous to PHP_FPM_MAX_CHILDREN) ----
|
||||||
## LSAPI is more memory-efficient than FPM; estimate 96 MB / worker
|
## Per the 2026-06-02 cac-litespeed memory-sizing finding (vantagehealth
|
||||||
## (vs 128 MB for FPM after the 2026-06-01 bump). Floor 2, cap 50.
|
## OOM-spawn loop at 512 MB cap): each lsphp worker carries ~115 MB
|
||||||
LSPHP_WORKER_ESTIMATE_MB=${LSPHP_WORKER_ESTIMATE_MB:-96}
|
## shmem-rss which is RSS-accounted per worker (vs cac-fpm's COW-shared
|
||||||
|
## fork model). Real-world worker budget ≈ 115 MB shmem + ~50-100 MB anon
|
||||||
|
## that scales with workload. 115 MB is the safe per-worker estimate for
|
||||||
|
## the divisor; floor at 2, cap at 50.
|
||||||
|
##
|
||||||
|
## Sub-512 MB containers are unsafe for dynamic WP on OLS per the memory
|
||||||
|
## note — the floor of 2 workers still applies but it'll be cap-marginal.
|
||||||
|
LSPHP_WORKER_ESTIMATE_MB=${LSPHP_WORKER_ESTIMATE_MB:-115}
|
||||||
|
|
||||||
calc_lsapi_children=$((AVAILABLE_MB / LSPHP_WORKER_ESTIMATE_MB))
|
calc_lsapi_children=$((AVAILABLE_MB / LSPHP_WORKER_ESTIMATE_MB))
|
||||||
if [ "$calc_lsapi_children" -lt 2 ]; then
|
if [ "$calc_lsapi_children" -lt 2 ]; then
|
||||||
@@ -64,13 +71,11 @@ fi
|
|||||||
## else the calculated value.
|
## else the calculated value.
|
||||||
LSAPI_CHILDREN=${LSAPI_CHILDREN:-${FPM_MAX_CHILDREN:-$calc_lsapi_children}}
|
LSAPI_CHILDREN=${LSAPI_CHILDREN:-${FPM_MAX_CHILDREN:-$calc_lsapi_children}}
|
||||||
|
|
||||||
## extprocessor mem limits — total LSAPI heap should fit AVAILABLE_MB with
|
## Per-worker mem limits (RLIMIT_AS) live in httpd_config.tpl now as
|
||||||
## some breathing room. Soft = budget/children, hard = soft * 1.5, both capped
|
## hard-coded 1024M soft / 1500M hard — those values comfortably fit
|
||||||
## at 2047 (OLS interprets > 2047 oddly in some 1.x builds).
|
## typical Divi/WooCommerce VSZ (~280-365 MB) while still catching a
|
||||||
LSAPI_MEM_SOFT=$((AVAILABLE_MB / LSAPI_CHILDREN))
|
## true runaway script. Cgroup remains the real backstop. The earlier
|
||||||
if [ "$LSAPI_MEM_SOFT" -lt 64 ]; then LSAPI_MEM_SOFT=64; fi
|
## AVAILABLE/CHILDREN formula was killing legitimate workers because
|
||||||
if [ "$LSAPI_MEM_SOFT" -gt 2047 ]; then LSAPI_MEM_SOFT=2047; fi
|
## it conflated VSZ (RLIMIT_AS) with RSS-budget arithmetic.
|
||||||
LSAPI_MEM_HARD=$((LSAPI_MEM_SOFT * 3 / 2))
|
|
||||||
if [ "$LSAPI_MEM_HARD" -gt 2047 ]; then LSAPI_MEM_HARD=2047; fi
|
|
||||||
|
|
||||||
export CONTAINER_MEMORY_MB LSAPI_CHILDREN LSAPI_MEM_SOFT LSAPI_MEM_HARD
|
export CONTAINER_MEMORY_MB LSAPI_CHILDREN
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ chmod 1777 /tmp/lshttpd
|
|||||||
## ---- memory + lsphp pool sizing ----
|
## ---- memory + lsphp pool sizing ----
|
||||||
# shellcheck source=/dev/null
|
# shellcheck source=/dev/null
|
||||||
source /scripts/detect-memory-litespeed.sh
|
source /scripts/detect-memory-litespeed.sh
|
||||||
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | LSAPI_CHILDREN=${LSAPI_CHILDREN} | memSoft=${LSAPI_MEM_SOFT}M memHard=${LSAPI_MEM_HARD}M | PHPVER=${PHPVER}"
|
echo "Container memory: ${CONTAINER_MEMORY_MB}MB | LSAPI_CHILDREN=${LSAPI_CHILDREN} | PHPVER=${PHPVER}"
|
||||||
|
|
||||||
## ---- self-signed cert (idempotent) ----
|
## ---- self-signed cert (idempotent) ----
|
||||||
mkdir -p /usr/local/lsws/conf/cert
|
mkdir -p /usr/local/lsws/conf/cert
|
||||||
|
|||||||
Reference in New Issue
Block a user