The Service-Graph Version of the Problem
one service, many dependencies, shared execution resources:
[orders] threads(100) ──► payments, inventory, email,
fraud-check, legacy-shipping-API
legacy-shipping hangs (it does that):
60 threads stuck waiting → checkout starves → revenue path
hostage to the flakiest dependency. again.
BULKHEADS at microservice granularity:
pool PER DEPENDENCY so each can only hurt itself.
The Isolation Layers
LAYER 1 — within-service pools:
[orders]
pool-payments(30) pool-inventory(20)
pool-email(10) pool-legacy-shipping(15)
one pool saturating ≠ others starving ✓
LAYER 2 — instance-level (k8s):
resource requests/limits per pod; node affinity for
batch vs serving workloads; separate node pools
LAYER 3 — service-level:
heavyweight/risky components as SEPARATE services
entirely (report-generation service ≠ checkout service)
= blast-radius bulkheading via boundaries
LAYER 4 — multi-tenant quotas:
per-tenant concurrency/memory caps inside services;
one giant customer cannot consume the neighborhood
Sizing From Demand Math
per-pool arithmetic (bulkheads lesson applied):
pool-payments:
peak 200 rps × p99 200ms ≈ 40 concurrent + burst → 50 slots
pool-legacy-shipping:
known-slow: cap at 15; queue overflow sheds with fallback
(its SLA is "best effort" by design)
principles restated for graphs:
□ critical-path pools sized FIRST and protected
□ flaky dependencies get SMALL pools + fast fallbacks —
smallness IS the protection
□ total ≤ capacity; no overcommit fiction
□ per-pool saturation metrics alertable
| Without graph bulkheads | With |
|---|---|
| any dep can starve all | contained per compartment |
| ”which dependency ate the threads?” forensics | per-pool attribution instant |
| slow deps take critical paths hostage | they shed into their own queue |
Interaction With Other Patterns
bulkheads + circuit breakers compose deliberately:
pool full → stop ISSUING calls into it (backpressure)
breaker on that dependency trips under failure-rate
→ pool drains instantly into fallbacks
→ capacity returns to serve OTHER dependencies
sequence during an incident:
legacy-shipping slows → its POOL fills (contained)
→ its BREAKER trips (fast-fail)
→ orders keeps checking out on other pools ✓
neither pattern suffices alone: breakers without pools
still let one dep consume everything while failing;
pools without breakers hold doomed requests till timeout.
Interview Framing
“One slow third-party API degrades your entire order flow” scored answer: per-dependency pool diagram with sizing math shown for two pools, small-cap-for-flaky-deps principle stated, breaker+pool composition sequence narrated through an incident, k8s/tenant layers mentioned for completeness. Graph-bulkhead questions check whether isolation thinking extends from single processes to service topologies — draw the pools, don’t just name them.
Premium Content
Unlock Bulkhead in Microservices and all premium lessons with a subscription.
All premium lessons
Ad-free experience
Priority support
From ₹199.99/year — See plans