Microservices Design Patterns : Implementation Patterns, Part 3 (Bulkhead)
Bulkhead implementation pattern

Microservices Design Patterns : Implementation Patterns, Part 3 (Bulkhead)

In my previous article we had a look at Anti-Corruption Layer implementation pattern of micro-services. This article lets have a look at Bulkhead implementation pattern

Bulkhead

This pattern derives the name from the analogy of a Ship. In ship’s a bulkhead, is used to partition ships into compartments. So that if one of the sections is compromised the other sections as still safe and prevent the ship from sinking. 

The same pattern can be used in software systems to prevent cascading failures. In this pattern you assign limited resources to modules, services, operations, client endpoints, and so on. These logical partitioning prevents single (or a group) of workload to consume all the resource.

This pattern increases the resiliency of the system by preventing cascading failures caused by one service.

Problem

In micro-services environment you have multiple services. Each of these services has one or more consumer. Failure of a service will impact the consumer of this services. When the consumer sends a request to a service that is failed or not responding, the resources used by the client's request may not be freed in a timely manner. As requests to the service continue, those resources may be exhausted.

This issue of resource exhaustion affects services with multiple consumers. A large number of requests originating from one client may exhaust available resources in the service. Other consumers are no longer able to consume the service, causing a cascading failure effect.

Solution

The idea here is to isolate the resource based on technical and business aspect. Partition your resources in groups based on consumer load and availability requirements. One common pattern is to make sure that the resource used to call one service doesn’t impact others. For example, a consumer that calls multiple services may be assigned a connection pool for each service. If a service begins to fail, it only affects the connection pool assigned for that service, allowing the consumer to continue using the other services.

Considerations

  • You need to design bulkhead (partitions), keeping your business and technical requirements of the applications.
  • You have to combine the bulkheads with other patterns likes retry, circuit breaker to provide better fault tolerance. 
  • Surely this adds a complexity overhead to overall design and implementation.

When to use?

  • Isolate resources used to consume a set of back-end services, especially if the application can provide some level of functionality even when one of the services is not responding.
  • Isolate critical consumers from standard consumers.
  • Protect the application from cascading failures.

When not to use?

  • Efficient usage of resource is of concern.
  • When we do not want to deal with the extra complexity overhead

Example

Let’s assume you have a scenario where you have to call two other services using HTTP requests. Most of the developers will create one HTTP client and will use the same call for both service. But, what happens if one of those external service starts taking longer time for response, this will impact all other following call, though these two services are not related.

This pattern proposes to have two clients, one for each external service so that impact in one client doesn’t stops the other client to perform as expected.

No alt text provided for this image

Thanks for reading this article. Please share your comments, questions and feedback. Would be more than happy to help.

To view or add a comment, sign in

More articles by Satish Sharma

Others also viewed

Explore content categories