8. Project Milestone 7.2 : Documentation of PM6 - airavata-courses/TeamAlpha GitHub Wiki
####Micro service design implemented in project:
Micro services is a software architecture style in which complex applications are composed of small, independent processes communicating with each other using language-agnostic APIs.
We divided our application into 3 micro services:
- User registration
- Save job details
- Fetch job details i.e. monitor job
.
Each of the three microservices can be deployed independently as a separate .jar application and the web application i.e. the Gateway will be deployed as a war file. These microservices communicate with the gateway using REST API and the messages are communicated in the form of JSON. We chose these three modules for being the microservices because
- User registration: This module can function independently without any input from the gateway. We just need the user details for authentication and it communicates with its own database and performs the authentication.
- Save job details: This module saves all job details to database upon job submission.
- Fetch job details: This modules require just the job id for functioning i.e. cancelling the job or fetching the job details. Thus, these modules can also be deployed independently.
We have used the microservices architecture using Spring Boot for Java development. The Web-Application will make requests to the microservices using a RESTful API. We fetch data and send HTTP requests to the RESTful server in JSON format.
We could have decoupled our system using nginx. It is possible to use nginx as a very efficient HTTP load balancer to distribute traffic to several application servers and to improve performance, scalability and reliability of web applications with nginx. We have described about Nginx and how our structure would have been using Nginx below:
####NGINX Load Balancing - HTTP and TCP Load Balancer
Nginx is the second most popular open source web server on the Internet. Features like load balancing, caching, access and bandwidth control, and the ability to integrate efficiently with a variety of applications, have helped to make nginx a good choice for modern website architectures.
Architecture:
Here is a single master process and several worker processes. There are also a couple of special purpose processes, specifically a cache loader and cache manager.
- Master: The master process is run as the root user. The cache loader, cache manager and workers run as an unprivileged user.
- Worker: Worker processes accept new requests from a shared "listen" socket and execute a highly efficient run-loop inside each worker to process thousands of connections per worker.
- Cache loader: The cache loader process is responsible for checking the on-disk cache items and populating nginx's in-memory database with cache metadata.
- Cache Manager: The cache manager is mostly responsible for cache expiration and invalidation. It stays in memory during normal nginx operation and it is restarted by the master process in the case of failure.
A typical HTTP request processing cycle looks like the following:
- Client sends HTTP request.
- Nginx core chooses the appropriate phase handler based on the configured location matching the request.
- If configured to do so, a load balancer picks an upstream server for proxying.
- Phase handler does its job and passes each output buffer to the first filter.
- First filter passes the output to the second filter.
- Second filter passes the output to third (and so on).
- Final response is sent to the client.
Using nginx we could set one daemon up as the proxy front end and two Nginx daemons behind it for load balancing. In our case, when we fetch job details, huge data travels over the network which may may be divided amongst various servers as shown in the above diagram.
We can also achieve fault tolerance by making copies of the micro service to make sure that if one service fails we could use up the backup copy in order to avoid failures. We can have instances of the same application running on multiple servers.
####Lifecycle of a job submission request
The lifecycle of job submission follows the below steps:
- Gateway accepts requests from the user and redirects them to the dedicated micro service.
- The steps followed are:
- Initial user logs into the application. In case user does not have an accunt, he can register himself to this application. Gateway redirects the registration request to the micro service.
- Once user logs in, he submits a job request to the server by uploading input files.
- Once job is submitted, the user can check the job status. This check status request is redirected by gateway to its dedicated microservice.
- The submitted job can also be cancelled. The request for cancelling request is is redirected by gateway to its dedicated microservice.
- Once a job is completed, the output files can be downloaded.
####Lessons Learned
Monolithic Architecture:
A monolithic application is basically built as a single unit. All your logic for handling a request runs in a single process, allowing you to use the basic features of your language to divide up the application into classes, functions, and namespaces. With some care, you can run and test the application on a developer's laptop, and use a deployment pipeline to ensure that changes are properly tested and deployed into production. You can horizontally scale the monolith by running many instances behind a load-balancer.
Advantages:
- Faster initial development: With one application, it would be relatively easy to add additional features, especially when the application is relatively small
- Little User Confusion: Users wouldn't have to learn about different applications, but would be focussed towards one application.
- User Interface Similarity: All of the pieces of the application would look very similar, so it would be obvious it's all part of one system.
Disadvantages:
- Within a monolithic application, all the modules are tightly coupled and any change made to a small part of the application, requires the entire monolith to be rebuilt and deployed.
- As your application grows, the code base grows with it, which can overload your IDE every time it loads the application. This definitely reduces developer productivity.
- Maintainence: The larger a website is, the more difficult it becomes to maintain the entire thing. Maintenance costs may go up exponentially with site size.
Microservices Architecture:
Using microservices is one way of breaking up a monolithic application to gain increased decoupling, separation of concerns and fast deployment. Microservices allow large systems to be built up from a number of collaborating components. A microservices architecture puts each element of functionality into a separate service and scales itself by distributing these services across servers, replicating as needed. Microservices architecture is basically an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API.
Advantages:
- Improves fault isolation: larger applications can remain largely unaffected by the failure of a single module.
- Makes it easier for a new developer to understand the functionality of a service.
- Developers can deploy their respective services independently without waiting for the others to finish their modules
- Flexibility to change and redeploy their modules without needing to worry about the rest of the application’s components.
Disadvantages:
- Because of independent service, we have to carefully handle requests travelling between modules. There can be a scenario where one of the services may not be responding, forcing you to write extra code specifically to avoid disruption.
- Deploying microservices can be complex. They may need coordination among multiple services, which may not be as straightforward as deploying a WAR in a container.
- Multiple databases and transaction management can be painful.
- Testing a microservices-based application can be cumbersome.
If we were to build the project from scratch, we would have divided our application into micro services since the beginning. This way we would have created a separate micro service for submitting a job as well as downloading job files. We could have deployed the micro services on multiple services using Nginx for load balancing and fault tolerance.