Nowadays, most companies are switching to microservices as their primary software development architecture. But what are the pros and cons of this modern way of doing things? As an engineering software services provider with 30+ years of experience, Auriga helps companies during their digital transformation journey with cloud solutions development or migration, data analytics, IoT applications, and customer- and employee-facing services.
As a sales engineering manager, I constantly talk to our customers about technologies and answer similar questions often, such as the following:
- Reasons to migrate to Kubernetes?
- What is a cloud-native application?
- Difference between DevOps and SRE?
- What is GitOps and why should we care?
In this post, we’ll explore some of the benefits and drawbacks of microservices so you can decide whether to move your solution in that direction. Stay tuned!
What are Microservices?
A microservice architecture (MSA) is a service-oriented architecture style that designs an application as a set of separate services that comply with the following principles:
- A service has a single concern
- Services are loosely coupled
- Each service is independently deployable
- Each service can be owned by a small team
- Each service keeps its persistent data private
MSA often uses lightweight JSON-based event buses for interservice communication and individual heterogeneous data storages per service that fit best for the use case. Usually, microservices are matched against monolithic applications, the more traditional way of designing a solution’s architecture. The differences between the two can be seen in the illustration below:
MSA is an evolution of service-oriented architecture (SOA). Although they have much in common, microservices’ scope is more granular and defines components of application-level functionality, while services in SOA operate at a high enterprise level.
Splitting the application into loosely coupled, fine-grained, independent parts has some advantages:
- Scalability: With monolithic applications, achieving scalability is a challenge. It is possible to scale vertically (scale-up) by adding additional resources to a machine. Still, hardware has its limits, and at some point, high-performance hardware starts costing a fortune. On top of that, not all software components were designed to work with extremely high numbers of CPU cores or terabytes of RAM, which sometimes lead to memory leaks and performance dropdowns. To scale horizontally (scale-out), the whole application is duplicated and put behind a load balancer. MSA makes it possible to scale-out each part of the application independently. CPU-intensive and RAM-intensive microservices require different resources to be allocated, so every service is scaled-up separately and more efficiently.
- The best tool for the job: Microservices are accurately isolated and autonomous. It means that the engineering team can choose an appropriate software technology and use optimal hardware for a particular service rather than be stuck with only one technology selected years ago.
- Parallel development: Independent services simplify an effective workflow for multiple teams working on the same product. It increases the engineering team capacity and reduces time-to-market, as teams can develop more business features during the same period than with a monolithic application.
- Independent deployment: Each microservice can be deployed independently without disturbing the whole system.
- Fast changes: Parallel development, continuous integration and delivery pipelines, and automated testing enable faster features delivery.
- Reliability: MSA enables fault isolation by design. If one microservice fails, it doesn’t lead to the failure of the whole system when the circuit breakers pattern is implemented properly and business logic follows defensive programming principles. The system continues to operate only with limited functionality following the graceful degradation philosophy.
- Flexibility: Due to MSA’s parallel computing nature, it is well suited for the cloud environment. Clouds, in its turn, make it possible to bring in additional resources for peak loads and release them for idle time. Such functionality is usually rather expensive for on-premises solutions.
However, there’s no such thing as a free lunch. Microservices introduce complexity on their own. Let’s explore some questions raised by microservices.
Challenges of Microservices
Event-driven distributed systems with a variety of data stores are complex by nature. MSA brings both managerial and technical challenges:
- Complicated design. Domain-driven design (DDD) aims to connect the business model to the implementation. Still, one of the most challenging architectural tasks is distinguishing services based on domain descriptions and boundaries. In addition, the focus on new features during system evolution and the lack of re-engineering efforts during development can dilute these boundaries.
- Distributed system complexity. Interservice communication protocols, event buses, load balancers, service discovery, and monitoring increase the chances of issues in a distributed system.
- Data handling. Each microservice is isolated and handles its own data, and more than one of them can require the same data to operate. Data de-normalization and duplication are used for performance reasons and create additional tasks for data synchronization to keep data consistent.
- Transactions across multiple services. When each service uses its separate data storage, and these storages are heterogeneous, ACID transactions are no longer applicable. Synchronous two-phase commits (XA transactions) can only be used if each datastore supports the XA specification, which is not the case for most NoSQL databases. Choreography or an orchestration-based SAGA pattern is used to achieve eventual consistency with a tradeoff of transaction isolation level.
- API versioning. Services can have multiple versions of API, and several versions of each service can be in production simultaneously. It causes a combinatorial explosion of versions, where some additional mechanisms should be implemented to keep services compatible.
- Operational complexity: An increasing number of deployment services, datastores, and APIs can’t be deployed manually anymore. CI/CD pipelines and Infrastructure as Code (IaC) tools are used to automate the process.
- Debugging: Distributed event-driven system debugging can turn into a nightmare. The OpenTelemetry standard was developed to facilitate the task.
- Cross-team collaboration. Usually, separate teams are responsible for the development of a service or a group of services. One feature requiring two or more teams should be planned and implemented in tight coordination between teams, and it will inevitably lead to additional costs for dependency management.
The company should make a balanced decision on whether MSA is the right way to go. My cheat sheet below can help determine when it is possible to get benefits from using MSA.
Where Microservices Bring Value
MSA shines for complex system implementations. Each monolithic application has its scalability limit. It can be hardware when it is impossible to buy a more powerful machine or software that can’t handle the system’s amount of data or load. With years of enhancements, the monolithic application has become so bulky and complex that it can be hard to manage, scale, modify, and deploy. That’s when it is reasonable to consider the transition to MSA.
According to our experience, these are the main reasons companies switch to MSA:
- Zero-downtime deployments. Canary and blue-green deployment approaches are used to test new releases on a small number of users to decide whether to roll them out full-scale.
- Isolation of data and processing around data is a good fit for solutions in need of regulatory compliance like GDPR or HIPAA.
- Efficient scaling. Microservices are scaled independently, allowing teams to utilize available hardware and infrastructure efficiently.
- A higher degree of organizational autonomy can help to reflect the organizational structure. It applies to big companies and increases consistency in development processes. As the team size increases, it becomes exponentially harder to coordinate people.
As Martin Fowler said,
My primary guideline would be don’t even consider microservices unless you have a system that’s too complex to manage as a monolith <…> As the size and other complexity boosters kick into a project, I’ve seen many teams find that microservices are a better place to be. But unless you’re faced with that complexity, remember that the microservices approach brings a high premium, one that can slow down your development considerably. So if you can keep your system simple enough to avoid the need for microservices: do.
The company should examine and verify the scope of problems they are trying to solve. MSA is not a goal but another tool to solve particular problems. In many cases, the right thing to do is start separating modules inside a monolithic application and eliminating any module border violations.
The team must have expertise in a domain area and strong knowledge of microservices best practices and antipatterns to implement MSA correctly. The organization’s mindset should be changed.
In the end, MSA costs more than monolithic from a short-term perspective, but it can be the only way to go in the long run while scaling as per business needs.