What Are Microservices? Pros, Cons, and How to Build Them
Microservice architecture is one of the most talked-about topics in software development. In this article, you’ll find out what microservices are.
What Are Microservices?
A microservice system is an architectural style used by many large-scale software projects. The aim is to improve efficiency, reliability, performance, and scalability. Let’s compare microservices with the traditional approach, often called monolithic architecture.
Last Updated April 2021
Use Kubernetes to deploy a Microservice architecture. You’ll deploy, manage and monitor a live Kubernetes cluster. | By Richard Chesterwood, Virtual Pair Programmers, Prageeth WarnakExplore Course
A monolithic architecture is where people develop an entire system as a single unit. This is simple to manage and is an efficient strategy for small projects. The benefits of a monolithic architecture include that they are:
- Easy to develop: You can open the entire project in an integrated development environment (IDE) or even a text editor.
- Easy to run: You can hit the run button in your IDE and start testing.
- Easy to deploy: You can deploy the entire system by uploading a single file — for example, a WAR file in a Java application.
But all of these advantages only apply to small systems.
As the system grows beyond a certain size, difficulties arise. And the more the system grows, the greater the difficulties. This can lead to a so-called “monolithic hell!”
Problems might include the following:
Deployment gets harder and riskier
Imagine that you uncover a major bug. You need to fix it, now! So, you fix the bug. Now, the entire system needs redeployment! But right now, there are other features that are in development. So the risk is that while you fix one bug, you introduce many others.
The big bang alternative
The alternative is for projects to restrict deployments to “big bang” releases. This means that a deadline is set to commit all changes and new features. Only when you’ve tested the entire system is the system deployed. This feels like a safer option, but the big problem is that you can no longer issue emergency fixes. And as the project grows, the deadlines have to get longer and longer. If your project releases once a year, then you’re stuck in monolithic hell!
It becomes too big and too complicated.
The monolith could become too big for a single developer to understand. Enforcing the boundaries between modules is too difficult. Over time, the modules become entangled in a mass of dependencies. Have you worked on a monolith where you’ve made a change to a module, only to discover you have broken another module? If you thought these modules were unrelated, then you’re working on a Big Ball of Mud!
The monolith becomes difficult to scale.
As the deployment unit grows, the only option is to increase the size of the target hardware. In a cloud environment, this means upgrading to a bigger virtual machine. This is called vertical scaling and is very inefficient because the costs do not scale linearly. For example, if you need a new machine with twice the memory, the cost will be much more than double. And, at some point, you will hit a hard limit of what is practical.
The alternative: a microservice architecture
With a microservices approach, we develop a collection of separate microservices. Each microservice would be:
- Developed by a separate team.
- Hosted in its own repository (such as Git).
- Performing a useful business function.
- Independently deployable.
- Runnable standalone and doing something useful and testable.
- Able to collaborate with other microservices to fulfill a bigger goal.
How microservices collaborate is a subject for a full, separate blog post. They can be simple representational state transfer (REST) web services, or we can use more sophisticated asynchronous messaging systems.
It’s easy to define what a microservice architecture looks like, but it’s much more difficult to build one! How do you determine what the microservices in your system should be? How big should they be? There is definitely some “art” here, and it is hard to be precise, so let’s run through the features of a microservice.
A microservice should be organized around business capabilities
For example, an e-commerce site isn’t just a “shopping cart.” It handles inventory, product catalogs, billing, customers, orders, and so on. These business functions are potential candidates for microservices. For example, inventory management sounds like a candidate microservice, provided that it fulfills the rest of the criteria for a microservice.
A single team will develop, deploy, and operate a microservice
One team takes full ownership of a microservice. This ensures that the microservice can’t become too big. And each developer in the team should be able to understand the entire microservice. A rule of thumb from Amazon is that two pizzas should be enough to feed everyone in any team meeting. Of course, this is vague guidance (how big is the pizza? I can eat a whole one). I prefer to be more specific and set the limit at six to eight team members. Can the team of eight develop an inventory management service? If so, it might be a suitable candidate. If not, then that microservice is too complex and would need further decomposition.
It is important to keep in mind that it is impossible to get this right the first time. A good microservice project will embrace flexibility. If any microservice becomes painful to work on, a good project will refactor it into two or more new services.
A microservice should have high cohesion
At the core of microservices is the same principle that is at the heart of any good software design. High cohesion means that a single microservice must do one thing and do that one thing well. Of course, what “one thing” means is vague and is down to judgment. But it will help to remember that a microservice should align to a specific area of the business.
Imagine that the inventory management microservice also calculates the tax of each item. Maybe it was easier to develop that way. Well, that would be a sign that a vital microservice is missing elsewhere. Perhaps a tax service?
Things that change independently need to be in separate microservices. Tax rates change all the time. It would be painful if we had to update and test the whole inventory service every time a new tax appeared!
A microservice should have loose coupling
The dependencies between the services should be as small as possible. Changing one microservice should have minimal impact on the other microservices.
Independent deployment of microservices
Each microservice should be able to be redeployed at any time, with no impact on the rest of the system. Imagine that you discover a bug in the inventory microservice. The team can deploy the change to the live system without the need to consult other development teams.
Automation of microservices
You might be able to put up with the pain of manually deploying a monolith application, spinning up a few cloud instances to host it, or installing software onto those instances. But forget about scaling that up to 100 deployments or 1,000 instances. Microservices depend upon the automation of deployment, provisioning, and configuration management. Continuous integration or continuous delivery is a must with any microservice project. Martin Fowler has some excellent information on this.
Microservices are often distributed systems
You could deploy all your microservices to a single server. Or, in an extreme case, you could have a single server for each microservice. This would be a very effective way of enforcing separation! Of course, for most projects, this would be very expensive.
The best solution is to use Docker to turn each microservice into a container, and then use an orchestration tool to manage the running containers. The most common orchestration tool is Kubernetes. Kubernetes uses load balancing and replication to achieve a high level of resiliency.
Advantages of a microservice architecture
The biggest advantages of a microservice architecture include the following:
- You enforce good modular principles, cohesion, and loose coupling.
- You can deploy and redeploy individual services at any time. Changes and new features can be introduced quickly.
- Each microservice can be written in any language you choose. This is called polyglot programming. For example, a financial microservice might be best written in Python. On the other hand, you might choose C for a graphics processing service that needs high performance.
- If a microservice becomes a problem, it can be thrown away and redeveloped from scratch.
- As the microservices can be distributed, it is easy to scale the system horizontally. That means the microservices can be divided among many machines. This is much cheaper than scaling vertically (buying a more expensive machine).
Disadvantages of a microservice architecture
But there are also some disadvantages of microservice architectures:
- The principles are simple, but putting them into practice is hard. For example, deciding on what the microservices are is subjective.
- Some badly run projects are switching to microservices, hoping to solve their problems. When things don’t go well, they wrongly blame the microservices.
- A lot of tooling has to be in place: automation, continuous delivery, source control, etc.
- It can be difficult to run and test a microservice in isolation.
Should you build a monolith or a microservice architecture?
A monolith app is reasonable if a single team can develop and operate it. Once you go beyond that size, then the pain of the monolith hell becomes unbearable. But you can’t just switch to microservices and expect it to solve all your problems!
I hope you enjoy your microservice journey!
Top courses in Microservices
Microservices students also learn
Empower your team. Lead the industry.
Get a subscription to a library of online courses and digital learning tools for your organization with Udemy for Business.