The term “microservices” is being heard a lot in the software development world in the last couple of years. Since this is a topic that has sparked interest these days, we will try to give you a high-level overview of what a microservices architecture is, what it seeks to achieve and how it accomplishes its goals.
Let’s think about the type of systems that can be found in a lot of companies. Systems made up of big, complex monolithic architectures.
This type of architecture has the following problems that I’m sure most of you already know:
- It’s hard to maintain: Every change, even small bug fixes, implies that the whole system must be deployed again.
- It’s difficult to test: The bigger a system is, the harder it is to test. Every part of the system has a lot of dependencies with no clear boundaries.
- There are very few people, if any, who knows the system as a whole: Almost every developer knows only a part of it, which increases the probability to break something when a change is introduced.
- Every module must be developed with the same technologies used on the whole system: Same language, same database, same communication style between modules (if any).
- Scary deployments: The risk of the deployment is proportional to the size and complexity of the system.
- Big learning curve for new developers: It’s hard for new members of the development team to start working right away on a system of this size.
All of these problems, and others not mentioned here, are frequently the main reason for which companies can’t deliver new features to customers on time and without risks. But… what can we do about it?
Decouple your system into services
A microservices architecture allows you to decouple a complex monolithic system into simple, independent and reusable services, which talk to each other using a standard communication channel.
A service is a standalone application that has a very specific purpose. It must be simple and small. It should expose its functionality through an API. This API must be exposed through a standard communication channel using, for example, a REST Web Service or a Message broker. Also, it can use its own database to store its data.
Every interaction with other services must be done through the API they expose. Additionally, each service must allow having several instances of it running in parallel.
This definition of a service has several advantages:
- Being simple, small, independent and with a very specific goal allows the service to be easily tested, maintained, and upgraded.
- Each service can be developed with the technologies that you consider the best for each case. For example, you can have a service in Java with a Postgres Database and another service implemented in Python and MongoDB. Since their communication is exclusively done through a standard communication channel, each service can use the technologies that are best suited for their tasks.
- Since services are autonomous, they can be deployed independently. If you need to introduce a feature on, for example, your Customers service, you can upgrade only that service, leaving the rest of the services untouched.
- Also, considering that you can have multiple instances of the service running at the same time, deployment risks are reduced to a minimum. You could even leave the last version of the service running while you introduce the new version. If there is a problem, you simply stop the new version instance and leave the original version running. This also reduces the downtime of your service to almost zero.
- You can have a team of developers for each service. This allows each application to evolve independently of each other, in parallel. The only thing each service must know of each other is their API, which must be clear, simple and stable.
- It promotes re-usability. Since a system now becomes a composition of services, you can reuse your services to create new systems.
- It’s prepared to scale. Every service can scale independently from each other.
- It’s a resilient architecture: Each service must be prepared to degrade gracefully, so if one instance fails, the rest can still run without bringing the whole system down.
Everything has a cost
Of course, not all of these advantages comes for free. This type of architecture has the following challenges:
- Being a system composed of services, a single request can span several instances of other services. For example, if you have an e-commerce system, a single purchase request could span a request on the orders service, which could make a call internally to the customer’s service and the products service. Your infrastructure must be prepared to track a single request through all the services it passed through.
- Since you can have a lot of services, and each service could have a lot of instances, it’s imperative that you automate their configuration and deployment.
- You must have a service discovery mechanism so services can register themselves and find each other automatically.
- It’s almost mandatory to have a monitoring system in place. You need to have a global picture of the status of all your services so you know when one of them is failing and why. This brings another important rule: Every service must be prepared to send monitoring data to the central monitoring system. This greatly simplifies the detection of problems or performance bottlenecks.
As you can see, a microservices architecture is a great way to decompose a complex system into smaller and simpler services, but as it also has a bigger cost in terms of the infrastructure, it needs to be really effective and maintainable.
Here at Intraway, we’ve started the exciting journey of implementing a microservices architecture for our new products. Although it has a lot of challenges to overcome, all the advantages it provides really worth the effort of the implementation of this type of architecture.
Thanks for reading!