In this blog we will cover transition from Monolithic Architecture to Microservices Architecture to Reactive Microservices by applying isolation techniques to Microservices Architecture.
To start explaining the microservices it’s useful to compare it to the monolithic application. A monolithic application is built as a single unit often comprises of three main parts: a client-side user interface, a database, and a server-side application.
The server-side application handles HTTP requests, executes domain logic, retrieves and updates data from the database, and selects and populates HTML views to be sent to the browser or returns JSON/XML response. This server-side application is a monolith – a single logical executable. Any changes to the system involve building and deploying a new version of the server-side application.
All your logic for handling a request runs in a single process, allowing you to use basic features of your language to divide up the application into classes, functions, and namespaces. You can run and test the application on a developer’s machine and use a deployment pipeline to ensure that changes are properly tested and deployed on production. The Monolithic application can be horizontally scaled by adding multiple instances behind a load-balancer.
Cons of Monolith
- The Monolithic application becomes difficult to understand after a certain point.
- It is harder to implement changes in a large and complex application with highly tight coupling. Any code changes affect the whole system so it has to be thoroughly coordinated. This makes the overall development process much longer.
- Components of monolithic application can not be scaled independently, only the whole application.
- It is extremely problematic to apply new technology in a monolithic application because then the entire application has to be rewritten.
Microservices Architecture is an architectural style that structures an application as a collection of smaller independent services. These services are highly maintainable and testable and loosely coupled. These microservices carry out every application process as a separate service. So all the microservices have their logic and the database as well as perform specific functions.
Pros of Microservices
- All the microservices can be deployed and updated independently, which gives more flexibility.
- A failure in one microservice has an impact only on a particular service and does not influence the entire system.
- Better granular level elasticity can be achieved.
- Flexibility in choosing tools and technologies.
The core of Reactive Microservices is finding ways to create more isolation between microservices. Reactive Microservices looks to be isolated in the state, space, time, and failure.
Principles of Isolation
- As we move from monolithic to microservices, more isolation is being introduced.
- Isolation provides reduced coupling and increased scalability.
- Reactive Microservices are isolated in:
Isolation of State
- Access to a Reactive Microservice’s state must be through its API.
- No Backdoor access through the database.
- Allows microservices to evolve internally without affecting outside.
Isolation of Space
- Microservices should be independently deployed and they should not care about the location of other microservice.
- The location of a microservice can be changed during deployment without an impact on any microservice.
- Allows microservices to be scaled up/down to meet demand.
Isolation in Time
- Reactive Microservices should be non-blocking and asynchronous.
- Between microservices, we expect eventual consistency.
Isolation of Failures
- Reactive microservices also isolate failures.
- A failure in one microservice should not cause another to fail.
- It allows the system to remain operational despite failure.
Bulkheading is is a technique widely used in ships for isolating failures. Failure zones are created in the application so that failure in that zone is not propagated to other zones and the overall system remains operational(possibly in a degraded state).
Circuit Breaker is another technique for isolating failures. When a microservice is calling another microservice that is overloaded and that may fail. The caller microservice may not realize that the called microservice is under heavy load and it may retry, resulting more load on the called microservice. Caller microservice needs to be careful to avoid this.
Circuit Breaker isolation technique solves above failure cascading problem. Circuit Breaker quarantine a failing service so it can fail fast allowing failing service time to recover without overloading it.
Message Driven Architecture
Reactive Systems are based on a message driven architecture. Asynchronous non blocking messaging allows us to decouple Reactive microservices in time and failure. It means that microservices are not dependent on the response from each other. If a request to a microservice fails, the failure won’t propagate. The client service can continue to operate without waiting for the response.
- Microservices can guarantee their behaviour using API calls.
- Isolation allows a service to operate independently of other services.
- They don’t require other services to be operational all the time.
- Autonomy allows for stronger scalability and availability.
- Fully autonomous microservice can be scaled indefinitely.
- Autonomy can be achieved through asynchronous messages.
- Use eventual consistency.
Managing API Complexity
Microservices can lead to complexity in API. A single request may require information from multiple microservices. Clients could send multiple requests but then aggregating these results will be complex one. API Gateway Service helps in this case. All the requests can be sent through API Gateway. A Gateway service sends requests to individual microservices and aggregate the response. Aggregation logic is moved from client to API Gateway Service. Gateway Service handles failures from each service and client has to deal with Gateway Service failure.