Bird
Raised Fist0

Bulkhead Pattern - Isolating Failures to Contain Blast Radius

HLDmediumInterview freq: medium
Choose your preparation mode4 modes available
🏗️
Bulkhead Pattern - Isolating Failures to Contain Blast Radius
Isolate failures in distributed systems to prevent cascading outages by partitioning resources.
mediumMicroservices InfrastructureFreq: medium
⚙️
Functional Requirements
  • Isolate failures in one microservice or resource pool to prevent cascading failures across the system.
  • Limit resource consumption (threads, connections, memory) per service or tenant to contain blast radius.
  • Provide graceful degradation or fallback behavior when a bulkhead segment is overwhelmed or fails.
  • Support dynamic configuration of bulkhead limits per service or resource type.
  • Expose monitoring and alerting on bulkhead health and saturation metrics.
  • Allow partial system availability even if some bulkheads are fully saturated or failed.
📊
Non-Functional Requirements
  • Support 2 billion daily active users (DAU) with peak write QPS of ~925K messages/sec.
  • Ensure 99.99% system availability with failure isolation to prevent cascading outages.
  • Maintain 100ms P99 latency for critical API calls under normal load.
  • Bulkhead resource limits must prevent resource exhaustion under 10x peak load spikes.
  • Monitoring and alerting latency must be under 1 minute for bulkhead saturation events.
❓
Clarifying Questions to Ask
  • What types of resources are we isolating? (threads, connections, CPU, memory, etc.)
  • Are bulkheads applied per microservice, per tenant, or per resource type?
  • What fallback or degradation behavior is expected when a bulkhead is saturated?
  • Is the system deployed on Kubernetes, VMs, or bare metal? How does that affect resource isolation?
  • What monitoring and alerting tools are currently in use or preferred?
  • Are there SLAs or SLOs tied specifically to bulkhead isolation and failure containment?
Out of Scope
✗ Designing the entire microservices architecture or service mesh.
✗ Implementing circuit breakers or retry policies (only mention as complementary).
✗ Detailed security or authentication mechanisms.
✗ Data storage schema design unrelated to bulkhead isolation.
📌
Assumptions
  • 2 billion DAU generating 40 messages per user per day on average.
  • Average message size is 100 bytes.
  • Peak write load is 10x average load during traffic spikes.
  • Read QPS is 3x write QPS due to analytics and user queries.
⚡
QPS Calculation
write qps2,000,000,000 × 40 / 86,400 ≈ 925,926 msg/sec
peak write qps925,926 × 10 = 9,259,260 msg/sec
read qps925,926 × 3 = 2,777,778 queries/sec
💾
Storage Estimate
daily storage gb(2,000,000,000 × 40 × 100) / (1024^3) ≈ 7,450 GB/day
retention days30
total storage gb7,450 × 30 = 223,500 GB
with replication 3x223,500 × 3 = 670,500 GB
🖥️
Server Estimate
api gateway serversAssuming 10,000 req/sec per server, need 925,926 / 10,000 ≈ 93 servers
bulkhead worker poolsEach worker pool limited to 500 concurrent threads, need 9,259,260 / 500 ≈ 18,519 workers distributed across clusters
🏗️
Architecture Diagram
Architecture Diagram
+----------------------+
|      API Gateway      |
+----------+-----------+
           |
+----------+-----------+
| Bulkhead Router/Load |
|      Balancer        |
+----------+-----------+
    |          |         |
+---+--+  +----+----+ +--+-------+
|Bulkhd |  | Bulkhd  | | Bulkhd   |
| Pool A|  | Pool B  | | Pool C   |
+---+---+  +----+----+ +----+-----+
    |          |          |
+---+----+ +---+-----+ +--+-------+
|Microserv| |Microserv| |Microserv|
|InstanceA| |InstanceB| |InstanceC|
+---------+ +---------+ +---------+
    |          |          |
+---+----------+----------+---+
|       Shared Data Store      |
+-----------------------------+
🧩
Components
API Gateway
Entry point for client requests, routes to appropriate bulkhead pools.
Why thisNginx with Lua scripting for high throughput routing and dynamic bulkhead-aware load balancing.
Why notAWS ALB lacks fine-grained control over bulkhead routing and resource isolation.
Bulkhead Router/Load Balancer
Routes requests to isolated bulkhead pools based on service/resource type and tenant.
Why thisEnvoy proxy supports dynamic routing and circuit breaking with per-cluster resource limits.
Why notHAProxy lacks native support for dynamic bulkhead isolation and telemetry integration.
Bulkhead Pools
Isolated thread/connection pools per microservice or tenant to limit resource blast radius.
Why thisKubernetes namespaces with resource quotas and pod anti-affinity enforce isolation at container level.
Why notSingle shared thread pool risks cascading failure due to resource exhaustion.
Microservice Instances
Business logic services running within bulkhead pools, isolated by resource limits.
Why thisDocker containers orchestrated by Kubernetes enable resource isolation and scaling per bulkhead.
Why notMonolithic deployment lacks isolation, causing cascading failures.
Shared Data Store
Stores persistent data accessed by microservices, designed for high availability and partition tolerance.
Why thisApache Cassandra provides linear scalability and fault tolerance with tunable consistency.
Why notPostgreSQL requires complex manual sharding and does not scale linearly at 9M writes/sec.
Monitoring & Alerting System
Collects bulkhead saturation metrics and triggers alerts for failures or resource exhaustion.
Why thisPrometheus with Alertmanager supports real-time metrics collection and alerting with <1 min latency.
Why notCloudWatch has higher latency and less flexibility for custom bulkhead metrics.
🔄
Data Flow
1
Client → API Gateway
Send request
Client sends request to API Gateway which acts as entry point.
2
API Gateway → Bulkhead Router/Load Balancer
Route request
Gateway routes request based on service and tenant to appropriate bulkhead pool.
3
Bulkhead Router/Load Balancer → Bulkhead Pool
Assign request to isolated resource pool
Request assigned to a bulkhead pool with limited threads/connections.
4
Bulkhead Pool → Microservice Instance
Process request
Microservice instance processes request within resource limits.
5
Microservice Instance → Shared Data Store
Read/Write data
Microservice reads or writes persistent data with fault tolerance.
6
Shared Data Store → Microservice Instance
Return data
Data returned to microservice after storage operation.
7
Microservice Instance → Bulkhead Pool
Return response
Response sent back through bulkhead pool.
8
Bulkhead Pool → API Gateway
Return response
Bulkhead pool returns response to API Gateway.
9
API Gateway → Client
Send response
API Gateway sends response back to client.

