This article was authored by Ankit Trivedi, a PGP- Cloud Computing alumnus from Great Learning. 
The traditional approach for an IT Client-Server application is to bundle all the code and libraries in a single file and deploy them on a single host. The host would act as a server and then a user acting as a client would interact with the server. There are limitations to such a monolithic approach to application deployment. A few years ago, a new approach was proposed which would address some of these limitations, which could be deployed in cloud architecture and leverage cloud computing capabilities to provide a highly available, loosely coupled, resilient and scalable architecture called the Microservices based Architecture.
Microservices Architecture based application consists of multiple services. The benefits of such an architecture are:
– Loosely coupled
– Independent of other services
– Can be coded in different languages
– Each service can be deployed, maintained and upgraded independently
– Better organization as the services are ideally based on business processes
Microservices Approach of Companies
Many companies have succeeded in migrating their existing monolithic applications to Microservices based architecture, and some companies are checking for proof of concept to see if such an architecture can bring any benefits to their organisation. It is much easier to build a new application in a Microservices based architecture rather migrating to it. There are no other options in some instances, so let’s look at how to migrate your application from a monolithic to a Microservices based solution.

The approach is written with the assumption that we are migrating an e-commerce application that is written in Python (Django framework) which uses SQLite as the database. The application is a web-based application that is bundled and deployed on a single host.

Existing Architecture assessment
In order to migrate any application, it is important to understand how the application works. So the first thing would be to analyze the existing application. The aim of this assessment is to understand how business flows are implemented and how these flows are coupled. The next step would be to identify various modules and identify their boundaries. Boundaries would be the point of interaction between 2 different modules. This will help us in breaking down the application. The analysis should also include an understanding of the Database schema. This will be required to decompose the DB schema to identify entities for individual services. Below is a checklist of expected outcomes of the architecture assessment:
– Identify how data flows in the application
– Identify various modules in the application
– Identify various interaction points between the modules
– Identify the database entities used by each module
Identifying modules to convert into services
After the architecture assessment, you should have a list of modules for your application. These modules represent various business functions. A service, as defined in the previous section, should be independent. Thus in order to make sure that services remain independent one of the best ways to identify microservices for an application is to make sure they are based on business functions that serve a single purpose.
You will have to go through the list of your modules identified in the previous section and align them to your business functions. This would help you to get all the modules categorised in groups based on business functions. And then you can identify these modules groups as services.
Below is a checklist of expected outcomes of this stage:
– Align modules to business functions
– Identify services to be implemented

Note: Some may argue that you can directly have a one-to-one mapping of modules to services. This is also possible because there are no hard and fast rules on what are the criteria for identifying services. A logical approach is to identify services that align with business functions so that you have a better understanding of what should be and should not be included in the service.

Identifying Database entities to be broken down
By now, you should have a rough idea of which services you are going to build. Once you have that list, you will have to identify the database tables that will be used by each of the services. You’ll then decompose the existing database into multiple databases for each of the identified services. This will be a challenging task because in traditional architecture the whole application uses a single database schema and the tables are linked to each other. When the application is processing data, it will refer to multiple tables, get data from them, do some processing and write the data back either to a single table or multiple tables. When you are decomposing the database into multiple databases, you will have to identify tables required for each service and also links to other tables and data required by the service from other tables. The other tables referred here will also belong to a service. And in the new Microservices based architecture, the other tables might not be available in the database schema of the main service.  Here’s an example:
Suppose you have a module named ‘orders’ that interacts with the orders table in the DB, and also refers to the products table to get products data. It will also refer to the billing table to generate billing for the order. If you are going to create 3 different services: order, products and billing then the new database schemas for orders will not have the products table and the billing table.
This shows that interaction and data sharing between the services is also required. Thus in order to send or receive data from services, the services will have to talk to each other. This is covered in the next section.
Below is a checklist of the expected outcome of this stage:
– Database schema for each service
– Interaction points of one service with other
Identify ways for services to interact
The main goal of Microservices based architecture is to have services that can be managed independently. But at the same time, the services should be able to communicate with each other. In this section, we will cover how and in what way services can talk to each other.
Basically, when we refer to services communicating with each other, we are saying that one service will be able to send data to another service and the second service will treat the data as input, do some processing and generate an output which will either be stored in local DB or sent to calling service or might even trigger a third service.
This invoking of services can be done in two ways, Synchronously or Asynchronously.
In the synchronous method, Service1 will send a request to Service2 and Service2 will send a response in real time to Service1. This can be achieved by creating an API for services.  This API would basically take inputs from any other service and provide an output to the calling service based on the input. Thus allowing the services to call each other. A typical way of implementing API is REST (REpresentational State Transfer) where every service would have an API endpoint which would receive requests that can be processed and a response will be sent back based on the outcome of processing of the request. The REST framework uses methods like GET, POST, PUT and DELETE to interact with API endpoints.

