Microservices architecture, or simply microservices, is a software architectural style that has grown in popularity in recent years due to high demands in performance and increasing usage of cloud platforms. It’s an approach of developing an application as a set of independently deployed, loose coupled small-sized services that communicate with standard mechanisms, such as REST or SOAP.
Microservices vs Monolith Applications: What’s The Difference?
To understand microservices it’s useful to compare them to a monolith — an application designed as a single unit, usually consisting of a client-side, server-side, and database.
A monolithic application is a composition of modules being executed within a single process. That’s why if you want to make a change to a single module, you’ll need to re-deploy the entire application, causing a temporary service outage.
The monolithic approach is still used a lot, but its drawbacks increase with system growth. Attempts to eliminate performance bottlenecks lead to the scaling of the entire application. The larger the codebase gets, the harder it is to maintain. Bigger development teams perform worse and are harder to manage.
Pros and Cons of Microservices
The microservices approach solves common problems with monolithic applications, but it has several drawbacks.
|Scalability: Instead of scaling an entire monolith, you can only scale performance-critical microservices.||Additional complexity: A set of services is harder to develop than a set of modules. Poorly designed, microservices are harder to refactor.|
|Dev team distribution: Different microservices can be developed by different, relatively small teams that only have to agree on a communication interface.||Communication excess: Each client request will result in multiple requests across microservices, each waiting for each other.|
|Independent deployment: You can deploy each microservice independently, without taking down entire system.||Data inconsistency issues: Maintaining data consistency in a distributed system is a challenge.|
|Technology independency: Similarly, you can develop different microservices using different technologies, frameworks, programming languages and even database engines.||Operation complexity: Deploying and managing multiple instances of multiple services.|
As noted above, monolithic apps are hard to extend and maintain as they grow in size.
In microservices you deal with this issue by splitting the system into relatively small components that you can be modify or extended without affecting others.
The key challenge here is proper decomposition. Ideally, microservices have to fulfill a single business capability and be loose coupled. So that they can be individually upgradable and replaceable. Proper microservices composition also makes their performance more reliable.
If done poorly, refactoring remotely communicating services will be much harder. Thus microservices don’t eliminate complexity but rather transfer it to the design level.
In around 2002, Amazon CEO Jeff Bezos issued a mandate stating:
- All teams will henceforth expose their data and functionality through service interfaces.
- Teams must communicate with each other through these interfaces.
- No other communication is allowed.
- It doesn’t matter what technology is used.
This approach largely contributed to Amazon’s huge success and greatly influenced microservices architecture. The benefit is that you can deploy each microservice individually, with the help of a small cross-functional team. Such an approach is especially useful for companies that have employees spread across the globe.
Another big advantage is that there’s no commitment to any technology stack, so an individual microservice can relatively easy migrate to different technologies and companies can involve developers with different skills.
The common pattern with microservices architecture is that each service has its own database and can access other services’ data only via API. This has many positive aspects as well:
- Services are loosely coupled, changes to one database don’t affect the others.
- Databases have a relatively simple structure and are easy to maintain.
- Ability to use different database engines that best suits the service needs, i.e., fast NoSQL databases for performance, relational ones for strong ACID support, etc.
However, there are some issues with this approach:
- Application-side joins. When data from multiple services is needed to serve a user’s request, the join will occur on the application level, instead of the database level. However, this is not necessary a drawback – many high-load systems, for instance eBay, tend to move a big part of the application logic from the database to the application. The reason is that applications are much easier to scale than databases: no worries about partitioning, replication, and maintaining consistency. Applications, being stateless by their nature, can simply spawn additional instances to improve the performance.
- Data consistency. Maintaining consistency is a challenge with database-per-service approach.
- Distributed transactions is a complex solution that’s not easy to implement and poorly (or not) supported by many DB engines.
- An alternative is event-driven architecture, where services publish events when their data changes, and dependent services subscribe to these events and update their own data. This leads to eventual data consistency.
- Services can have eventually consistent materialized views of other services data, which they replicate for performance reasons. This is a popular approach. For example, when you add a new post on social media, oftentimes it doesn’t immediately appear in all news feeds.
To Sum Up
The microservices architecture pattern arose as a result of companies trying to deal with their high-load solutions. The most notable examples include Amazon, Netflix, and eBay.
However, the question whether to use microservices or not is a rather tricky one. The thing is that microservices solve problems that you don’t usually experience when you begin developing an application. Microservices help to deal with an application’s growing complexity and load, which is not usually an issue in the beginning.
Martin Fowler has come up with the following diagram illustrating microservice benefits in relation to the system’s complexity:
Some people suggest to go with a monolith first and then to migrate to microservices if necessary. Some try a hybrid approach, keeping a monolith as a base and adding new functionality around it with microservices.
On the other hand, when starting with a monolith it may be very hard to migrate to microservices, because good in-app interfaces may not become good service interfaces.
Generally, to get the most of a microservices-based solution, you’ll need to place a lot of emphasis on proper architecture design, using relevant domain knowledge. Otherwise this type of architecture can cause more problems than benefits.
Need more advice on microservices architecture solutions development or on refactoring your existing monolithic application? We are always up for a chat. Contact Edvantis to schedule a call!