Monitoring and managing microservices, the metrics that matter, distributed tracing, logging and monitoring tools, securing services, security patterns, service-to-service security with mTLS and tokens, database-per-service security, and failure-handling patterns — circuit breaker, bulkhead, retry with backoff.
Published September 25, 2026
These questions separate people who have run microservices from people who have only drawn them. Name the signals you'd watch (latency, errors, saturation), the tools that show them, and the patterns that stop one failure from spreading. Resilience4j and Micrometer are the standard Spring answers.
Short answer: With the three pillars of observability, plus automation:
Learn it in depth → Metrics & Monitoring
Short answer: Start with the golden signals for every service:
Key points to cover:
Learn it in depth → Alerting Strategy
Short answer: A trace follows one request across every service it touches. Each hop is recorded as a span, with timing and metadata, all linked by a shared trace ID that's propagated in headers (W3C traceparent). A trace shows exactly where the time went, and which service failed. Without it, debugging means guessing across dozens of log files.
Key points to cover:
Learn it in depth → Distributed Tracing
Short answer:
Learn it in depth → Centralized Logging
Short answer: Defence in depth:
Learn it in depth → Spring OAuth2 Basics
Short answer:
Learn it in depth → Service Mesh Basics
Short answer: mTLS encrypts the traffic, and lets each side verify the other's certificate. A service mesh can manage the certificates automatically. On top of that, send tokens: forward the user's JWT (or an exchanged token) so the downstream service can authorise the user, or use OAuth2 client credentials for service-to-service calls without a user. Add network policies, so only the allowed services can reach each other.
Common trap: plain HTTP inside the cluster "because it's internal". An attacker who gets into one pod can then read and forge traffic.
Short answer: It limits the blast radius. A compromised service can reach only its own data, with its own credentials. Each database gets permissions and encryption suited to its sensitivity (for example, a stricter setup for payments data), and access is easier to audit.
Key points to cover:
Short answer:
Learn it in depth → Why Microservices Fail
Short answer: A circuit breaker wraps calls to a dependency, and tracks their failures. It has three states:
@CircuitBreaker(name = "inventory", fallbackMethod = "stockUnknown")
public StockLevel stock(String sku) { return inventoryClient.stock(sku); }
private StockLevel stockUnknown(String sku, Throwable ex) {
return StockLevel.unknown(sku); // degrade gracefully: show "check availability" instead of an error page
}
resilience4j.circuitbreaker.instances.inventory:
sliding-window-size: 20
failure-rate-threshold: 50
wait-duration-in-open-state: 30s
permitted-number-of-calls-in-half-open-state: 3
Learn it in depth → Circuit Breaker with Resilience4j
Short answer: Like the watertight compartments in a ship's hull, a bulkhead isolates resources per dependency or per workload. Each gets its own limited thread pool, or its own cap on concurrent calls. Then a slow payment provider can occupy at most, say, 10 threads, and can't exhaust the whole request pool, so other features keep working.
resilience4j.bulkhead.instances.paymentProvider:
max-concurrent-calls: 10
max-wait-duration: 50ms
Learn it in depth → Bulkhead & Rate Limiting
Short answer: Retry re-attempts an operation that failed with a transient error (a timeout, a 503, a connection reset). Backoff waits longer between attempts (for example 200 ms, 400 ms, 800 ms: exponential), with random jitter, so thousands of clients don't retry in lockstep and overload a recovering service.
resilience4j.retry.instances.inventory:
max-attempts: 3
wait-duration: 200ms
enable-exponential-backoff: true
exponential-backoff-multiplier: 2
retry-exceptions: [ java.io.IOException, java.util.concurrent.TimeoutException ]
Common trap: retrying non-idempotent operations (charging a card) without an idempotency key, or retrying at every layer. Three layers × three retries = 27 calls per user request, a retry storm. Retry at one layer only, and combine retries with a circuit breaker.
Learn it in depth → Retry & Backoff Strategies
Q: What's the difference between liveness and readiness probes? A: Liveness asks whether the process is alive or stuck. Failing it restarts the pod. Readiness asks whether the pod can serve traffic right now. Failing it only removes the pod from load balancing, which is used during startup or when a dependency is unavailable.
Q: What is a correlation ID? A: An ID attached to a request at the edge, and propagated to every service and log line. It lets you gather all the logs for one user request. Trace IDs from distributed tracing now usually serve this purpose.
Q: What is an SLO? A: A Service Level Objective: a target for user-facing reliability, such as "99.9% of checkout requests succeed within 800 ms over 30 days". The unused error budget tells you how much risk (deploys, experiments) you can take.
Q: In what order should the resilience decorators wrap a call? A: Resilience4j's default aspect order, from outermost to innermost, is Retry → CircuitBreaker → RateLimiter → TimeLimiter → Bulkhead → the call. So each retry attempt goes through the circuit breaker, and an open circuit fails the attempts quickly.