diagram.mmd — flowchart
Bulkhead Pattern flowchart diagram

The bulkhead pattern isolates a service's resources — thread pools, connection pools, semaphores — into separate partitions per downstream dependency, so that a slow or unresponsive dependency can only exhaust its own partition and cannot starve resources needed for other dependencies.

What the diagram shows

This flowchart illustrates a service (Service A) that calls three downstream dependencies: a Payment Service, an Inventory Service, and a Notification Service. Without bulkheads, all three share a single thread pool. A slow Payment Service response causes threads to pile up waiting, eventually exhausting the pool and causing Inventory and Notification calls to fail — even though those services are healthy.

With bulkheads applied:

1. Partition resources: each dependency gets its own dedicated thread pool (or semaphore limit). The sizes are tuned to the expected call volume and acceptable latency of each dependency. 2. Requests acquire from partition: when Service A needs to call a dependency, it acquires a slot from that dependency's partition. 3. Partition full: if the Payment partition is exhausted, only Payment calls are rejected. Inventory and Notification partitions are unaffected. 4. Fail fast on exhausted partition: the caller receives an immediate error rather than waiting, preventing thread accumulation.

Why this matters

The term comes from ship design: a ship's hull is divided into watertight compartments (bulkheads) so that flooding one compartment doesn't sink the whole ship. The same logic applies to software: one failing dependency shouldn't bring down the entire service.

Bulkheads pair naturally with Circuit Breaker Pattern — the circuit breaker detects sustained failures and stops sending requests, while the bulkhead limits the blast radius when the circuit hasn't opened yet. Together they form the core of defensive microservice design. See also Rate Limiting Architecture for external traffic controls.

Free online editor
Edit this diagram in Graphlet
Fork, modify, and export to SVG or PNG. No sign-up required.
Open in Graphlet →

Frequently asked questions

The bulkhead pattern isolates a service's resources — thread pools, connection pools, or semaphores — into separate partitions per downstream dependency. A slow or unresponsive dependency can only exhaust its own partition and cannot starve resources needed by other dependencies, preventing one failure domain from cascading into the entire service.
Each downstream dependency is assigned a dedicated resource partition sized to its expected call volume. When a request arrives, the caller acquires a slot from the appropriate partition. If the Payment Service partition is full, only Payment calls are rejected — Inventory and Notification partitions remain unaffected. Callers on an exhausted partition receive an immediate fail-fast error rather than waiting indefinitely.
Use bulkheads in any service that calls multiple downstream dependencies with different reliability profiles. It is particularly important when one dependency is notably slower or less reliable than the others — without isolation, that single dependency's latency will eventually exhaust shared resources and bring down all other calls.
The circuit breaker detects a pattern of sustained failures on a specific dependency and stops sending requests to it entirely — it operates at the call level over time. The bulkhead operates at the resource level in the present moment: it limits how many concurrent calls can be in-flight to a dependency regardless of their success rate. Bulkheads prevent resource exhaustion; circuit breakers prevent cascading failure propagation. Using them together provides defense in depth.
mermaid
flowchart TD A([Inbound Request to Service A]) --> B[Route to dependency type] B --> C{Payment Service call} B --> D{Inventory Service call} B --> E{Notification Service call} C --> F[Payment thread pool\nMax: 10 threads] D --> G[Inventory thread pool\nMax: 20 threads] E --> H[Notification thread pool\nMax: 5 threads] F --> I{Pool slot available?} G --> J{Pool slot available?} H --> K{Pool slot available?} I -- Pool exhausted --> L[Fail fast: Payment unavailable] I -- Slot acquired --> M[Call Payment Service] M --> N[Release thread slot] N --> O([Payment response returned]) J -- Pool exhausted --> P[Fail fast: Inventory unavailable] J -- Slot acquired --> Q[Call Inventory Service] Q --> R[Release thread slot] R --> S([Inventory response returned]) K -- Pool exhausted --> T[Fail fast: Notification unavailable] K -- Slot acquired --> U[Call Notification Service] U --> V[Release thread slot] V --> W([Notification response returned])
Copied to clipboard