Spring Boot Admin in Production: Monitor, Alert, and Tame JVM Meltdowns
Master Spring Boot Admin for production monitoring.
20+ years shipping production Java in banking & fintech. Written from production experience, not tutorials.
- ✓Java 17+ and Spring Boot 3.x (we'll use 3.2.1)
- ✓Familiarity with Spring Boot Actuator and its endpoints
- ✓Basic Kubernetes or Docker for deployment examples
- ✓Maven or Gradle build tool installed
- ✓A running Prometheus and Alertmanager instance (for alerting section)
• Spring Boot Admin (SBA) provides a web UI to monitor multiple Spring Boot applications via Actuator endpoints. • In production, you must secure SBA behind OAuth2 or VPN, configure health check groups, and set up alerting for heap dumps, GC pauses, and thread starvation. • Key features include real-time metrics, log viewer, environment management, and JMX integration. • Production pitfalls include overloading SBA server with too many apps, exposing sensitive endpoints, and ignoring SBA's own high availability. • Use SBA 3.1+ with Spring Boot 3.x for reactive monitoring and better memory profiling.
Think of Spring Boot Admin as a hospital's central monitoring station for your microservices. Each service wears a 'heart rate monitor' (Actuator) that sends vitals (metrics, health, logs) to a central nurse's station (SBA server). When a service's 'blood pressure spikes' (memory leak) or 'heart stops' (crash), the station alerts the on-call doctor (you). Without it, you'd have to check each patient's room individually—impossible at scale.
You've got 50 microservices running in Kubernetes, each a Spring Boot 3.2 app. Everything's fine until 3 AM when one service starts consuming 8GB of heap, GC pauses hit 10 seconds, and your pager goes off. Without centralized monitoring, you're SSHing into pods, running jstat and jmap blind, praying you find the culprit before the SLO burns down. Spring Boot Admin (SBA) is the answer—but only if you configure it for production, not just the demo setup from the official docs.
I've been using SBA since version 2.0 (2018) and have seen teams make the same mistakes: exposing admin UI without auth, polling every 5 seconds on 100 services, and ignoring SBA's own resilience. This guide is for senior engineers who need to deploy SBA in anger—covering alerting, JVM crash detection, memory leak hunting, and the gotchas that'll bite you in production.
We'll build a real monitoring stack with SBA 3.1.2, Spring Boot 3.2.1, and Prometheus alerting. You'll learn how to configure health groups for circuit breakers, set up webhook notifications for OOM errors, and use SBA's log viewer to tail logs across services without kubectl exec. By the end, you'll have a production-hardened setup that tames JVM meltdowns before they become incidents.
Setting Up Spring Boot Admin Server in Production
Start with SBA 3.1.2 (latest stable for Spring Boot 3.x). Don't use the embedded H2 database in production—it'll lose all history on restart. Use PostgreSQL 15 with Flyway migrations. Also, never expose the SBA server directly; put it behind a reverse proxy with OAuth2 (Keycloak or Okta).
Here's a production-ready pom.xml snippet. Note the exclusion of H2 and inclusion of PostgreSQL and Spring Security. The admin server itself is a Spring Boot app, so you need Actuator endpoints for its own health.
The client applications need spring-boot-admin-starter-client and must expose Actuator endpoints. Register clients via spring.boot.admin.client.url property. For Kubernetes, use service discovery with spring.boot.admin.discovery.enabled=true and spring.cloud.kubernetes.discovery.enabled=true.
What the Official Docs Won't Tell You
The official docs show a simple @EnableAdminServer and you're done. In production, you need to configure health groups to avoid cascading failures. For example, if a service's database is down, its health status becomes DOWN, and SBA marks it as critical. But what if the service has a circuit breaker for that database? You need a custom health indicator that reports UP if the circuit is open but the service is still serving cached data.
Also, the default polling interval is 10 seconds. For 100 services, that's 10 requests per second to SBA's API. Scale that to 500 services and you'll DDoS your own admin server. Set spring.boot.admin.monitor.default-timeout to 5000ms and spring.boot.admin.monitor.read-timeout to 2000ms. Use a dedicated thread pool for monitoring: spring.boot.admin.monitor.task-executor.pool-size=10.
Another hidden gem: SBA can expose sensitive Actuator endpoints (like /heapdump and /logfile) to anyone who can reach the UI. Always filter these with Spring Security: restrict /heapdump to ADMIN role only.
Alerting on JVM Meltdowns: Webhooks and Prometheus
SBA's built-in notification channels (email, Slack, PagerDuty) are okay, but for JVM meltdowns you need faster feedback loops. I configure SBA to emit metrics to Prometheus via Actuator's /actuator/prometheus endpoint, then set up Alertmanager rules for critical conditions.
What to alert on: heap usage > 80% (potential leak), GC pause time > 1 second (stop-the-world), thread count > 500 (starvation), and file descriptor usage > 90% (connection leak). Use SBA's custom notification filter to suppress alerts during maintenance windows.
Here's a Prometheus alert rule for heap usage. Note the for: 5m to avoid flapping. Also, SBA can send webhooks directly—configure spring.boot.admin.notify.webhook.url with a JSON payload that includes instance name, status, and timestamp.
for: 5m clause and saved the on-call team from PTSD.Hunting Memory Leaks with Heap Dumps and Log Viewer
When a service OOMs, you need the heap dump from before the crash. SBA can trigger a heap dump via /actuator/heapdump and download it. But if the JVM is already dead, you're out of luck. Configure -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp/dumps on each client JVM, then use SBA's log viewer to check for OOM errors in real-time.
SBA's log viewer streams logs from /actuator/logfile. In production, I use logback with JSON layout and configure SBA to filter by level. For memory leaks, look for repeated OutOfMemoryError: Java heap space or GC overhead limit exceeded.
Here's a Java snippet to programmatically trigger a heap dump when memory usage exceeds a threshold. This is useful for catching leaks before they crash the JVM.
High Availability for SBA Server Itself
SBA server is a single point of failure. If it goes down, you lose monitoring. Deploy at least 2 replicas behind a load balancer. But there's a catch: SBA uses in-memory event bus for notifications. With multiple replicas, each replica only sees events from its own clients. You need a shared event store.
Use Hazelcast or Redis Pub/Sub to synchronize events across replicas. Add spring-boot-admin-starter-hazelcast dependency and configure a Hazelcast cluster. Each SBA instance joins the same cluster and shares events.
Also, use a shared database (PostgreSQL) for persistent state. Configure spring.datasource.url to point to the same DB for all replicas. Flyway migrations ensure schema consistency.
Custom Health Indicators for Business Metrics
SBA's default health indicators (disk, DB, Redis) are system-level. For production, you need business health: is the payment gateway responding? Is the order queue backlogged? Create custom HealthIndicator beans that return UP/DOWN based on business logic.
For example, a health check that pings a downstream SOAP service every 30 seconds. If it fails, mark the service as DOWN but don't remove it from load balancer (use separate health group). Also, expose custom metrics via Micrometer: MeterRegistry.gauge("order.queue.depth", queue, Queue::size).
Here's a custom health indicator for a Kafka consumer lag. If lag exceeds 1000, it's DOWN. SBA will show this in the UI.
Securing SBA in a Multi-Tenant Environment
If you run SBA for multiple teams, each team should only see their own services. SBA doesn't support multi-tenancy out of the box. You have two options: run separate SBA instances per team (expensive) or use SBA's instance groups with custom security.
Instance groups allow you to tag services: spring.boot.admin.client.instance.metadata.group=payment-team. Then, in SBA's UI, you can filter by group. But the API still exposes all instances. To enforce authorization, implement a custom InstanceRepository that filters based on the logged-in user's group.
Use Spring Security's @PostFilter on the repository methods. Here's a simplified example.
@PreAuthorize on the REST controller. It was a pain to set up but saved us from a compliance nightmare.Debugging Production Issues with SBA's JMX and Environment
SBA's JMX tab lets you invoke MBeans remotely. In production, this is a double-edged sword. You can change log levels at runtime via ch.qos.logback.classic:name=default,type=Logger—great for debugging. But an attacker could also disable security logging. Restrict JMX access with -Dcom.sun.management.jmxremote.ssl=true and -Dcom.sun.management.jmxremote.authenticate=true.
The Environment tab shows all properties, including passwords if you're not using @Value with placeholders. Always mask sensitive properties with management.endpoint.env.keys-to-sanitize=password,secret,key,token. SBA respects this.
Here's how to change a log level via SBA's JMX from your code. Useful for automated debugging pipelines.
The 3 AM OOM Killer: When SBA Saved Our SLO
com.example:payment-sdk:2.1.0 library that didn't release HttpClient connections after each request, causing a slow heap leak. The leak rate was ~100MB per hour, hitting the 2GB limit after 4 hours.java.lang:type=Memory heap usage and triggered a webhook when usage exceeded 80%.- Don't trust third-party SDKs—always monitor heap usage with SBA's memory metrics.
- Set up proactive alerts on heap usage trends, not just absolute thresholds.
- Use SBA's heap dump download to analyze leaks without SSHing into pods.
ps aux | grep java./actuator/heapdump. Download and analyze with Eclipse MAT. Look for byte[] arrays or HashMap$Node as top consumers.Parallel GC or G1 Young Pause exceeding 1 second. Add JVM flags: -XX:+PrintGCDetails -XX:+PrintGCDateStamps -Xloggc:/tmp/gc.log.BLOCKED or WAITING threads. Check for connection pool exhaustion (e.g., HikariPool).ls -la /tmp/dumps/*.hprofjhat -port 7000 /tmp/dumps/heap.hprof| File | Command / Code | Purpose |
|---|---|---|
| admin-server-pom.xml | Setting Up Spring Boot Admin Server in Production | |
| SecurityConfig.java | @Configuration | What the Official Docs Won't Tell You |
| prometheus-alert.yml | groups: | Alerting on JVM Meltdowns |
| HeapDumpTrigger.java | @Component | Hunting Memory Leaks with Heap Dumps and Log Viewer |
| application-ha.yml | spring: | High Availability for SBA Server Itself |
| KafkaHealthIndicator.java | @Component | Custom Health Indicators for Business Metrics |
| SecuredInstanceRepository.java | @Repository | Securing SBA in a Multi-Tenant Environment |
| LogLevelChanger.java | @Component | Debugging Production Issues with SBA's JMX and Environment |
Key takeaways
Interview Questions on This Topic
How does Spring Boot Admin discover client applications?
Frequently Asked Questions
20+ years shipping production Java in banking & fintech. Written from production experience, not tutorials.
That's Spring Boot. Mark it forged?
4 min read · try the examples if you haven't