CPU throttling: The container hit its CPU limit and is being paused by the kernel
A CPU limit is enforced by pausing the container whenever it exhausts its quota in each 100 ms period. Throttling produces latency spikes, not errors, so it is invisible unless you look for it directly.
Applies to: All Kubernetes versions, Linux nodes
What it means
CPU limits are implemented with the kernel's CFS bandwidth control: the container gets a quota of CPU time per period, and once it is used the container is stopped until the next period begins. The default period is 100 milliseconds, which means a container exceeding its quota early in a period stalls for the remainder of it — up to a 100 ms pause, repeatedly. Nothing fails and nothing is logged, so the only symptoms are latency, probe timeouts, and slow startups. This makes CPU limits qualitatively different from memory limits: exceeding a memory limit kills the container loudly, while exceeding a CPU limit degrades it silently.
Most common causes
- A CPU limit set lower than the workload's actual peak demand.
- A multi-threaded application whose parallelism exceeds its quota — eight threads under a one-CPU limit exhaust the quota in an eighth of the period.
- Startup being far more CPU-intensive than steady state, so the limit that suits normal operation cripples boot.
- Garbage collection bursts consuming the quota briefly but repeatedly.
- Limits copied from another workload without measurement.
- A runtime that sizes its thread pool from the node's CPU count rather than the container's quota.
How to diagnose it
- Read the throttling counters directly from the container's cgroup —
cpu.statreports throttled periods and total throttled time. - Compare throttled periods against total periods. A meaningful ratio confirms it, and a ratio near zero rules it out.
- Correlate latency spikes and probe timeouts with throttling rather than with the application's own metrics.
- Check whether the application sizes its thread pools from the node's CPU count: many runtimes read the host and ignore the cgroup quota.
- Test by raising or removing the limit temporarily and observing the latency change.
How to fix it
- Raise the CPU limit to cover peak demand, not average demand.
- Consider removing CPU limits entirely while keeping requests. This is a defensible choice: requests still guarantee a share, and without a limit a container can use spare capacity instead of being paused. The trade-off is less predictable neighbour behaviour.
- Configure the application's parallelism from the cgroup quota rather than from the node's CPU count.
- Give startup more headroom, since a limit sized for steady state can make boot pathologically slow.
- Raise probe timeouts on containers that are legitimately close to their limits.
Notes
CPU is a compressible resource — a container over its limit is slowed, not killed — which is why removing CPU limits is a reasonable option while removing memory limits is not. The two are often set together out of symmetry, and they behave nothing alike.
Related
- Insufficient cpu — No node has enough unreserved CPU
- Probe: timeout — The probe got no answer within its timeout
Sources
- Kubernetes documentation — Resource Management for Pods and Containers
- Kubernetes documentation — Quality of Service for Pods
- Kubernetes documentation — Assign CPU Resources to Containers and Pods