✅ What is the Bulkhead Pattern?
The Bulkhead pattern isolates different parts of your application so that a failure in one part does not bring down the whole system — just like watertight compartments in a ship.
In microservices, this usually means isolating:
-
Different external calls (like DB, REST APIs),
-
Or threads for different tasks.
✅ How to Implement Bulkhead Pattern in Spring Boot
We can implement Bulkhead using Resilience4j – a fault-tolerance library designed for Java 8 and functional programming.
๐ ️ Step-by-Step Implementation
1. Add Resilience4j Dependencies
2. Basic Bulkhead Usage Example (Thread Pool Bulkhead)
❗Scenario: A method making an external REST API call is bulkheaded.
import io.github.resilience4j.bulkhead.annotation.Bulkhead;
import org.springframework.stereotype.Service;
@Service
public class ExternalCallService {
@Bulkhead(name = "externalApiBulkhead", type = Bulkhead.Type.THREADPOOL)
public String callExternalService() {
// Simulated external service call
return "Success from external service";
}
}
3. Configure Bulkhead Properties in application.yml
resilience4j:
bulkhead:
instances:
externalApiBulkhead:
max-concurrent-calls: 5
max-wait-duration: 100ms
thread-pool-bulkhead:
instances:
externalApiBulkhead:
core-thread-pool-size: 4
max-thread-pool-size: 8
queue-capacity: 20
keep-alive-duration: 30s
4. Add Fallback Method (Optional)
You can add fallback with @Bulkhead
using Spring's @Recover
or use @Retry
or @CircuitBreaker
with it too.
@Bulkhead(name = "externalApiBulkhead", fallbackMethod = "fallbackMethod")
public String callExternalService() {
// ...
}
public String fallbackMethod(Throwable t) {
return "Service temporarily unavailable";
}
5. Monitoring with Actuator
If you added Spring Boot Actuator:
management:
endpoints:
web:
exposure:
include: resilience4j.bulkhead
You can now hit this endpoint to monitor:
GET /actuator/resilience4j/bulkhead
✅ When to Use Which Type?
Type | Use When... |
---|---|
Semaphore (default) | You want simple thread isolation. |
ThreadPool | You want to run the method asynchronously in separate thread pool. Better control for latency issues. |
๐ Real Use Case: Calling Another Microservice
@Bulkhead(name = "userServiceBulkhead", type = Bulkhead.Type.THREADPOOL)
public UserDto getUserById(String userId) {
return webClient.get()
.uri("http://user-service/users/{id}", userId)
.retrieve()
.bodyToMono(UserDto.class)
.block();
}
If you're building a microservice architecture and using WebClient, Feign, or RestTemplate, you can wrap your service calls with Resilience4j Bulkhead to prevent cascading failures and resource exhaustion.
๐ Summary
-
Use Resilience4j for implementing Bulkhead in Spring Boot.
-
Protect your microservices from overloading or crashing due to dependencies.
-
Combine with other patterns like Circuit Breaker and Retry for robust fault-tolerance.
How is the Bulkhead pattern different from Resilience (or Resilience4j in general)?