Search code examples
spring-webfluxproject-reactorresilience4j

What's the purpose of applying the Bulkhead pattern on a non-blocking application?


My understanding of the Bulkhead pattern is that it's a way of isolating thread pools. Hence, interactions with different services use different thread pools: if the same thread pool is shared, one service timing out constantly might exhaust the entire thread pool, taking down the communication with the other (healthy) services. By using different ones, the impact is reduced.

Given my understanding, I don't see any reason to apply this pattern to non-blocking applications as threads don't get blocked and, therefore, thread pools wouldn't get exhausted either way.

I would appreciate if someone could clarify this point in case I'm missing something.

EDIT (explain why it's not a duplicate):

There's another (more generic) question asking about why using Circuit-Breaker and Bulkhead patterns with Reactor. The question was answered in a very generic way, explaining why all Resilience4J decorators are relevant when working with Reactor.

My question, on the other hand, is particular to the Bulkhead pattern, as I don't understand its benefits on scenarios where threads don't get blocked.


Solution

  • The Bulkhead pattern is not only about isolating thread pools.

    Think of Little's law: L = λ * W

    Where:

    L – the average number of concurrent tasks in a queuing system

    λ – the average number of tasks arriving at a queuing system per unit of time

    W – the average service time a tasks spends in a queuing system

    The Bulkhead pattern is more about controlling L in order to prevent resource exhaustion. This can be done by using:

    • bounded queues + thread pools
    • semaphores

    Even non-blocking applications require resources per concurrent task which you might want to restrict. Semaphores could help to restrict the number of concurrent tasks.

    The RateLimiter pattern is about controlling λ and the TimeLimiter about controlling the maximum time a tasks is allowed to spend.

    An adaptive Bulkhead can even replace RateLimiters. Have a look at this awesome talk "Stop Rate Limiting! Capacity Management Done Right" by Jon Moore"

    We are currently developing an AdaptiveBulkhead in Resilience4j which adapts the concurrency limit of tasks dynamically. The implementation is comparable to TCP Congestion Control algorithms which are using an additive increase/multiplicative decrease (AIMD) scheme to dynamically adapt a congestion window. But the AdaptiveBulkhead is of course protocol-agnostic.