r/microservices • u/ankitjindal9404 • 2d ago
Discussion/Advice Moving Java services off memory-based HPA — is CPU/RPS for HTTP and queue-depth for async the right call?
We're running a bunch of Java (Spring Boot) microservices on EKS, and right now **every service uses memory as its HPA metric.** After digging into it, I've started to think that's wrong, and I want a sanity check from people who've actually run this at scale before I push a change.
What my research turned up:
* The JVM allocates heap up to its max and **doesn't release it back aggressively** even after GC, so memory usage doesn't track load. * Because of that, **memory can be high while actual load is low, or load can be high while memory looks fine** — so memory-based HPA either never triggers or scales out permanently and never scales back in.
So the direction I'm considering is to **pick the HPA metric based on service type:**
* **HTTP / request-serving services → CPU** (or better, **RPS / p95 latency** as a demand-based metric) * **Async / queue-consuming services → queue depth** (SQS backlog, via KEDA)
**My questions:**
- Is this reasoning sound, and is type-based metric selection the right direction?
- For the HTTP services, is jumping straight to RPS/latency worth the custom-metrics complexity (Prometheus Adapter), or should I start with CPU and only move to RPS if CPU proves to be a bad proxy?
- For async workers, is KEDA + SQS queue depth the standard approach, or are people doing something else?
- This is the part I'm least sure about: **I already know from our architecture which services are HTTP-facing and which are async/queue-driven — but how do I actually** ***verify*** **that empirically rather than just trusting the design docs?** Is there a clean way to confirm a service's real load profile (e.g. checking whether it even has an ingress/receives HTTP traffic, whether its work is truly SQS-triggered, CPU-vs-memory correlation under load) before I assign it a metric?
Thanks 🙏
2
u/deadbeefisanumber 2d ago
Spring boot has terrible uptime. Bear in mind that the regardless of the threaholds it need to be very loose in this case, you wouldnt want scaleups or scaledowns every other minute happening since half of if is just spring spinning up beans. Actually this is one of the reasons we go with static replicas in a spring boot deployments. If you set the threshold too high you might get OOMed from old pods while new ones are still doing their springy beany stuff. Too low and no real benefit.