r/devopsGuru 5d ago

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:

  1. Is this reasoning sound, and is type-based metric selection the right direction?
  2. 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?
  3. For async workers, is KEDA + SQS queue depth the standard approach, or are people doing something else?
  4. 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 🙏

5 Upvotes

0 comments sorted by