-
Notifications
You must be signed in to change notification settings - Fork 5
Project Milestone 7.2: Documentation of PM6
Microservices are small, independent processes that communicate with each other to form complex applications which utilize language-agnostic APIs. These services are small building blocks, highly decoupled and focused on doing a small task, facilitating a modular approach to system-building.
We had a single monolithic middleware application packaged into a single unit, and so segregating it into various microservices allowed it to be easily deployed as independent units. We identified 4 microservices:
- UI microservice
- API microservice
- Database microservice
- Middleware microservice
-
UI Microservice: All the user interface is deployed in this project. All form validations are first performed at this microservice, so that user inserts correct input. The UI microservice makes REST calls to the API microservice.
-
API Microservice: This acts like an interceptor between the UI and middleware, which processes input and makes java calls to the middleware.
-
Middleware Microservice: This is the heart of the gateway, which intercepts java calls and makes JDBC/ JPA calls and ssh commands to HPC resources to complete the requests.
-
Database Microservice: This is a separate microservice intercepting calls from the other microservices, and completes the JDBC/ JPA requests by interacting with the sql server on Amazon RDS.
The job submission lifecycle is as follows:
- First a user needs to login to use the gateway services. Login is done using the UI microservice.
- Next, a user is displayed with a host of actions like submit job, view details, cancel job, etc. When a user selects submit job, it is intercepted as a API call which will use the API microservice.
- Next, it will SSH to HPC resources and peform pre-requisites like copying resources.
- Then a job is submitted using Middleware microservices.
- Next, a record is stored into the database using database microservice which will use the Amazon RDS.
One way we could have carried out load balancing was using "HAProxy"
HAProxy, which stands for High Availability Proxy, is a popular open source software TCP/HTTP Load Balancer and proxying solution which can be run on Linux, Solaris, and FreeBSD. Its most common use is to improve the performance and reliability of a server environment by distributing the workload across multiple servers (e.g. web, application, database).
Here is a diagram of a simple example of layer 7 load balancing:
Using application layer load balancer allows the load balancer to forward requests to different backend servers based on the content of the user's request. This mode of load balancing allows you to run multiple web application servers under the same domain and port.
In this example, if a user requests yourdomain.com/blog, they are forwarded to the blog backend, which is a set of servers that run a blog application. Other requests are forwarded to web-backend, which might be running another application. Both backends use the same database server, in this example.
- Logging microservice
- Messaging microservice
Challenges faced while adding more microservices are:
- CI/CD gets convoluted
- handling asyncronous messaging
- fault-tolerance
Pros of microservices when compared to a monolithic model:
- Deployability: more agility to roll out new versions of a service due to shorter build+test+deploy cycles. Also, flexibility to employ service-specific security, replication, persistence, and monitoring configurations.
- Reliability: a microservice fault affects that microservice alone and its consumers, whereas in the monolithic model a service fault may bring down the entire monolith.
- Availability: rolling out a new version of a microservice requires little downtime, whereas rolling out a new version of a service in the monolith requires a typically slower restart of the entire monolith.
- Scalability: each microservice can be scaled independently using pools, clusters, grids. The deployment characteristics make microservices a great match for the elasticity of the cloud.
- Modifiability: more flexibility to use new frameworks, libraries, datasources, and other resources. Also, microservices are loosely-coupled, modular components only accessible via their contracts, and hence less prone to turn into a big ball of mud. Dynamic discovery and binding via a registry (e.g., Apache ZooKeeper, Netflix Eureka) is sometimes used for location transparency.
- Management: the application development effort is divided across teams that are smaller and work more independently.
- Design autonomy: the team has freedom to employ different technologies, frameworks, and patterns to design and implement each microservice, and can change and redeploy each microservice independently
Cons of microservices when compared to a monolithic model:
- Deployability: deployment becomes more complex with many jobs, scripts, transfer areas, and config files for deployment.
- Performance: services more likely need to communicate over the network, whereas services within the monolith may benefit from local calls. Also, if the microservice uses dynamic discovery, the registry lookup is a performance overhead.
- Availability: if you use a registry for dynamic discovery, unavailability of the registry may compromise the consumer-service interaction.
- Modifiability: changes to the contract are more likely to impact consumers deployed elsewhere, whereas in the monolithic model consumers are more likely to be within the monolith and will be rolled out in lockstep with the service. Also, mechanisms to improve autonomy, such as eventual consistency and asynchronous calls, add complexity to microservices.
- Testability: automated tests are harder to setup and run because they may span different microservices on different runtime environments. Management: the application operation effort increases because there are more runtime components, log files, and point-to-point interactions to oversee.
- Memory use: several classes and libraries are often replicated in each microservice bundle and the overall memory footprint increases.
- Runtime autonomy: in the monolith the overall business logic is collocated. With microservices the logic is spread across microservices. So, all else being equal, it's more likely that a microservice will interact with other microservices over the network--that interaction decreases autonomy. If the interaction between microservices involves changing data, the need for a transactional boundary further compromises autonomy. The good news is that to avoid runtime autonomy issues, we can employ techniques such as eventual consistency, event-driven architecture, CQRS, cache (data replication), and aligning microservices with DDD bounded contexts.
- single sign-on
- Create seperate project modlues for microservices identified
- Add a high-throughput, distributed, publish-subscribe messaging system like Kafka
- Implement devops techniques like ansible or chef for configuration management