In modern microservice architectures, managing system resources effectively ensures high availability and prevents cascading failures. Resilience4j, a lightweight fault-tolerance library, provides various patterns, including Circuit Breaker, Rate Limiter, Retry, and Bulkhead, to handle system resilience.
This tutorial will focus on the Bulkhead pattern in Spring Boot 3, which isolates critical system resources to prevent overload and ensure service continuity.
What is the Bulkhead Pattern?
The Bulkhead pattern is inspired by ship design, where a ship is divided into watertight compartments. If one compartment is compromised, the damage is contained within it. Similarly, a Bulkhead limits concurrent access to a service or resource in software systems, ensuring failures in one part don’t propagate and compromise the entire system.
In Resilience4j, Bulkhead can be implemented in two modes:
- Semaphore Bulkhead: Limits the number of concurrent calls to a service.
- ThreadPool Bulkhead: Allocates a separate thread pool for service calls, isolating resources.
Adding Resilience4j to Your Spring Boot 3 Application
First, add the Resilience4j dependency to your project.
Maven Dependency:
<dependency> <groupId>io.github.resilience4j</groupId> <artifactId>resilience4j-spring-boot3</artifactId> <version>2.2.0</version> </dependency>
Configuring Resilience4j Bulkhead
To use Bulkhead, define its configuration in the application.yml
file.
Basic Configuration:
resilience4j: bulkhead: instances: myBulkhead: maxConcurrentCalls: 5 # Maximum number of concurrent calls maxWaitDuration: 2s # Maximum time to wait for a free slot thread-pool-bulkhead: instances: myThreadPoolBulkhead: coreThreadPoolSize: 3 # Number of core threads in the pool maxThreadPoolSize: 10 # Maximum number of threads queueCapacity: 5 # Queue capacity before rejecting tasks
Implementing Bulkhead in a Service
Create a service class that simulates resource-intensive processing. We’ll demonstrate both Semaphore Bulkhead and ThreadPool Bulkhead.
Service Implementation:
import io.github.resilience4j.bulkhead.annotation.Bulkhead; import org.springframework.stereotype.Service; import java.util.concurrent.TimeUnit; @Service public class MyBulkheadService { @Bulkhead(name = "myBulkhead", fallbackMethod = "bulkheadFallback") public String processWithSemaphoreBulkhead() { simulateLongProcessing(); return "Processed by Semaphore Bulkhead!"; } private void simulateLongProcessing() { try { TimeUnit.SECONDS.sleep(2); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } } public String bulkheadFallback(Throwable t) throws Exception{ throw new Exception(t.getMessage()); } @Bulkhead(name = "myThreadPoolBulkhead", fallbackMethod = "bulkheadFallbackThreadPool", type = Bulkhead.Type.THREADPOOL) public CompletableFuture<String> processWithThreadPoolBulkhead() { return CompletableFuture.supplyAsync(() -> { simulateLongProcessing(); return "Processed asynchronously"; }); } // Fallback method for the ThreadPool bulkhead public CompletableFuture<String> bulkheadFallbackThreadPool(Throwable throwable) throws RuntimeException { throw new RuntimeException(throwable.getMessage()); } }
Creating a REST Controller
To expose these services, create a REST controller with endpoints for testing.
Controller Implementation:
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class MyBulkheadController { private final MyBulkheadService bulkheadService; public MyBulkheadController(MyBulkheadService bulkheadService) { this.bulkheadService = bulkheadService; } @GetMapping("/semaphore-bulkhead") public String testSemaphoreBulkhead() { return bulkheadService.processWithSemaphoreBulkhead(); } @GetMapping("/threadpool-bulkhead") public CompletableFuture<String> testThreadPoolBulkhead() { return bulkheadService.processWithThreadPoolBulkhead(); } }
Testing the Bulkhead Configuration
You can test the Bulkhead configuration using Postman or any other REST client.

Semaphore Bulkhead Test:
- Send multiple concurrent requests to the
/semaphore-bulkhead
endpoint. - Observe the behavior:
- The first five requests (as per
maxConcurrentCalls
) are processed successfully. - The remaining requests wait (up to
maxWaitDuration
) or fallback if no slot becomes available.




The test result shows that when the user reaches 13.2 VU, the client gets an error response from Bulkhead.
ThreadPool Bulkhead Test:
- Send multiple concurrent requests to the
/threadpool-bulkhead
endpoint. - Observe the behavior:
- The requests are queued and processed by a thread pool with a capacity defined by
coreThreadPoolSize
andqueueCapacity
. - Requests exceeding the pool capacity trigger the fallback method.





The test result shows that when the user reaches 17.4 VU, the client gets an error response from the Bulkhead thread pool.
Monitoring and Metrics
Spring Boot Actuator and Micrometer can be used to monitor Bulkhead metrics.
Enable Actuator:
Add the dependency:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
Expose the actuator endpoints in application.yml
:
management: endpoints: web: exposure: include: "*"
Metrics Endpoint:
Access the /actuator/metrics
endpoint to view Bulkhead metrics. Metrics like resilience4j.bulkhead.calls
, resilience4j.threadpool_bulkhead.queue.size
, etc., can help monitor performance.
http://localhost:8080/actuator/
{ "bulkheads":{ "href":"http://localhost:8080/actuator/bulkheads", "templated":false }, "bulkheadevents-bulkheadName-eventType":{ "href":"http://localhost:8080/actuator/bulkheadevents/{bulkheadName}/{eventType}", "templated":true }, "bulkheadevents":{ "href":"http://localhost:8080/actuator/bulkheadevents", "templated":false }, "bulkheadevents-bulkheadName":{ "href":"http://localhost:8080/actuator/bulkheadevents/{bulkheadName}", "templated":true } }
BulkheadEvents
{ "bulkheadEvents":[ { "bulkheadName":"myThreadPoolBulkhead", "type":"CALL_PERMITTED", "creationTime":"2024-11-28T16:14:18.850391300+07:00[Asia/Bangkok]" }, { "bulkheadName":"myThreadPoolBulkhead", "type":"CALL_FINISHED", "creationTime":"2024-11-28T16:14:20.856723+07:00[Asia/Bangkok]" }, { "bulkheadName":"myThreadPoolBulkhead", "type":"CALL_PERMITTED", "creationTime":"2024-11-28T16:14:22.043573100+07:00[Asia/Bangkok]" }, { "bulkheadName":"myThreadPoolBulkhead", "type":"CALL_FINISHED", "creationTime":"2024-11-28T16:14:24.046501100+07:00[Asia/Bangkok]" }, { "bulkheadName": "myBulkhead", "type": "CALL_FINISHED", "creationTime": "2024-11-28T16:28:35.983890700+07:00[Asia/Bangkok]" } ] }
Common Mistakes and Best Practices
1. Ignoring Fallbacks:
Always provide a fallback method to handle rejected requests in a graceful manner.
2. Misconfigured Limits:
Set realistic values for maxConcurrentCalls
and maxWaitDuration
(or thread pool size) based on your system’s capacity.
3. Overuse of ThreadPool Bulkhead:
Thread pools can isolate resources but may introduce latency. Use them judiciously.
4. Lack of Metrics Monitoring:
Regularly monitor Bulkhead metrics to adjust configurations for optimal performance.
Advanced Bulkhead Features
Combining Bulkhead with Other Patterns:
Resilience4j allows chaining Bulkhead with other patterns, such as Circuit Breaker or Retry. For example:
resilience4j: retry: instances: myRetry: maxAttempts: 3 waitDuration: 2s
Use annotations to combine them:
@Retry(name = "myRetry") @Bulkhead(name = "myBulkhead", fallbackMethod = "bulkheadFallback") public String combinedResiliencePatterns() { // Logic here }
Conclusion
The Bulkhead pattern is a tool to prevent overload and ensure resilience in microservice systems. With Spring Boot 3 and Resilience4j, you can implement and maintain applications with ease. The developer can build web services that handle high-load scenarios without compromising the availability of critical system resources and effectively monitor performance.
By following this tutorial, you’ve learned:
- What the Bulkhead pattern is.
- How to implement Semaphore and ThreadPool Bulkhead.
- How to test, monitor, and avoid common mistakes.
Start using Resilience4j Bulkhead today to improve the reliability and scalability of your Spring Boot applications!