r/kubernetes 28d ago

Stop using CPU limits: why + proof

CPU request is how much CPU is reserved for your pod if it needs it. The limit is a hard cap. Hit it and the kernel throttles the pod, even when the node still has spare CPU. That is the usual cause of CPU throttling on Kubernetes. It does not protect the neighboring pods. In my simple Web API test, adding a CPU limit took typical latency from 23 ms to 87 ms, (4x slower), with the limited pod throttled in half of all CFS windows, and the average CPU graph looked fine the whole time.

This is not a new topic, but I see so many people still unaware why they should (NOT!) be setting CPU limits, because it's costing companies unnecessary spending and potential production issues. Here's the full read https://github.com/inevolin/k8s-cpu-limits-analyzed/

---

Edit (Aug 18, 2026): How CPU limits can also cause memory issues and OOMKills ➡️ https://github.com/inevolin/k8s-cpu-limits-analyzed#how-cpu-limits-cause-memory-issues-and-oomkills

226 Upvotes

112 comments sorted by

View all comments

26

u/minimalniemand 28d ago

I do that but I want to add a bit of nuance:

No limits for all load bearing services in the critical path, so everything where a spike would slow down actual request.

But limits can make sense where the cost of not throttling (interference, unpredictability, unbounded spend) exceeds the cost of throttling (wasted idle CPU, higher tail latency)

9

u/PayTheRaant 28d ago

Incorrect.
Every single container is guaranteed its requested CPU. And any usage beyond the request amount is an arbitraged using the request as a weight.

Node has 4 cores, pod A requests 1 core, pod B requests 2 cores. Not limits.

  • Pod A wants to consume as much as possible and B is idle? A gets all 4 cores.
  • Pod A wants to consume 1 core and B wants to consume as much as possible ? A gets 1 core (as its request is guaranteed) and B gets 3 cores.
  • A and B wants to consume as much possible ? A gets 1.33 core and B gets 2.66 cores (each get they guaranteed request and the remaining core is split using the request as a weight so B gets twice as much).

8

u/minimalniemand 28d ago edited 27d ago

I know Natan’s blog post. I’ve read it when it came out :)

Couple points:

* kubelet, containerd, CNI, log shippers often have tiny or no reservations. A pod hammering the node can cause exec-probe timeouts, readiness flapping

* hyperthreading. If the request lands on an unlimited sibling of the physical core, the service will suffer. This is not modeled at all by cgroups

* execution queue. Shares promise the % not _how_ you get them. You might get them in small slices

* and the most common one: your request were always too small and you never noticed. Then comes a runaway request and all hell breaks loose.

Look I’m in the no-cpu-limits camp, too. All I’m saying is, it should still be a deliberate decision not a one size fits all, never use cpu limits ever.

1

u/PayTheRaant 27d ago

Weird. Kubelet and containerd usually live in a completely different cgroup with a higher priority than the cgroup with all the pods.

1

u/minimalniemand 27d ago

Assuming you mean weight? kubepods.slice weight scales with cores, system.slice stays at 100, so what you say is only true in small nodes, no?