PHP
Managed PHP-FPM pools over FastCGI, front controller and PATH_INFO, or an external FastCGI endpoint.
1.86× nginx 1.31.6, same PHP-FPM pool. Varies run to run; under investigation.
Linux · Rust · Adaptive Runtime
A Linux web and application server in Rust that adds web-tier capacity only when the web tier is the bottleneck.
Explore the architecture →class=WebTierSaturated action=None reason="pressure 0.79; at max_instances 3"
Three instances on three CPUs: 143.2k req/s, p99 14 ms, zero errors. At max_instances the controller logs the reason instead of acting.
Measured: D5 burst, idle to 1024 connections, zero errors. Pressure bars and values inside log lines are illustrative.
nginx 1.31.6 · TLS + HTTP/2 small file
nginx 1.31.6 · response cache hits
nginx 1.31.6 · fixed in-memory response
1.37× nginx 1.31.6 in the tested TLS + HTTP/2 small-file workload and 1.93× on cache hits. Behind: Fixed response 0.92×, Reverse proxy 0.98×, Python (uvicorn) 0.93×. Same bare-metal host, same pinned cores for every server.
Full results and methodology →“Every N requests, start another instance” is wrong whenever the application behind the server is the limit. The ScalWS controller first decides which tier is saturated, and only a saturated web tier may act.
WebTierSaturated
PressureScore above 0.75, driven by CPU together with event-loop lag. No application at its CPU allotment.
ScaleOut within min, max, memory and cooldown limits.
PhpSaturated · NodeSaturated · PythonSaturated
The application uses at least 90 % of its CPU allotment. Even if the web tier is busy too, more instances would not raise throughput.
None, plus a logged recommendation for the operator.
MemoryPressure · ConnectionPressure · InsufficientEvidence
Low free memory, many requests in flight with idle CPUs, or too few samples.
None, with the reason in the log.
Measured in front of PHP-FPM on one CPU: 13.3k, 15.4k and 15.8k req/s with 1, 2 and 3 instances. Efficiency 0.58 and 0.40. ADR-0034
Instances share each listener through the kernel’s SO_REUSEPORT group and terminate TLS themselves. scalws-controller watches their metrics and runs their lifecycle. If it stops, instances keep serving.
Control plane and data plane →control plane
data plane
Bursts from idle to 1024 connections, three in a row, zero errors, autoscaling in web-tier mode with one CPU per instance. Each step adds a CPU. With the same CPUs, one larger instance does about as well: 0.92× to 1.14× across web-tier scenarios. Multi-instance buys the ability to add and remove capacity, not more work per CPU.
Scaling data →Spawned with an id, a CPU set and a configuration generation. Bound, not listening.
Configuration prepared, runtimes and caches initialised.
Readiness passed. Still no traffic.
Joins the SO_REUSEPORT group. New connections arrive.
Listeners close first, queued connections migrate, in-flight requests finish.
Drain testing found and fixed four defects that also affected a single instance on every SIGTERM. Lifecycle, generations and recovery →
Experimental and opt-in at build time: HTTP/3 and eBPF accounting. Experimental and opt-in in the configuration: the own HTTP/1 server and upstream client (the default stays hyper). The multi-node control plane is designed (ADR-0021), not built. .htaccess support is a subset, not Apache compatibility.
Managed PHP-FPM pools over FastCGI, front controller and PATH_INFO, or an external FastCGI endpoint.
1.86× nginx 1.31.6, same PHP-FPM pool. Varies run to run; under investigation.
Supervised processes, one socket each, round-robin over ready workers. Or any upstream.
1.00× nginx 1.31.6, application-bound. OpenLiteSpeed is ahead (0.93×).
ASGI and WSGI through uvicorn, hypercorn or gunicorn, with virtualenvs.
0.93× nginx 1.31.6, same uvicorn server, application-bound.
Supervised with readiness, crash backoff, restart-loop detection and graceful drain. Under the Adaptive Runtime controller, application tiers must be external endpoints: managed pools are refused so instances do not each start their own.
Signed apt repository for Ubuntu 24.04+ and Debian 13+ (amd64). scalwsctl check runs the exact prepare path a reload would. Building from source is in the README.
Getting started →curl -fsSL https://scalws.com/apt/scalws-archive-keyring.gpg \
-o /usr/share/keyrings/scalws-archive-keyring.gpg
echo 'deb [signed-by=/usr/share/keyrings/scalws-archive-keyring.gpg] https://scalws.com/apt stable main' \
> /etc/apt/sources.list.d/scalws.list
apt update && apt install scalws
scalwsctl check && systemctl enable --now scalwsd