Microservices Vs Monolith: The never ending battle
How to choose between Monolith and Microservices ?
Introduction
Monolith and Microservices based architecture has divided the tech industry. Internet applications saw tremendous growth in early 2010s. Mobile revolution, cloud computing and internet proliferation fuelled the growth.
Many companies migrated from monolithic systems to microservices based architecture. The companies were able to scale, deliver features and realise the benefits in short span of time.
Microservices provided many benefits, but it introduced lots of complexity & increased the costs. As a result, many engineers started advocating monolithic systems over microservices. In 2023, Amazon Prime Video replaced their microservices with a monolith and reduced their costs by 90%.
Choosing between monolithic and microservices based architecture is a one-way door decision. Every system is unique and has it’s own requirements. Just because one type of architecture worked for one system, doesn’t imply it would work for other systems.
It’s important to have a thorough understanding of monolith, microservices and the pros/cons of each. In this article, we will understand the fundamental concepts of monolith and microservices. We will explore the advantages and disadvantages of each. We will also look at how to choose between the two types of architectures by making the right trade-offs.
What is a Monolith ?
Monolith is a single software application that serves many functions. Let’s understand this with an example.
Let’s assume that you are developing a ride hailing app like Uber. You will implement the application in the language of your choice. You will add functionalities such as Ride management, Ride matching, Payments, Ratings, Near-by drivers, etc. Each functionality will be exposed by an API.
The below diagram illustrates how a Monolithic application works. The system consist of clients (mobile app), server application (monolith) and the database.
The client application such as a Mobile phone will integrate with the APIs to fetch and show the data. Each functionality is independent of the other. For eg:- Payments is independent of Driver rating. In order to organize your code, each functionality will be implemented as a part of a module.
The modules can communicate using well-defined language interfaces and exchange the data. For eg:- Ride Management module will pass the data to Ratings module through an interface.
Let’s now look at Pros and Cons of having a monolithic system.
Pros
Simple interactions - A monolith consists of a single application. It is easier for developers to understand the modules and their interactions. The operations are local and don’t encompass multiple distributed services.
Costs - The infrastructure costs to maintain the application are lower. As the modules call each other through language calls, there is no additional network bandwidth consumed.
Ease of debugging & troubleshooting - Developers can easily identify the root cause of an issue by looking at the application logs, and operational metrics. They have to deal with a single system and this reduces the time to fix the issue.
Performance - There is no performance penalty as different modules reside in the same application on a given host. As there is no network call involved, the latency is much lower. This results in highly performant monoliths.
Cons
Availability & Reliability - A monolith becomes a single point of failure. In case the monolith goes down, it would result in a downtime & impact all the users. In addition, a bug in one functionality can cause the whole application to fail. This reduces the availability and reliability of a monolithic application.
Scalability - The build times and deployment times are more. It becomes difficult to deploy simple features or bug fixes. As a result, fast growing organizations can’t scale with this type of architecture.
Separation of Concerns - As all the functionality is embedded within a single application, there is no clear separation of concerns. Every team contributes to the same codebase. Any revert done to mitigate a bug in new release, could block a critical feature from going live.
Inefficient resource usage - Each module would have a different traffic requirement. For eg:- Ride management would receive more 10x traffic as compared to user profile. To meet this demand, you will need to deploy 10 application instances. However, the user profile module will be underutilised in this case.
What are Microservices ?
Microservices split a large application into a set of small, independent, distributed applications. Each small application is also known as a service. The services are autonomous and responsible for serving a business functionality.
Let’s consider the example of Uber app that we discussed in the previous section. Each module within the Uber app will be deployed as a service. In other words, the module will run inside a web server.
The below diagram shows how the Uber’s backend consists of multiple distributed services. Modules such as Payments, Ride Management, etc are deployed independently as services.
The services communicate with each other through RPC (Remote Procedure Call). They can use wide array of protocols such as HTTP, GRPC, etc for communication. Additionally, the communication can be asynchronous using message queues such as RabbitMQ.
Pros
Availability & Reliability - Microservices are independent and loosely coupled. There is no single point of failure in a microservices based architecture. Hence, this architecture improves the availability and reliability.
Scalability - Each service can be scaled independently. Since different services have different traffic requirements, this architecture also utilises the computing resources efficiently.
Separation of Concerns - There is clear separation of concerns between the different services. Each service is responsible for a particular functionality. Furthermore, the services can be divided between different teams and ownership can be segregated.
Developer velocity and productivity - With each team owning a set of microservices, features can be developed and deployed easily. There is no dependency on large build times. Developers can become experts on the code they own and easily contribute to the features.
Multiple technology stacks - Each service can be implemented in a different language. Unlike a monolith, you are not constrained to use a single language for development. This provides lot of flexibility to the developers to experiment with different languages and choose the right stack.
Cons
Costs - A single monolithic application can be broken down into thousands of microservices. As the number of services increase, the associated maintenance costs also proportionately increase.
Complexity - A feature encompasses multiple microservices. In order to introduce a new change, you might have to modify the codebase of multiple services. This would require co-ordination between multiple teams or knowledge of codebase owned by different teams.
Debugging & Troubleshooting - It becomes difficult to debug and troubleshoot issues since hundreds of services are involved. In order to analyse a latency regression, you would have to navigate through multiple services.
Performance - The microservices rely on RPC calls to fetch the data. As a result, there is an inherent performance penalty with microservices. This increases the latency. In addition, a single call can fan-out to multiple services, and thereby impact the overall latency of the feature.
How to choose between Monolith and Microservices ?
In software development, there is no right or wrong answer. The choice between monolith and microservices is driven by business requirements, and the organisational goals.
In today’s world, every company’s business is backed by technology. The growth of the business is dictated by the underlying technology. To be at the forefront and beat the competition, it’s important for the business to be agile, and innovate at a rapid pace. Any friction would impede the growth of the business.
Software companies organize themselves into small, cross-functional teams. Each team is responsible for a business functionality. To improve their processes and ship features fast, they adopt best CI/CD processes.
When you start a new company, it makes more sense to build the application as a monolith. Micro-services based architecture for startup companies often results in over-engineering. It not only increases the costs but also increases the complexity. Once, a colleague of mine sarcastically said “Let’s build a micro-service for the toString() function in java” 😁😁.
Your monolithic application can scale provided that it is loosely coupled, testable and able to ship features quick. At times, the application can outgrow the monolith and impede the pace of development. Moreover, the company can grow exponentially and add more people to scale their operations. In such cases, you should think about pivoting to a microservices based architecture.
Migrating from a monolithic system to a microservices based system isn’t straight forward. It would take months or years of developer effort and also increases the software costs. The decision should be taken only if all the benefits outweigh all the costs. In other words, the migration should be taken up only if there is ROI (Return On Investment).
Companies such as Uber, Airbnb and Netflix have successfully adopted the microservices architecture. They were able to scale their businesses and simplify their operations. To overcome the complexity of microservices architecture, a concept called Domain Oriented Microservice Architecture (DOMA) has emerged. You can read more about the concept here - Introducing Domain Oriented Microservice Architecture.
Conclusion
The most challenging part of software development is defining the system architecture. The architecture design requires careful planning and design. A poorly defined architecture increases the costs, reduces the developer velocity and finally impacts the business.
Monolith is a single application or a service that serves different functionalities. It consists of loosely coupled modules. The modules talk to each other using interfaces. Monoliths are highly performant and save the network bandwidth. The operations are far simpler since a single application is involved.
The biggest downside of using a monolith is the time for deployment. A simple feature could take months to get deployed. There is no separation of concerns as all the functionality is embedded within a single codebase. The codebase can receive commits from many teams at the same time.
Microservices overcome most of the disadvantages of monolith. However, there is a performance penalty in using microservices. It also results in additional complexity and complicates the troubleshooting process.
The choice between monolith and microservices is dictated by your organisational structure and the processes followed. For early-stage companies, it makes more sense to have a monolith based system. In case your application has outgrown the monolith and is hindering the developer velocity, it makes sense to migrate to a microservices based architecture.
Thanks for reading the article! Before you go: