Microservices Design Patterns
Why do we need design patterns?
By using the design patterns,the team working on various projects use the same pattern to build similar applications.
What are design patterns?
Design patterns can be defined as a software template or description to solve problem that occurs in multiple instances while designing a Software applications or a Software Framework.
Microservices Design Patterns:
1. Decomposition Pattern :
a. Decompose by sub-domain pattern :
The domain-driven design (DDD) approach is a way of building complex software applications that is based on the development of an object-oriented domain model.Domain driven design defines separate domain models for each subdomain.
Sub-domain can be classified as follows
Core — The biggest differentiator for the business and the most valuable part of the application.
Support — Not a differentiator, but related to what the business offers. Usually implemented internally or outsourced.
Generic — Not specific to the business and are best implemented using off-the-shelf software.
b. Decompose by business capability pattern :
As a business,you do things to generate value.This is what a Business capability is.In e-commerce business for example,order management,inventory management,payment,shipping and so forth are involved.
c. Strangler pattern :
When migrating legacy monolithic applications to microservice architecture,the Strangler pattern is used.Monolithic applications can be incrementally transformed using this pattern by replacing a particular functionality with a new service.As soon as the new service is ready,the old component is decommissioned.
d. Sidecar Pattern :This pattern deploys components of an application into a separate process or container to provide isolation and encapsulation.It can also enable applications to be composed of heterogeneous components and technologies.
A sidecar service is not necessarily part of the application, but is connected to it. It goes wherever the parent application goes. Sidecars are supporting processes or services that are deployed with the primary application.
e. Bulkhead Pattern :
The Bulkhead pattern is a type of apllication 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.Partition service instances into different groups, based on consumer load and availability requirements. This design helps to isolate failures, and allows you to sustain service functionality for some consumers, even during a failure.
2. Integration Pattern :
a. API Gateway :
We can define API gateway which will act as single entry point for all types of clients.
Consider an example of an Online Book Store. API Gateway allows to use the online Book store APIs on multiple devices seemlessly.
b. Aggregator Pattern:
We can define aggregator as a simple web module which will call different services as per the requirement.If we need to apply any business logic over the result of services A,B and C,then we can implement the business logic in the aggregator itself.
An aggregator can be again exposed as another service to the outer world,which can be consumed by others whenever required.
c. Proxy Pattern :
It is a variation of aggregator pattern.The proxy service pattern can be devides into two categories:
- Dump proxy:It just delegates the request to another service.
- Smart proxy:It may apply transformation,logic,filtering,rejection before a request is delegated to other services.
It can be used mostly where you need a unified API interface for all your services.
d. Client Side UI Composition Pattern:
With microservices,the UI has to be designed as a skeleton with multiple sections of the screen.Each section will call to an individual backend microservice to pull the data.This is called as composing the UI components specific to service.Frameworks like AngularJS and ReactJS help to do that easily.These screens are also known as single page Applications(SPA).
e. Chain of Responsibilities:
As the name suggests ,this pattern will follow the chain structure.Here we will allow the client to communicate directly with the services and all the services will be chained up in such a manner that the output of one service will be input to the next service.
The major drawback of this architecture is, the client will be blocked until the entire process is complete. Hence, it is highly recommendable to keep the length of the chain as short as possible.
f. Branch Pattern :
This pattern is the extended version of aggregator and chain pattern.In this design pattern the client can directly communicate with the service.Also one service can communicate with more than one service at a time.
3. Database Pattern :
a. Database per Service:
This pattern keeps each microservice data private to that microservice and this data will be accessible only via relevant microservice. The microservice will use its own database for transactions.
b. Shared Database per Service:
In this pattern,a database is shared among microservices. Each service is free to use data accessible to other services.In this pattern, one database can be aligned with more than one microservice, but it has to be restricted to 2–3 maximum, otherwise scaling, autonomy, and independence will be challenging to execute.
c. Command Query Responsibility Segregation(CQRS) :
CQRS suggests splitting the application into two parts — the command side and the query side.The program will be split into two sections, Command and Query, in accordance with this design. The query section will take care of the materialized views, while the command part will handle all requests completely related to CREATE, UPDATE, and then DELETE.
d. Saga Pattern :
A Saga represents a high-level business process that consists of several sub requests, which each update data within a single service. Each request has a compensating request that is executed when the request fails. It can be implemented in two ways:
- Choreography — When there is no central coordination, each service produces and listens to another service’s events and decides if an action should be taken or not.
- Orchestration — An orchestrator (object) takes responsibility for a saga’s decision making and sequencing business logic.
e. Asynchronous Messaging:
This pattern is used for inter service communication as using synchronous communication will result in tight coupling of services and also requires both client and service to be available during request.Using asynchronous messaging a service can communicate by exchanging messages over messaging channels.
RabbitMQ and Apache Kafka are good examples of asynchronous messaging in microservices arena.
f. Event Sourcing:
We can use Event Sourcing Pattern for inter service communication. To aid the developers in keeping track of which change was done when these events are also saved as a series of events. Because of this, you may always update the application state to take into account historical modifications. Additionally, you can simultaneously publish similar events from event storage and query these events for any data changes. Once the events are published, the presentation layer will display any changes to the application state.
4. Observablility Pattern :
a. Log Aggregation:
We need a centralized logging service that aggregates logs from each service instance. Users can search and analyze the logs. They can configure alerts that are triggered when certain messages appear in the logs. For example, PCF does have Loggeregator, which collects logs from each component (router, controller, diego, etc…) of the PCF platform along with applications. AWS Cloud Watch also does the same.
b. Performance Metrics :
We can implement a instrumentation service which will be responsible to gather statistics about individual operations and a central metrics service which should aggregates metrics and provides the reporting and alerting. These services can collect the performance metrics in two ways −
Push − A services pushes the metrics to central metrics service.
Pull − The central metrics service pulls the metrics from the services.
Following are the examples of Instrumentation libraries −
- Java Metrics Library − A Java library to get insight into what code does in production.
- Prometheus client libraries − Prometheus libraries to monitor services.
Following are the examples of Metrics Aggregation libraries −
- Prometheus − An open-source systems monitoring and alerting toolkit.
- AWS Cloud Watch − AWS resources and service observability and monitoring service.
c. Distributed Tracing :
Distributed tracing is a method of observing requests as they propagate through distributed cloud environments. Distributed tracing follows an interaction by tagging it with a unique identifier. This identifier stays with the transaction as it interacts with microservices, containers, and infrastructure. The unique identifier offers real-time visibility into user experience, from the top of the stack to the application layer and the infrastructure beneath.
d. Health check :
A health check is a special REST API implementation that you can use to validate the status of a microservice and its dependencies. With MicroProfile Health, microservices can self-check their health and publish their overall status to a defined endpoint.A health check can assess anything that a microservice needs, including dependencies, system properties, database connections, endpoint connections, and resource availability. The overall status of the microservice depends on whether all the configured health checks pass.
5. Cross-cutting concerns Pattern :
a. External Configuration pattern:
Externalize all the configuration, including endpoint URLs and credentials. The application should load them either at startup or on the fly.
Spring Cloud config server provides the option to externalize the properties to GitHub and load them as environment properties. These can be accessed by the application on startup or can be refreshed without a server restart.
b. Service Discovery Pattern :
A service registry needs to be created which will keep the metadata of each producer service. A service instance should register to the registry when starting and should de-register when shutting down. The consumer or router should query the registry and find out the location of the service. The registry also needs to do a health check of the producer service to ensure that only working instances of the services are available to be consumed through it. There are two types of service discovery: client-side and server-side. An example of client-side discovery is Netflix Eureka and an example of server-side discovery is AWS ALB.
c. Circuit Breaker Pattern:
We can use circuit breaker pattern where a proxy service acts as a circuit breaker. Each service should be invoked through proxy service. A proxy service maintains a timeout and failures count. In case of consecutive failures crosses the threshold failures count then proxy service trips the circuit breaker and starts a timeout period. During this timeout period, all requests will failed. Once this timeout period is over, proxy service allows a given limited number of test requests to pass to provider service. If requests succeed the proxy service resumes the operations otherwise, it agains trips the circuit breaker and starts a timeout period and no requests will be entertained during that period.
Netflix Hystrix is a good implementation of the circuit breaker pattern. It also helps you to define a fallback mechanism which can be used when the circuit breaker trips. That provides a better user experience.
d. Blue green deployment :
We can define deploy newly development microservices using blue-green deployment. In this model, user traffic is diverted from old application to new microservice application gradually. One a microservice is available in production, the load balancer redirects the request targeted for old application to the new microservice.
- Blue Environment − The old application running in the production is called blue environment.
- Green Environment − The new services deployed which replicates the given part of old application is called the green environment.
So over the time of development, microservices increases and monolith shrinks with features moving out from monolith to microservices Application.
References:
1] https://www.knowledgehut.com/blog/programming/microservices-design-pattern
2] https://dzone.com/articles/design-patterns-for-microservices