How should I set Kubernetes CPU and memory requests and limits for Java services?
Asked by
MellowPine7
I'm trying to right-size resource settings for several Kubernetes services and keep them accurate over time. My current CPU requests are around 200โ500m, but steady-state usage is closer to 20m, which seems to be driving unnecessary node capacity. CPU limits are around 800โ1000m, and Java services sometimes start slowly or crash-loop because JVM startup needs a large burst for JIT compilation, class loading, and framework initialization. I also see occasional request latency that may be caused by CPU throttling.
Memory requests of roughly 600Miโ1000Mi seem to match actual usage. However, I'm questioning whether setting memory limits higher than requests is useful, since memory consumed above the request may remain allocatedโespecially with JVM heapsโand can increase the risk of node-level OOM pressure.
I'm considering lowering CPU requests to something closer to observed usage, setting a much higher CPU limit such as 3โ4 cores or removing the CPU limit entirely, and making memory requests and limits approximately equal. My main concern is whether a pod without a CPU limit could consume all available node CPU during a spike and starve other workloads. How do you handle this in production, particularly for Java services, and how do you continuously adjust the values?
Answers
A practical starting point is to use historical metricsโoften around the 90th or 95th percentileโfor requests, then adjust them as workload patterns change. Many teams omit CPU limits because throttling can hurt latency and startup performance. Keep alerts for sustained CPU or memory usage above the configured values, and periodically check whether the long-term average is far below the request so you can right-size again.
This is especially important for workers and queue consumers, whose usage can vary considerably. Vertical Pod Autoscaler recommendations or tools such as Goldilocks can help collect the data and suggest values, while automated right-sizing products can handle the recurring maintenance if you have many workloads.
Reply to this answer
Removing a CPU limit does not automatically let one pod permanently take over the node. CPU requests are used for scheduling and influence proportional CPU allocation under contention; workloads with requests have their requested capacity protected. Any unused CPU can then be shared during bursts, which is useful for JVM startup. Keep CPU requests high enough for the serviceโs real performance needs, thoughโusing only a tiny steady-state number may leave the pod with poor throughput during sustained load. For applications that dynamically size threads or worker pools based on available CPUs, make sure the JVM or runtime is configured with an appropriate CPU ceiling or cgroup-aware settings.
SilverRook56: The key distinction is that a request reserves scheduling capacity, while a CPU limit caps execution and can cause throttling. Removing the limit is usually safer for latency-sensitive services than setting it just slightly above the request, provided the node has sensible capacity planning and every important workload has an appropriate request.
Reply to this answer
For memory, setting the request equal to the limit is a common stability-focused choice. It prevents the pod from appearing to have inexpensive burst capacity that could contribute to node memory pressure and gives it the guaranteed QoS behavior many teams want. The application still needs a sensible heap limit and headroom for non-heap memory, because matching the container limit to observed heap usage too tightly can cause the JVM itself to hit the container limit.
Reply to this answer
Add your answer
Answers are reviewed before publication.
CedarOrbit19: If you need Kubernetesโ guaranteed QoS class, matching requests and limits is the stricter option, but it generally costs more because the scheduler has less room to overcommit the node.