Bandwidth vs CPU: finding the real bottleneck
Work out whether your server is limited by network, CPU, memory or disk — and fix the right one.
A slow service is limited by exactly one thing at a time (sometimes two). Find it before spending money on the wrong resource.
The four candidates
CPU — compute-bound work: transcoding, builds, heavy PHP/Node, crypto.
Memory — caching, worker counts; running out causes swapping or OOM kills.
Disk I/O — databases and many small writes; a slow disk is a slow app.
Network — bandwidth or latency; media delivery and large transfers.
Diagnose it
uptime # load average vs core count -> CPU pressure?
free -h # swap in use -> memory pressure
vmstat 1 5 # si/so (swapping), wa/iowait (disk), cpu columns
iostat -x 2 # %util and await per disk -> disk saturation
iftop / nload # live network throughput
nproc # how many cores you actually haveInterpreting
Load > cores, CPU busy → CPU-bound. Optimise the code, or add CPU.
High
wa(iowait), CPU not busy → disk-bound. Faster storage, better indexes, or fewer writes.Swap in use (
si/so> 0) → memory-bound. Find the leak or add RAM.Network near the port/plan limit → bandwidth-bound. CDN, caching, or a bigger transfer allowance.
Everything low but still slow → look at the client path: DNS, TLS handshake, or an external dependency with a slow timeout.
The classics that look like the wrong thing
A slow site with idle CPU — often a missing database index (disk) or an unindexed query.
"High CPU" that is really I/O wait —
topshows CPU mostly inwa; adding vCPUs will not help.Buffering streams with plenty of headroom — could be the listener's connection, not your server.
Timeouts that are not load — an external API call with no timeout blocks a worker while resources sit idle.
Fix in the right order
Optimise first — indexes, caching, fewer round-trips, compression. Free wins.
Then resize the correct resource, not all of them.
Then re-measure — assumptions about bottlenecks are frequently wrong.
Related reading