Identify whether CPU is the limiting resource by comparing load, wait and I/O metrics.
Distinguishing a CPU-bound bottleneck from an I/O-bound one from simple overload matters because the fix differs for each: sustained %user+%system above 80% points to genuinely CPU-hungry workloads (needing more cores, code optimization, or horizontal scaling); %iowait above 20% points to processes blocked waiting on disk or network I/O (needing faster storage, more caching, or async I/O); and load average exceeding roughly 2× core count indicates more runnable/blocked tasks queued than the system can service, regardless of which resource is the root cause.
Bottleneck thresholds
CPU-bound if (user% + system%) > 80; I/O-bound if iowait% > 20; overloaded if load_avg > 2 × cores
A CPU bottleneck (high user+system time) means the CPUs themselves are saturated doing work. A high load average can occur even with idle CPUs if many processes are blocked waiting on I/O (uninterruptible sleep) rather than actually running — load average counts both runnable and I/O-blocked tasks, so it doesn't by itself distinguish the cause.
iowait specifically measures CPU idle time while waiting for outstanding I/O to complete, so it can also spike from network filesystem latency (NFS, network block storage) or even swap activity under memory pressure — not exclusively local disk hardware. Correlate with `iostat -x` and `vmstat` to pin down the actual I/O source.
They're reasonable general-purpose rules of thumb, not hard physical limits — some latency-sensitive workloads want alerts well below 80% CPU, while some batch/background systems tolerate load average well above 2× cores. Treat them as a starting point and tune based on your workload's actual latency requirements.