Intro
Microservices have gotten a lot of publicity over the last few years. Companies like Netflix, Stripe, Uber and many others have migrated to microservices architectures and seen incredible results. As far back as 2018, reports show that over 63% of companies use microservices to ship faster and build more resilient applications.
But there has also been a lot of controversy around microservices. Recently, AWS published a blog post talking about how they “migrated away” from a traditional microservices environment and were able to reduce their infrastructure costs by 90%. I put migrated in quotes because I would argue that what they refactored was their serverless stack and not their containerized services. But that’s a debate for another day.
Similar to any other tool and technology, microservices have their pros and cons, they’re not inherently ‘good’ or ‘bad’ (regardless of what DHH has to say). They’re just a tool or a pattern to achieve an outcome.
So, why the controversy? I think a lot of it stems from two main problems:
- A lack of understanding what microservices are
- A lack of understanding of when to use microservices and when not to use them
I’m going to address both points below and give a framework that I think can be useful in determining if and when you should use microservices.
What are Microservices?
The word ‘microservices’ gets thrown around a lot and there are a lot of misconceptions so I think it’s important to level-set on a common definition to ensure that we’re speaking the same language.
First, microservices should follow the Single Responsibility Principle (SRP). Your microservice should implement and execute a single piece of business logic i.e. it should have a single responsibility.
For example, in the graphic above, you can see a monolith that’s been decomposed into microservices. The Users microservice can handle things like registering and removing users. The Posts microservice handles creating, editing and deleting posts. Each microservice is responsible for one functional part of the application.
A second component of a microservice is that it should be independently deployable, ideally containerized. You should be able to update the code and deploy it independently of having to redeploy the entire system. In our example above, the Users microservice would be a containerized service that is independently deployed from the Billing service, even though it makes an API call to the billing service.
This is important because each microservice should be able to scale independently. You may be running a SaaS product that gets a lot of user sign ups but not every user uses the billing features. This means that your User microservice may need more compute than your Billing microservice because of the different traffic demands on each microservice. By independently deploying each microservice, you can easily manage compute needs by microservice without overpaying for compute that only one component needs.
Lastly, microservices communicate using well defined interfaces and APIs (REST, SOAP, gRPC) and usually run within their own process. In our example, each arrow is an API call to another microservice.
What is a Microservices Architecture?
Now that we’re settled on what a microservice is, let’s talk about bringing microservices together to create a microservices architecture. Given that microservices, by their nature, are independently deployable pieces of code, a microservices architecture stitches these independent blocks into a cohesive network. Platforms like Kubernetes make it easy to orchestrate and manage these microservices architectures and scale them as they grow. Microservices architectures vary in terms of the components they have and structure they take but generally most have:
- Service discovery - helps services locate and communicate with each other, works closely with service registry.
- Service Registry - registers services to a central registry that broadcasts that those services are available to handle requests.
- Load balancer - distributes incoming requests to appropriate service instances as to not overload any given instance.
- API gateway - routes API requests to the appropriate microservices, and authenticates and authorizes those requests.
- Circuit breaking - helps prevent cascading failures by interrupting communication between services when one is unresponsive; can be implemented by a service mesh
- Service monitoring - tracks the health and performance of microservices, generating alerts in case of failures or performance degradation.
- Service mesh - infrastructure and networking layer that helps microservices authenticate, authorize and communicate with each other; can provide monitoring and tracing as well.
- Configuration server - centralized repository for storing configuration information. This data is accessible to all microservices.
From a people perspective, devops and platform engineering teams typically manage and extend microservices architectures as companies release new products and update existing ones. We'll do another blog on how to actually build a microservices architecture but this is a good overview of the components in play and how they interact with each other.
When to use Microservices and when not to use them
We've learned what microservices are and what a microservices architecture is and now its time to discuss when to use it (or sometimes more importantly, when not to use it!) Many teams, architects and authors have debated over which is better: a microservices or a monolithic architecture and the answer is the unsatisfyingly: 'it depends'. At the end of the day, it really depends on the team, the product and the organization. Adopting microservices isn't just a technical decision, it's really an organizational one. And with that comes a lot of questions that you have to answer. Can our teams handle sometimes complex dependencies between them and communicate well enough to resolve those? Are our devops and infrastructure teams strong enough to handle the complexity that comes with microservices? What are we really solving for by moving to microservices? What can we build vs. buy?
These are just some of the questions to consider when deciding if moving to microservices is the right for your team. But I promised above that I would provide a framework so I want to at least give some guard rails on making this decision. So here we go:
When to use Microservices
Generally speaking, microservices work well if you have a larger engineering organization that is segmented into smaller teams that work on defined parts of your system. Microservices can help these types of team operate with less overhead and ship faster than integrated teams that have to coordinate updates. Here are some signs to look out for that might signal that microservices can help:
- You have variable workload requirements across your application. For example, one part of your system may get a lot of traffic or high have compute requirements while other parts of your system are pretty predictable.
- You have small distributed teams that focus on components of your system and prefer to work independently with low overhead
- You're building a lot of independent building blocks as part of your system such as APIs or integrations
- You're noticing that your team is shipping features slower do to the overhead of coordinating changes and updates
- You're re-writing legacy applications and want to write new components in different programming languages
When not to use Microservices
Generally speaking, if you have a small team and relatively simple application then you probably don't need microservices. A monolith or architecture where you have just a few services may work just fine until either the team starts to grow or your traffic and compute requirements change. Here are some signs to look out for that might signal that microservices aren't the right choice for you:
- You have a relatively small and straightforward application
- Your application has pretty predictable compute requirements
- You have a smaller team that coordinates well together
- You don't have a devops or infrastructure team that can handle the complexity that comes with microservices or has no experience working with microservices
- You're still able to ship fast and with little overhead and complexity
Wrapping
Microservices don't have to be as misunderstood or confusing as they may seem. At the end of the day, they're just another engineering design pattern that's designed to help teams build scalable and reliable applications. The context of the application and the team should be the primary drivers in determining if microservices are the right choice. If you have any questions or want to see what it's like to deploy microservices, sign up for a free account here on Nucleus.