Practice

(1/5)
1. In a cache stampede prevention system, at Step 4 the Cache Rebuilder checks if a distributed lock is held before regenerating the cache. What happens if the lock is already held by another process?
easy
A. The Cache Rebuilder immediately regenerates the cache anyway, risking duplicate work
B. The Cache Rebuilder waits or returns stale data until the lock is released
C. The Cache Rebuilder deletes the cache key to force a fresh fetch next time
D. The Cache Rebuilder escalates the request to the backend synchronously

Solution

  1. Step 1: Trace Cache Rebuilder behavior at Step 4

    If the distributed lock is held, another process is regenerating the cache.
  2. Step 2: Understand correct handling

    The Cache Rebuilder waits or serves stale data to avoid duplicate regeneration and backend overload.
  3. Final Answer:

    Option B -> Option B
  4. Quick Check:

    Waiting or serving stale data prevents duplicate cache rebuilds [check]
Hint: Lock held -> wait or serve stale, no duplicate rebuilds [OK]
Common Mistakes:
2. If the Kafka broker cluster goes down unexpectedly, what exactly breaks in the message delivery pipeline?
medium
A. Producers receive errors and messages are lost if not retried; consumers stop receiving new messages causing delivery stalls
B. Consumers continue reading cached messages but new messages from producers are lost until broker recovers
C. Producers block indefinitely waiting to write messages, causing backpressure
D. Messages are duplicated because brokers resend uncommitted messages after restart

Solution

  1. Step 1: Trace producer behavior on broker failure

    Producers get errors on send; without retries, messages are lost. They do not block indefinitely (A).
  2. Step 2: Trace consumer behavior

    Consumers cannot fetch new messages; cached messages may be consumed but no new delivery occurs, causing stalls. Duplication (D) is prevented by offset commits.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Broker failure causes producer errors and consumer stalls, risking message loss [check]
Hint: Broker down -> producer errors, consumer stalls, possible message loss [check]
Common Mistakes:
3. For a multiplayer online game requiring real-time position updates with minimal delay, which transport protocol and design choice best balances speed and reliability?
medium
A. Use UDP without any reliability mechanism to maximize speed
B. Use TCP exclusively to ensure all packets arrive in order
C. Use UDP with application-level sequence numbers and selective retransmission
D. Use TCP with aggressive Nagle's algorithm tuning to reduce latency

Solution

  1. Step 1: Analyze game requirements

    Real-time position updates require low latency but some reliability to avoid inconsistent state.
  2. Step 2: Evaluate protocol trade-offs

    UDP provides low latency; adding application-level sequence numbers and selective retransmission balances speed and reliability.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    UDP + app-level reliability fits real-time game updates [check]
Hint: UDP + app reliability balances speed and correctness [check]
Common Mistakes:
4. Without a rate limiter in place, what exactly happens when a sudden traffic spike occurs on a backend service?
medium
A. The backend service crashes or becomes unresponsive, causing client requests to time out or fail
B. The backend service rejects requests gracefully with error codes indicating overload
C. The backend service automatically scales up instantly to handle the spike
D. The backend service queues all requests, causing increased latency but no failures

Solution

  1. Step 1: Understand backend behavior without rate limiting

    Without rate limiting, traffic spikes overwhelm backend, causing resource exhaustion and crashes or unresponsiveness.
  2. Step 2: Eliminate incorrect failure modes

    Automatic instant scaling (C) is unrealistic; graceful rejection (D) requires rate limiting; queuing all requests (A) leads to resource exhaustion and eventual failure.
  3. Final Answer:

    Option A -> Option A
  4. Quick Check:

    Spike without limiter -> backend crash or unresponsiveness [check]
Hint: No limiter -> spike crashes backend, causing timeouts [check]
Common Mistakes:
5. At 10x scale, which component in a real-time chat system implementing CAP theorem fails first and why?
hard
A. The database fails first due to increased write amplification
B. The message queue fails first due to partition key hotspots causing uneven load
C. Chat servers fail first because WebSocket connections are stateful and cannot be resharded easily
D. The load balancer fails first due to inability to handle increased connection churn

Solution

  1. Step 1: Identify stateful bottleneck

    Chat servers maintain WebSocket connections statefully, limiting horizontal scaling.
  2. Step 2: Understand scaling impact

    At 10x scale, existing WebSocket connections cannot be moved, causing chat servers to saturate first.
  3. Final Answer:

    Option C -> Option C
  4. Quick Check:

    Stateful WebSocket servers bottleneck scaling before DB or load balancer [check]
Hint: Stateful WebSocket servers bottleneck scaling first [check]
Common Mistakes:
Recommended

Ready to prove it?

Pass the test and this pattern moves unknown strong while earning +1 Grip toward your certificate.

10 questions~5 mineasy hard