Optimising web servers
Browser render and network dominate first; then memory, CPU, and I/O on the origin. Proxy buffering and X-Accel cut app concurrency.
Most perceived delay is browser render and network, not the application process. Fix page weight, caching headers, and compression before celebrating a faster app worker.
Server constraints
Once the client side is sane, the origin hits memory, CPU, or I/O:
- Memory ≈ per-process footprint × concurrent workers. Spare RAM on Linux is disk cache for static assets — starve it and reads get slower.
- CPU shows up when every request runs heavy app code end-to-end.
- I/O includes the database. Treat a remote MySQL host as latency you pay on the critical path; enable the slow query log and push joins/filters into indexed SQL.
Proxy buffering
A front proxy (Nginx was the usual choice here) accepts the client connection, buffers the request, and only then engages the app. On the way out it can trickle the response while the app worker exits. Shorter app lifetime → lower concurrency → less RAM for the same throughput.
For authenticated large downloads, prefer X-Accel-Redirect / X-Sendfile: the app authorises, then the web server streams the file.
Database from the web tier
Slow queries multiplied by request concurrency flatten sites. Index the predicates you write; do set operations in SQL rather than N+1 loops in the language. See also error handling for deadlock retries under load.