From Monolithic to Microservices Architecture - What to expect?

From Monolithic to Microservices Architecture - What to expect?

We all have been hearing about Microservices for quite a time now. Sometimes, people often compare companies based on the number of microservices they are running.

Company X has 300 microservices running at any point in time

Let’s pause for a while and think why do we need so many microservices. Is it necessary? What factors decide that we need X number of services? Why should we break a service(monolith) into multiple services?

Before diving deeper, let’s understand first what exactly are microservices.

Microservices are smaller pieces of software that have their own area of concern and only fulfill a specific business need and communicate with each other which makes the platform function as a whole.

E.g. For an e-commerce site, the front end for the main landing site can be one service. Similarly, the backend, billing, and products search can be three different independent services.

On the other hand, a monolith is a single service/application which serves the need of the entire platform and has all business logic cramped into a single app. There is no need to have another internal service. Pretty straightforward set up as it sounds.

Okay. Now we have a general idea of what microservices are, let’s jump into cases where microservices architecture is useful.

1. Working across multiple development teams

It is fine if you have a single monolith app and a couple of people working on it. Eventually, your app codebase grows and It starts serving a variety of business needs. You will need more people to work on various business domains (e.g. recommendation system, user management and search, new product alerting mechanisms). Imagine 50–100 people working on a single repository/codebase on hundreds of things. What a mess would it be. One’s work is conflicting/dependent on others. In this case, the major benefit of microservices is the decoupling of development and deployment.

2. Independent scaling

Imagine if you have an entertainment website that has almost 20–50 games that can be played online. Let’s also assume you also have a meme generator tool on your site that is very famous. Imagine the case where the meme generator gains more popularity resulting in 1 million API calls per second. However, other games on your website are not that popular and their usage is low. Your server runs out of resources. What do we do in this case? We can separate out the meme generator API and then scale it as much as needed keeping the other functionalities of the website at minimal resource configuration.

3. Working with different Technology Stacks

E.g. Your primary stack is Ruby but for a specific problem, you have decided to use GoLang. There is no other way than having two separate services which work together as a part of the same system.

Don’t Build a Distributed Monolith!

There is also a chance that we might have separated a perfectly working monolithic app into microservices that are not decoupled at all. There are few questions that we can ask ourselves in order to identify if we are working on distributed monolith or not.

  • Are the microservices too chatty?
  • Do they share a common database?
  • Does change/deployment in one requires change/deployment in another?
  • Do they share some code?
  • Are microservices maintaining a cache of each other’s data?

The Microservices Mindset

