SOFTWARE ARCHITECTURE / SYSTEM CONCEPT BRIEF

Bulkhead

The bulkhead pattern isolates resources so a failure or overload in one part of a system cannot consume everything and take down the rest.

IntermediatePhase 08 / Topic 15 of 17RequirementsTrade-offsFailure modes
01

Overview

The bulkhead pattern isolates resources so a failure or overload in one part of a system cannot consume everything and take down the rest. The name comes from ships, whose hulls are divided into watertight compartments: a breach floods one compartment, not the whole ship.

In software, bulkheads are separate thread pools, connection pools, concurrency limits, queues, or even separate deployments per dependency, feature, or customer tier. If the recommendations service hangs, only the resources dedicated to it are exhausted, and checkout keeps working.

Watertight compartments in a ship

If the hull is breached, water fills only one compartment and the ship stays afloat. Without compartments, one hole sinks everything.

02

When to use it

  • Services calling several dependencies of different criticality.
  • Multi-tenant systems where one tenant must not starve others.
  • Separating critical from non-critical workloads.
  • Protecting shared infrastructure (databases, thread pools).
03

Where it shows up in interviews

Dependency isolation

Recognize it when: a slow non-critical dependency exhausts threads.

  • Design a resilient product page
  • Design an API gateway
Tenant isolation

Recognize it when: one big customer's load hurts others.

  • Design a multi-tenant SaaS
  • Design a public API platform
04

Where it is used in real software

Hystrix thread pools

Netflix gave each dependency its own thread pool so one failing service could not starve others.

AWS cell-based architecture

Customers are split across independent cells, a large-scale bulkhead limiting blast radius.

Separate worker pools

Job systems use separate queues and workers for critical (payments) vs bulk (reports) work.

05

Key terms

Resource isolation
Dedicated pools or limits per consumer or dependency.
Semaphore bulkhead
Limit concurrent calls with a counter.
Thread-pool bulkhead
Separate thread pool per dependency.
Cell
Independent full stack serving a subset of users.
Noisy neighbor
A workload consuming shared resources unfairly.
06

How it works, step by step

  1. 1
    Identify shared resources

    Threads, connections, CPU, queues, databases.

  2. 2
    Classify by criticality

    Checkout vs recommendations; paying vs free tier.

  3. 3
    Allocate separate limits

    Pools or semaphores sized per dependency.

  4. 4
    Reject when full

    Fail fast with fallback instead of queuing forever.

  5. 5
    Monitor saturation

    Alert when a bulkhead is frequently full.

07

Shared vs bulkheaded thread pool

200 request threads; recommendations service hangs

Step 1 / 2
SetupThreads stuck on recommendationsCheckout requestsResult
Shared poolAll 200 over timeNo threads leftEntire service down
Bulkhead: max 20 concurrent recommendation calls20180 threads availableCheckout unaffected; recs fall back

NOWSetup: Shared pool | Threads stuck on recommendations: All 200 over time | Checkout requests: No threads left | Result: Entire service down

The bulkhead converts a total outage into a degraded feature.

08

Implementation

// Semaphore bulkhead: limit concurrent calls per dependency and reject when fullexport class Bulkhead {  private active = 0;  constructor(private readonly maxConcurrent: number, private readonly name: string) {}   async run<T>(fn: () => Promise<T>, fallback: () => T): Promise<T> {    if (this.active >= this.maxConcurrent) {      metrics.increment("bulkhead.rejected", { name: this.name });      return fallback();    }    this.active++;    try {      return await fn();    } finally {      this.active--;    }  }} const recommendationsBulkhead = new Bulkhead(20, "recommendations");const inventoryBulkhead = new Bulkhead(100, "inventory"); const recs = await recommendationsBulkhead.run(() => withTimeout(recsClient.similar(id), 200), () => []);
09

Complexity and performance

OverheadO(1) per call

Counter or pool.

Pool size~ rate x latency (Little's Law)

Plus headroom.

10

Trade-offs

Isolation vs utilization

Dedicated pools can sit idle while another pool is saturated; shared pools are more efficient but less safe.

Granularity

More bulkheads isolate better but require more tuning.

11

Variants and related techniques

Separate deployments

Run critical and non-critical endpoints on different instances.

Per-tenant rate limits and quotas

Bulkheads at the tenant level.

12

Common mistakes

  • Sizing bulkheads by guesswork.

    Fix: Use Little's Law with measured rates and latencies.

  • Unbounded queues in front of bulkheads.

    Fix: Queues hide saturation and add latency; bound them.

13

Interview questions

What is the bulkhead pattern?

Isolating resources, such as thread pools, connection pools, or concurrency limits, per dependency, feature, or tenant so that exhaustion in one area cannot take down the whole service.

How do you prevent one tenant from affecting others in a SaaS?

Per-tenant rate limits and quotas, separate queues or worker pools for large tenants, sharding or cells to place tenants in isolated infrastructure, and monitoring per tenant.

14

Practice problems

ProblemDifficultyWhat it trains
Implement a semaphore bulkheadEasyConcurrency limits.
Design tenant isolation for a multi-tenant APIHardCells and quotas.