Monolith to Microservice Architecture Migration
Monolith architecture is the standard approach for developing applications from the beginning.. In this approach all elements of the software – the user interface, the business logic and database access logic is in a single code base. All functionalities are tightly integrated into the same code base. One of the major reasons for people using this architecture is the ease of development, deployment and maintainability.
Over the years, as applications grew in size and complexity, everyone started to realize the limitations of monolithic architecture. With this architecture, any small change would require the entire application to be tested and redeployed. With some level of automation, this has been taken care of, however for large applications, continuous delivery, availability, scalability and maintainability were the major concerns.
Microservices were introduced during 2011-12 to address the challenges with Monolithic architecture. This allows applications to be developed as a collection of independent services which are loosely coupled, each service is responsible for a specific business functionality and can be tested, deployed and scaled independently. The frontend would be separated from the backend. And the backend would be split into microservices having its own API interface. Front end communicates with the backend through these APIs and microservices would also communicate with each other as needed.
We will see the Pros and Cons of both Monolith and Microservice architecture.
Monolith | Microservices |
Consists of a single code base with multiple modules according to the business features | Consists of multiple code base – decomposing the entire application into multiple services |
Tightly coupled, hard to make changes, one issue can bring system down | Loosely coupled, introducing changes is easier, high availability |
Entire code to be developed in same technology | Services could be developed irrespective of the technology |
Need to scale up the entire application | Monitoring and scaling up of individual services |
Testing would be easier – focus on single app | Testing individual services, and then testing as a whole – time consuming |
Entire code base needs to be redeployed, but deployment would be easier | Each microservice can be deployed individually, deployment could be a tedious process unless automated. Enables continuous delivery |
Initial costs will be lower, operational cost would be higher | Initial costs would be higher, operational costs will be lower |
Why Migrate ?
When you are planning to migrate, you need to analyze the reasons for migration. Depending on the application, technology, business needs and customer preferences, the approach for migration would be different. Some of the major considerations would be
- Do you want to be able to adopt new technologies and processes faster?
- Do you want faster release cycles for your application?
- Do you want to scale more easily in the cloud?
Migration Strategies
Once the decision is made for migration, we need to decide the best strategy.
Domain Driven Design – In this approach, the whole migration could be considered as a project and finally there would be a big bang release of the application in the new architecture. The steps are
- Stop Expanding – Stop adding functionality to the monolithic application. If new features are needed, add as a separate service and have request routing mechanism to redirect to the monolithic application and new service
- Split the frontend from the backend – Create API interfaces for the backend code and have the UI disconnected from the backend.
- Decompose and decouple the monolith into a series of microservices – Split the backend monolith to separate microservices based on the domain features
Strangler Pattern – In this approach, we will incrementally transform the Monolith to Microservices. Any new feature will be created as a new service and features from the current Monolith will be extracted to a new service in stages. This enables the Monolith and new Microservices to Co-exist for a period of time until the Monolith is fully eliminated.
Lets see what are the steps involved in the migration process.
Step 1 – Identify Microservices based on functionality
- Based on the business features, identify the Microservices and its scope. There could be Business domain related services as well as common services or utility services which could be used by all services
Step 2 – Ensure relevance of each model in the service
- Remove dependency of data on multiple services, if there is dependency try to combine those services or remove dependency by removing foreign key constraints.
Step 3 – Identify the REST API endpoints for each Service
- API endpoints with input parameters and output JSON that includes error handling
Step 4 – Identify interservice communications
- There will be scenarios where services need to communicate with each other. Communication could be Synchronous or asynchronous. The most common approach is Event driven communication where the service posts an event with state to an event bus all services subscribed to the event will process it asynchronously.
Step 5 – Identify polyglot persistence
- Here the idea is to have Independant database for each service. Benefit of this approach is that for performance, the service could use a Redis or ElasticSearch database based on the functionality.
Step 6 – Repository restructuring
- Each service in its own code repository to enable isolating issues, testing and deployment without affecting other services.
Step 7 – Identify changes in the frontend corresponding to the change in the backend API
- Changing the end points of the APIs in the front end
Challenges
Though Microservices provide a lot of benefits such as scalability, performance, flexibility etc, there are also several challenges that we need to consider. Few of them are listed below.
- Picking the right R – When implementing microservices, we need to decide whether to rewrite, reuse, retain, or retire the existing legacy application. This decision depends on various factors such as the complexity of the application, business requirements, and available resources. Each option has its advantages and disadvantages, and we need to carefully evaluate them before making a decision.
- Complexity of Legacy application – Legacy application may be over complex and developed using some outdated technologies and may not be supported by Microservices architecture. We need to assess the complexity of the app and technologies, rewrite or refactor the existing code to support Microservices architecture.
- Deciding on the microservices and its scope – Microservices architecture requires us to break down the application into smaller, independent services. Deciding on the scope of each service can be challenging. We need to identify the business requirements and functionalities that can be implemented as separate services.
- Managing the database – Microservice architecture suggests having a separate database for each service. We need to give careful consideration on the data management plan to ensure data consistency between services
- Timeline for completion – Microservices implementation will take longer time than monolithic architecture. Arriving at a timeline for completion would be challenging. Breaking down the development into multiple phases and a phase wise estimation would be better while making any commitments to the customer.
- Managing IT spends – Implementing Microservices will be costlier considering the additional infrastructure and resource needs. In the long run the costs would come down, however the initial costs need to be managed well.