Things drastically change when we move from monolithic to microservices architecture. We need to think about how the development teams and processes need to be structured, how microservices talk to each other and handle all failure cases. More microservices mean more points of failure. Things might also get pretty complex depending on the nature and scale of the system. We need a mindset change for an easy transition. Here is the list of things we should be thinking about:

  • Cost: Infrastructure, People, Management

    Yes! The very first thing. Keep in mind that, every decision comes with a cost. One simple example, let’s assume you had a single server setup before which could scale to N instances if needed. Now, you have M microservices with databases and everything which can autoscale to N instances. All of these microservices require some other setups as well. Now, you need more people to work on these. Also, there is a management cost for all microservices. Don’t make them too micro resulting unnecessary number of microservices.

  • Working Across Teams: Communication

    You will have multiple teams to work on different sets of microservices. Each team will look only into certain business domains and the microservices which fall under the domain. Suddenly there will be less visibility of what other teams are doing. Do a sync-up meeting regularly. Focus on documentation and sharing.

  • Re-evaluating priorities across teams

    Team 1 need to build a feature on microservice Product Search on coming sprint which requires a change in the Billing App which falls under Team 2. But Team 2 has other higher priority tasks to work on than the change requested by Team 1. *What to do now? In this case, we need to zoom out from the development teams’ scope and think in terms of business. Select the work which adds the most value to the business at this point in time amongst all. It is necessary to realize that we(all development teams) are all working for a common goal.

  • Working on a Microservice as a Developer

    Previously, there used to be a few apps or a single app that would not depend on anything else. We could just boot up one app and test. But now, one microservice can depend on 2–3 other services. So we need to boot them all in our local machine. You can group related microservices in a single cluster and fire up all apps as Docker containers using Docker compose. Another approach could be mocking all other services which are not required while doing development on a particular microservice. But sometimes mocking does not work because one transaction in service X might trigger database create request in other Y and Z services and we need to fetch the actual data from the database from service Y and Z in service X and the data must be in sync across all services. Explore different approaches to select the best fit for you which makes it simple and easy for the developers.

  • Proper Release/API Documentation

    Different teams need to look into what other teams are planning to work, working, and have worked on. E.g. In the case of API development, we can finalize and release the documentation of APIs earlier to other development teams before we actually start working on it. This way, we will have documentation as well as visibility. Yes, you can ignore documentation and deliver work but in the coming days, your team/org will definitely going to suffer because of assumptions and miscommunications.

  • Defining Standards

    We have different teams working on different microservices and if there is no any guidelines/standard, there could be different versions of microservices which is difficult to manage. The core service setup needs to be the same. So, we need to define standards for things like microservice codebase layout, coding standards, conventions, and things that should be present in any microservices(authentication, logging, error handling, error formats), so that there is no difference in the foundational elements in all microservices developed by different teams. You can also build a bootstrapping tool for creating a new microservice that all teams can use. It will also be easy to onboard a new person in any team if we all follow the same standards.

To build resilient microservices, we also need to make sure we have taken care of the following things:

  • Interservice Communication

    Microservices are loosely coupled and they still need to talk to each other. Choose appropriate tech stack for Synchronous(eg. REST, gRPC) and Asynchronous(e.g. Messaging systems like RabbitMQ) communication. Consider latency while choosing the protocols.

  • Timeouts

    What if some service is not responding timely? How long to wait? E.g. Service X requests service A for something. Service A takes some to build the result and attempts to return back the result to service X. But service X is no longer there. The connection has timed out already.

  • Failure Handling and Recovery Strategies What if some service is not able to process requests at this point in time due to some error? What if some service is not available? What message do we show to the users? We might need to have failure recovery strategies like rolling back to a previous working state.

  • Observability

    We should be able to look into how well the microservices are doing.

    • Metrics: You will need a place to look into how well the microservices are behaving. Metrics like response time, success rate, request volume, Memory/CPU Usages are super helpful in day-to-day monitoring.

    • Tracing: A request has passed through multiple microservices and one of the microservice somewhere in-between is sluggish resulting in a large round trip time. We should be able to trace the request and see where it is going and how much time it is taking in each microservice to detect the sluggish one. We can use APMs(Application Performance Monitoring) tools like Newrelic, Sentry out there that provide these features.

    • Logging: A request initiated from service X failed on service Z while passing through service Y. We should be able to look into the logs and determine where and why it failed.

  • Distributed Transactions and Rollbacks: In a complex system, one event can trigger cascading transactions on microservices one after another. If any transaction fails somewhere in-between, we need a mechanism to identify at what point it failed and what transaction has already been completed and then to roll back to the previous state canceling the successfully completed transaction as well.

Conclusion

Start Small — Evaluate — Make Decision

Starting with a single monolithic app is the best idea. Break it into just 2–3 services based on the need. You will be able to get a rough idea of what it looks like. Analyze the cost. Microservices architecture is fit for you if it allows developers to work faster, independently, and efficiently across teams and also it is easier to package, deploy, manage the services independently and worth the cost. Don’t just switch to microservices because they are the current trend and everyone is doing it.

Thank You!

Hope this article was helpful.

References:

Did you find this article valuable?

Support Nirdosh Gautam by becoming a sponsor. Any amount is appreciated!