Enterprises are heavily switching to building microservice based applications instead of monolithic. The microservice based architecture breaks down a large application into smaller autonomous service units that can act independently without impacting other services. Each of the microservices design patterns is tried and tested like object oriented patterns and have their unique advantages and drawbacks.
Most Common Microservices Design Patterns
Database per service
Each microservice has a dedicated database, a table or a whole schema, dedicated to them. Other external services are unable to access this. Individually segregated databases are easy to scale. New development team prefers this kind of architecture as it is easy to understand services and its data as a whole.
Event driven architecture
An event triggers communication between two independent services in an event driven architecture. An event is a change of state like a button being toggled, or notification generated, or an item added to cart.
An event store keeps track of all events and serves as a database of events. Services subscribe to events they are interested in and once a change of state happens the event store sends updated information to all the subscribers.
CQRS (Command Quality Response Center)
Command changes the state of an object while query brings information about the changed state. While CRUD operations might be enough for simple applications it might lead to overworking when multiple query and write operations are being performed simultaneously. Also keeping the same model for read and write operations exposes database to security vulnerabilities.
CQRS isolates read and update operations from a data store. Commands are written as task based allowing enough granularity in commands to minimize merge conflicts.
The saga design pattern allows to breakdown complex transactions into smaller, more manageable steps. The saga pattern helps maintain data consistency and recoverability. It does so by breaking down the entire operation into smaller, individual transactions known as “local transactions.” Each of these local transactions is responsible for updating the database and potentially triggering an event or message for the next transaction in line.
The saga pattern is especially useful in distributed environments where network partitions, service failures, or other issues can lead to partial failures. By breaking down the operation into smaller, manageable steps and providing a mechanism for recovery, the saga pattern ensures that the system can handle failures gracefully and maintain data integrity.
BFF (Backends for Frontends)
In this architecture backend of an application is isolated from the frontend. This promotes code reusability as multiple clients can use the same backend code. This pattern is also used to identify how the data is being fetched between servers and clients. A single BFF handles a single UI allowing a unified view of data at the backend.
Circuit breakers are adopted to limit the propagation of failures throughout the microservices ecosystem. It is designed so that the service breaks after reaching a certain number of failures, preventing the system from generating further requests and effectively mitigate the repercussions of service downtimes and delays.
The API gateway pattern places a gateway between the microservices and the client application. This pattern is preferred for large applications with multiple client apps that need to access a certain group of microservices, where the gateway serves as a single entry point. The API gateway provides some cross-cutting services as it serves as a reverse proxy, forwarding client requests to services. authentication, SSL termination, and caching. It can also deal with partial failures like using cached data from a previous request.
Configuring services separately for every environment they are intended to run can be challenging. Externalizing allows to leave the code intact and externalize all the configuration like endpoint URLs and database credentials.
The API gateway pattern connects services with external clients. However there is a challenge, the IP and port keeps changing for services. Service registry pattern registers all microservice and the client service finds the location of required services by checking the service registry. Nowadays, container orchestrator systems comes with the automatic service discovery facility and this pattern is going out of practice.
Bulkhead pattern is a fault tolerant microservice design pattern that isolates the impact of a failing service. The system is partitioned into multiple compartments called ‘bulkhead’ separated from each other. Services are stored in bulkhead and when one fails the other still continues to work without interruption. It also allows to independently scale services.
There are plenty of microservices design patterns to pick from when going for building or transferring some application to microservice based architecture. The key considerations here remains volume of data, type of services, frequency of query, budget. It requires an expert team to decide suitable microservice for a project after a thorough analysis of the conditional factors.