Note: API can be stateful or stateless. It’s up to you and your business requirement, how you are going to build your service.

In the asynchronous method, Service1 will send a request to Service2 and Service2 will send a response to Service1 but the response would not be in real time. This can be achieved by implementing a queue between services. The flow would when Service1 wants to talk to Service2, Service1 would generate a request and send to the queue. Service2 would keep poling the queue at regular intervals and as soon as it gets a request it would process it and send the response to Service1 through a different queue.
In order to migrate a monolithic application to microservices based architecture, you first need to understand the existing architecture. Once you have a good understanding of what the architecture is then you can identify the services that you are going to build and the database schemas for each of the services. In the end, when you have a clear picture of the service and the associated database schemas then you would identify how the services would communicate with each other.
Use Cases (E-commerce website)
Let’s apply this approach to a simple e-commerce website. The website will be a demo app having below functionalities:
– Home Page
– Featured Product on home page
– User Registration and User Login
– My Carts page
– Order displayed on Carts page
– Products Displayed on the home page and detailed view on clicking the product

Note: The website code reference here is code available on github.

Existing Architecture assessment
The first step would be to understand how data flows. Based on the UI interaction, we could get below details of the various modules for the website.

This gives us a rough idea of the modules for the web app. Based on these details, a definite list of the modules and interaction between modules can be identified. In the below snapshot we have identified modules like Ecommerce, Newsletter, User Admin, User Checkout, User Address, Carts, Orders and Products. The snapshot also gives you information about how the modules interact with each other and the purpose of that interaction.

 
Identifying modules to convert into services
Based on the above list of modules, we have identified below services of the microservices based architecture.
– e-commerce
– User Admin
– Carts
– Orders
– Products
Identifying Database entities to be broken down
Now that we have a definite list of expected services we are going to get details of the database tables for each of them.

The above snapshot provides you with details of which tables are used by each of the modules/services. The reference columns have details of the other tables being referred by the main tables of the modules (Note: These references are foreign key constraints for the tables). In order to decompose the existing database into multiple databases, we now have details of which tables are required by each service.
The database schema for each of the services will have their main tables, as mentioned in the table column. But there are chances that the reference tables may not belong to the services. In that case, data pertaining to those reference tables will be fetched from other services using API calls.

Note: There are chances that we might store the data fetch from other services in the database schema of the calling service. This can lead to data duplication and hence it is advised to store required data only and not the complete record being fetched.

Identify way for services to interact
The final step is to identify a way for the proposed services to interact with each other. The services that are identified will require synchronous interaction and hence we would be setting up API endpoints for each of the services. Using these endpoints, we would be able to send and receive data from each of the services. Below provides a snapshot of how the services are going to interact with each other using REST API calls.

After this is completed, we can start with the implementation or migration of the monolithic application to microservices.
A Sample Implementation

This is a sample approach, which we used in our PGPCC Capstone implementation.
 

0

LEAVE A REPLY

Please enter your comment!
Please enter your name here