Moving to Microservices
Moving to Microservices
Microservices has advantages and disadvantages. Take a look at how to reap the benefits while migrating from a monolithic architecture.
Join the DZone community and get the full member experience.Join For Free
Learn why microservices are breaking traditional APM tools that were built for monoliths.
The microservices concept is similar to a “divide and conquer” type of architectural approach. This approach has been around: service-oriented architecture. Technologists are attracted to microservices mainly for the following set of predominant benefits:
- Development dependencies: Minimized code conflicts, ability to deploy partial implementation through isolated developments and deployments specific to each service.
- Scalability: Distributed horizontal scaling to overcome fault tolerance issues and performance issues with geospatial users.
Microservices as a concept is an illusorily simple one. Ideally, they are multiple self-contained single-service applications (extracted from a centralized monolith architecture, in the case of migration) that are de-centralized/distributed and talk to each other through predefined APIs.
“If you can't build a monolith, what makes you think microservices are the answer?" -Simon Brown
These microservices benefits are not that easy to deliver if there are no proper architectural plans and goals predefined in the course of this movement. Microservices architectures can become complex to manage. Distributed systems have ways of failing that you’ve never thought of before.
Let's explore further on these benefits and how to achieve a closer effect without moving away from the monolith:
A very common attraction to migrate to microservices architecture approach is to make it easy for managing development dependencies that are being faced by teams. If you have a large team all working on the same big codebase then that can cause clashes and merge conflicts and there will be a lot of code for everyone to understand.
Points to be considered:
Code Conflicts Mostly Arise From Communication/People-Practice Issues
It would immediately seem very easy if all the services were smaller and isolated by a clear interface. That way each microservice could be owned by a small team who could all work together.
The actual problems with code conflicts and clashes are mostly related to communication problems or team management problems. Although technology approaches/tools will help to improve the situation, they cannot eradicate this completely. Revisiting this in terms of resolving people and communication issues instead will definitely improve cultural situations.
“[With distributed teams] Face-to-face communications are rare. Hence fewer connections between modules are established. The architecture that evolves is more modular as a result of the limitations on communications between developers." –Harvard Study
Local Development Environment Overheads
In addition, many technologists, when deciding to move towards microservices, don't consider the local development environment-related complexities that will come along with it. In case of a monolith approach, this will be a piece of cake, whereas it will be complex to achieve if the microservices have multiple services interdependent on each other, in terms of achieving a single business workflow lifecycle. Containerized solutions also will not be that easy when it comes to local environment setup.
The self-contained nature of microservices allows an individual instance of a microservice to be decoupled not only from other microservices but also from itself. This allows running of duplicate services in parallel. This effectively brings in horizontal scaling. As an additional effect, it provides resilience and a way to achieve fault tolerant systems.
Points to be considered:
Data Tier Isolation
Most technologists who adopted microservices still use the same data tier for all of their microservices (i.e. not isolating the data tier for each microservice to handle its own responsible data). This setup brings in the horizontal scalability only for your service and not for the entire applications. There are hurdles to achieving clean data-tier isolations when aligning with the microservices/modular separations. One example is achieving distributed database transactions. This will require re-architecting the business logic adhering to the saga pattern or using Java DSL with Spring Integration techniques.
“In general, application developers simply do not implement large scalable applications assuming distributed transactions." –Pat Helland
Resilience, Fault Tolerance, and High Availability Through Scalability
If the aim for scaling out is just to achieve fault tolerance and high availability, then the easiest way to scale a monolith is to simply deploy additional copies of the subject monolithic applications behind a load balancer. This is a straightforward way to scale up if your system receives more traffic, and it involves minimal additional complexity from an operations perspective. Even in a cloud environment, this can still be achieved using something similar to Beanstalk techniques. Just optimizing CI/CD settings will be enough to manage these multiple copy deployments properly.
The multiple modules within the monolith application (with well-defined APIs) nearly have zero overhead when interacting with those APIs. This is definitely not the case with microservices, since they are often running on different host machines and require a network between the services. This can slow down your whole system considerably (if they are getting hosted on-premise microservices platform). This situation becomes even worse if you have some services which need to contact multiple other services, synchronously, in order to complete a request (i.e. response time for a particular business transaction may increase due to underlying network issues, if not established and monitored properly).
Starting Monolith Improvements
Following rough guideline stages shall be incorporated into the context of the subject monolith application if applicable. These stages will typically solve many of the problems that cause teams to move towards microservices, and without all the associated complexity/learning curve/high amount of time & effort. And yet taking it to closer to the similar benefits that we may expect from microservices.
- Refactor application to make sure to bring in automatic testing.
- Refactor application into isolated modules with clear API definitions without encouraging any overlap of code pieces into the modules directly. All modules must talk through APIs only.
- Choose critical module(s) and take it out of monolith application pack, split it into its own application on the same host (if capacity allows). The communication and security setting will have to be sorted out treating them as two different applications interfacing with each other through properly defined APIs. This will be a step that makes a module ready for further distributions in future if traffic for that particular increases.
- Move separated module(s) and put it on a different host system(s) (VM(s)) for the purpose of size optimization specific to the nature of these modules. (i.e. one module may require more memory allocation than others, considering the amount of data it might require in the course of processing a request). This shall be duplicated with front-ending load balancer for achieving fault tolerance and high availability.
- Finally refactoring the data tier for bringing in the same level of isolation that has been introduced at application modules’. If it is RDBMS, try to see for options to improvise with ORM and ORM caching techniques to improve performance. It might be started with a separate set of database tables isolated from each module within the same database as an intermediate step to assess and understand the complexity involved before isolating them into a separate database.
This is simply a summary of my observations and collation of other's experiences in the journey of migrating to microservices from monolith architecture approach. Hope technologists shall find these high-level concepts useful to factor-in while preparing/considering for movement towards microservices approach. If there are strong prerequisites that are in need of microservices architecture approach, they may exempt from these stages.
Opinions expressed by DZone contributors are their own.