The Bulkhead pattern isolates resources, such as thread pools, connection pools, or CPU/memory, per service or per dependency so that a failure or overload in one part of the system can't exhaust resources needed by the rest.
Key Points: • Each service, or even each downstream dependency within a service, gets its own dedicated thread pool or connection pool instead of sharing one global pool. • A cap on concurrent requests per dependency prevents one slow or failing downstream call from consuming all available threads. • Bulkheads are commonly implemented with libraries like Resilience4j's Bulkhead module, which limits concurrent calls to a named resource. • The pattern is named after ship bulkheads, which stop a hull breach in one compartment from flooding the entire ship. • Bulkheads work well alongside the Circuit Breaker pattern: bulkheads limit concurrency, circuit breakers stop calling a dependency that's already failing.
Example: If a Recommendations service call is slow, a bulkhead limits it to, say, 10 concurrent threads out of a much larger total pool, so even if Recommendations hangs, the Checkout flow still has threads available to serve other requests.
Code Example:
Bulkhead bulkhead = Bulkhead.of("recommendations",
BulkheadConfig.custom()
.maxConcurrentCalls(10)
.maxWaitDuration(Duration.ofMillis(500))
.build());
Supplier<List<Item>> decorated = Bulkhead.decorateSupplier(
bulkhead, recommendationsClient::fetch);Interview Tip: A concise interview answer is:
"I'd give each downstream dependency its own bounded pool of threads or connections, using something like Resilience4j's Bulkhead, so a slow or failing dependency can only exhaust its own slice of resources instead of starving the whole service. It pairs naturally with a circuit breaker for defense in depth."