Microservices Design Patterns Series — Part 4/5
Building Resilient Systems with Design Patterns
This article is Part 4 of the Microservices Design Patterns series, focusing on the Bulkhead and Database per Service Pattern. Below are the previous segments of this series:
- Part 1 — Service Registry and Service Mesh Pattern
- Part 2 — Circuit Breaker and Event Sourcing Pattern
- Part 3 — SAGA and API Gateway pattern
This article explores the Bulkhead and Database per Service design patterns. The Bulkhead pattern focuses on isolating application components to minimize the effects of failures and uphold system stability. The Database per Service pattern promotes the use of dedicated database instances for each microservice, enhancing autonomy and minimizing dependencies between services.
Bulkhead Pattern
The Bulkhead pattern draws inspiration from ship design, where compartments (bulkheads) are used to prevent a breach in one area from sinking the entire vessel.
The Bulkhead pattern is a type of application design that is tolerant of failure. In a bulkhead architecture, elements of an application are isolated into pools so that if one fails, the others will continue to function. It’s named after the sectioned partitions (bulkheads) of a ship’s hull. -[1]
This pattern is employed to enhance the resilience and performance of distributed systems, particularly in scenarios where resources need to be partitioned to isolate failures and prevent cascading issues.
For example, in a banking application, there are various critical services like transaction processing, user authentication, and customer support. Each of these services requires different resources and can experience failures or performance issues independently.
- Transaction Processing: This service handles incoming requests to deposit, withdraw, or transfer funds. To ensure high availability and performance, the system could employ a separate pool of worker threads dedicated solely to processing transactions. If there’s a sudden influx of withdrawal requests, causing a bottleneck or even a failure in the processing logic, it won’t affect other services like user authentication or customer support.
- User Authentication: User authentication involves verifying user credentials before allowing access to sensitive information or performing transactions. To prevent authentication failures from impacting other parts of the system, the authentication service could be isolated with its own set of resources, such as separate databases or authentication servers. If there’s a temporary issue with the authentication service, it won’t affect transaction processing or customer support functionalities.
- Customer Support: Customer support functionalities, such as handling inquiries, complaints, or account assistance, may require different resources compared to transaction processing or authentication. By segregating customer support resources into their own compartment, the system ensures that issues or heavy loads in customer support activities won’t degrade the performance or availability of transaction processing or authentication services.
Database per Service Pattern
The Database per Service pattern is a design approach where each microservice in a system has its dedicated database.
In this pattern, each service is responsible for managing its own data storage, which is decoupled from the databases of other services. This pattern contrasts with the more traditional approach of sharing a single, centralized database among multiple services.
By deploying the database-per-service pattern, you choose the most appropriate data stores (for example, relational or non-relational databases) for your application and business requirements. This means that microservices don’t share a data layer, changes to a microservice’s individual database do not impact other microservices, individual data stores cannot be directly accessed by other microservices, and persistent data is accessed only by APIs. — [2]
Consider an example of a web application for an online bookstore. In this scenario, we can apply a “database per service” pattern, where each microservice has its own dedicated database tailored to its specific needs.
- User Authentication Service: This microservice handles user authentication and manages user accounts. It requires a database to store user credentials securely. We might use a database like PostgreSQL or MySQL to store user information such as usernames, hashed passwords, and email addresses.
- Product Catalog Service: This microservice is responsible for managing the bookstore’s product catalog. It needs a database to store information about books, including titles, authors, descriptions, prices, and availability. A NoSQL database like MongoDB might be a good fit for its flexible schema and fast read and write operations.
- Order Management Service: This microservice handles order processing and fulfillment. It requires a database to store order details, such as order IDs, customer IDs, product IDs, quantities, and shipping information. A relational database like PostgreSQL or Amazon Aurora could be used for its strong consistency and transaction support.
- Recommendation Service: This microservice provides personalized book recommendations to users based on their browsing and purchase history. It needs a database to store user preferences and historical data. A graph database like Neo4j might be suitable for modeling user preferences and relationships between books.
References
- Microsoft. (n.d.). Bulkhead. Retrieved April 19, 2024, from https://learn.microsoft.com/en-us/azure/architecture/patterns/bulkhead
- Amazon Web Services, Inc. (n.d.). Database per service. Retrieved April 19, 2024, from https://docs.aws.amazon.com/prescriptive-guidance/latest/modernization-data-persistence/database-per-service.html