Last week I spoke at the JSchannel Mumbai meetup on Microservices. My agenda for the talk was to introduce to the audience this upcoming popular trend and the reason we need to start thinking about using Microservices as the architectural approach for modern web applications. I also spoke about the various advantages it offers and the challenges that may come up and how to tackle those challenges.
Unfortunately, I couldn’t get the session recorded to share with you guys, so I thought why not write about it till it’s fresh in my mind.
This article touches on all the points very briefly. Each point discussed below is capable of having it’s own 1000 words blog post.
There are various advantages of using microservices, but of all of them there is one which I will say is an indirect advantage and that is the focus on building reusable components, i.e Reusing a microservice across multiple projects.
Any application we develop has various business requirements or say business capabilities. Some capabilities are unique to the application but a lot of them are common. Consider the following two applications as an example.
An Ecommerce Application may have the following business capabilities.
- User Management
- Product Management
A CMS may have the following business capabilities.
- User Management
- Content Management (Manage various Articles/ Pages)
- Widget Manager
If we build these applications with a regular Monolithic architecture, each of these capabilities is interlinked at application and data level and the result is a single huge code base that runs as a single process. So if we observe, it is obvious that when building applications the monolithic way we are reworking and recreating certain common business capabilities for every application. However, if we are able to build these capabilities as independent components and allow them to talk to each other via a common mechanism (REST APIs) we could very well reuse these components across applications.
So with microservices, we build products instead of projects. In the above example, all these common business capabilities viz: (User Management, Workflow, Notifications) will be our products and these products can be used across multiple projects (These products may or may not be independently deployed per project depending on the implementation).
Focus on products rather than projects
What are Microservices?
The very definition of microservices is vague, if you ask 10 developers for the definition of microservices you’ll get 10 different definitions. This is my best effort to define microservices.
“An architecture pattern where software applications are decomposed into a network of independently deployable Components, each component solves a single business capability and communicate with each other via a common lightweight protocol.”
A component here is a microservice, this component is capable of running independently and is responsible for it’s own data. A component’s data is private to itself.
Common characteristics of Microservices.
A better way to identify microservices is by looking for the common characteristics they should have.
- Componentization via services.
Applications are distributed as components exposed as a service running as it’s own process. These components can talk to each other but are not dependent on others. A component is independently replaceable and independently upgradable.
- Products, not projects.
Developing Softwares the microservices way encourages the development of reusable components/services, Microservices that can be used in multiple projects. These services should be developed as products and not projects. What this means is that the microservice evolves and improves with time. We don’t have a single big bang release and that’s about it rather we have incremental upgrades and continuous maintenance.
- Organized around business capabilities.
In a microservices architecture, the application is divided based on the business capabilities. What this also means is that the teams are also organized around these business capabilities and not technologies. So each microservice team would be as full-stack as possible.
- Designed for failure.
When you have an application running as a set of 100s of services, failures are bound to happen. Hence the attitude of the Microservices people should be to keep this in mind and use proper monitoring, debugging tools and make the system as resilient as possible. Also, a failure of one service should not bring down the entire application. Instead, it should ideally not affect any other services or the impact radius should be minimum. For eg. In an e-commerce application, if for some reason the recommendation service goes down, there should be a default set of values to replace the data provided by that service.
- Infrastructure Automation.
Build and deployment automation is mandatory when working with microservices. When we have dozens of services running as independent processes to come together as a single application, manual deployment is bound to produce failures.
- Responsible for its own data and data privacy.
In microservices, each microservice maintains it’s own data persistence. Also, the data is private to itself. No microservice can directly access the database of other microservices, the data communication should only take place via the APIs defined by that microservice. This also means that the type of database selection is completely the decision of that microservice. For one microservice GraphDB would be suitable for other a relational and may be a document based for another.
The above diagram illustrates a general architecture of a microservices application. We can clearly see that each service has its own database and no service directly connects to the database of other services.
The web and the mobile applications communicate with these services via an API gateway. The API gateway can merely be a proxy but can also act as a data transformer, thereby serving the right and relevant data to the right page. Eg. When loading product info in a mobile application you might want to reduce the number of fields fetched to save bandwidth. Ideally, an integration engineer should take ownership of the API gateway.
The API gateway is as important as any other microservice, in fact much more important as it is the only bottleneck of your application and a failure in the API gateway can bring down the complete application. Hence it should be as robust as possible.
The event queue acts as a transport layer for communication between microservices.
Clear Developer Ownerships
In microservices we have teams organized around business capabilities, these teams are responsible for their own microservices, starting from architecting to deployment.
Right tools for the right business problems
Since each microservice is independent of each other, each can have a varying tech-stack suitable to solve it’s own business responsibilities. For eg: If microservice deals with transactions we can have a relational data store, if a microservice has a lot of read operations and flexible model NoSQL (MongoDB) can be used.
As we have seen earlier, a microservice solving a common business problem can become a product for an organization which can be used across projects.
Easy to deploy/redeploy parts of application
Each microservice can be deployed and redeployed independently without affecting the entire application.
In a monolith, we have to replicate the entire application when doing horizontal scaling. Using microservices allows us to scale on the services that require being scaled, independently.
Easy independent Upgrades
Any upgrades will be independent and won’t affect other microservices.
Even though microservices offers numerous advantages, do remember that implementing it in practice is anything but a cake walk. Microservices offers its own set of implementation challenges. Let’s have a close look at them and see how we can address them.
This is the first challenge you will encounter when working with microservices. How do we divide the application into smaller units so that there is minimum interdependency?
The service separation strategy would vary with applications. There is no writing on the wall as to how to do this. But in general try to divide the application according to business capabilities, like how we saw for an e-commerce and a cms application above. The second way to work on it is by dividing based on application entities (eg: Users, Products, etc).
Work well on the data layer. Avoid data level joins, application-level joins are fine.
Another important challenge is the choice of mode and tool for inter-process communication. There are two broad ways using which IPC can be done in microservices.
- Request/Response based
A client makes an HTTP request to a service and takes action based on the response provide. The client may wait for the response or listen to is asynchronously depending on the requirement of the request.
- Event Based
A client publishes/ emits an event to which one or more services are subscribed. The services take action based on the nature of the event. Event-based communication is better for asynchronous communication.
- Avoid IPC as much as possible.
- It’s obviously not avoidable. Delay the choice of the tool. Once the application is a bit mature you’ll have a better idea as to which tool fits your application’s needs.
- If it’s just a matter of few calls, do direct communication via HTTP services.
- Include an event queue/store.
When the service count increases deployment automation is a must in a microservices architecture.
- Use Jenkins/ Travis/ webhooks for CI
- Use Docker for containerization. However, this can be avoided if services count is less and all of them have the same tech stack.
Source Code Management
Managing source code is also a bit tricky with microservices. You will most probably have a single repo for each microservice (Simply because having one repo for all sucks!). But this makes it difficult for developers to setup the entire application on local environments and also it’s hard to get a clear picture of the application architecture.
Using Git submodules is a possible solution. We have one parent repo which will have links to each microservice as a submodule.
Token based authentication has a few advantages over other methods in a microservices architecture. JWT can be a possible option. This eliminates the need to have a session store and session sharing between microservices.
- Neglecting the API Gateway. The API Gateway is mostly the single entry point to the microservices. An error in the API Gateway can bring down the entire application. Hence, it should be taken proper care off and should include error handling, debugging and monitoring capabilities.
- Event Queue is a must. Use event queue only when necessary do not try to force fit it.
- Directly accessing the data of other microservices. No microservice should directly access or manipulate the data of other microservices. The communication should only take place via well defined APIs.
Q. How to break down an existing Monolith into microservices?
- Don’t go for the Big Bang. Don’t try to rebuild everything from scratch.
- Separate UI from Backend.
- Use REST for Client/ Server Communication.
- Introduce an API Gateway as a proxy.
- Implement new features as separate microservices.
- Start moving less impacting capabilities into separate microservices.
- These microservices and monolith can work together until all the capabilities are extracted.
In this post, we had a brief overview of the overall concepts involved in microservices. We saw why we need microservices, the benefits it offers, challenges faced and possible solutions. However, this post only scratches the surface and there is a lot more to microservices. As stated at the start, each point discussed above is capable of having its own 1000 words article. Also, when our application grows we face unique and difficult challenges like service discovery and having infrastructure as code, we will leave these topics for a later time.
Hope this post helped you guys to have a better understanding of microservice architecture and will aid you in developing awesome applications with microservices.