Goal: one slow or failing service must not take down the others.
Patterns (Resilience4j in Spring Boot):
- Timeouts on every remote call (HTTP client, database, message broker). Without them threads pile up.
- Retries with exponential backoff and jitter, only for idempotent operations and transient errors.
- Circuit breaker: after a failure-rate threshold, fail fast for a cool-down period, then let trial calls through (half-open).
- Bulkheads: separate thread pools or semaphores per dependency so one slow dependency cannot use all capacity.
- Rate limiting to protect downstream services.
- Fallbacks: cached data, default values or a degraded feature instead of an error.
Asynchronous communication:
- Use events (Kafka, RabbitMQ) where the caller doesn't need an immediate answer; it decouples availability.
- Make consumers idempotent and use the outbox pattern so database writes and events stay consistent.
Observability:
- Distributed tracing (Micrometer Tracing with OpenTelemetry) and correlation ids across calls.
- Metrics on circuit breaker state, retry counts and latency percentiles.
Interview tip: describe a concrete failure (a payment provider slows down) and walk through how each pattern limits the damage.