Microservices are not a completely new concept. In the past, there have been many attempts, such as EJBs, Remote procedure calls (RPC), and implementations of services through SOAP, that aimed to reduce dependencies among various application components. Let’s look at a formal definition to set the context and then we will try to understand it in detail:
“Microservices – also known as the microservice architecture – is an architectural style that structures an application as a collection of loosely coupled services, which implement business capabilities. The microservice architecture enables the continuous delivery/deployment of large, complex applications. It also enables an organization to evolve its technology stack,” http://microservices.io/
As the name suggests, microservices entail breaking services down to a micro level. The next most important aspect is to think about these microservices as independent entities that can be developed, tested, deployed, and managed as complete sub-applications in themselves.
The following diagram demonstrates a microservices-based implementation of an employee management system:
Notice that the services have been divided at a granular level. For example, we are supporting Excel and PDF-based reporting, but the actual generators need not be part of the reporting service. The reporting service should only be responsible for generating data, but how the data is represented should not be part of this service.
An additional advantage it gives us is that, if in future, we want to support other formats, say a Word DOC report, we don’t need to touch any of the existing code; we just create a new service, say Word Document report generator, and plug it in. So we can say that a Microservices-based architecture is easy to extend and maintain.
As we have divided the application into smaller services that can be managed independently, we also talk about smaller teams and decentralized management. Each team can take independent decisions on the design and technology stack they want to use, and hence there is no dependency on other teams. Each service can be easily tested independently.
Another thing you might have noticed is that each service is deployed independently. Well, this might not be the exact scenario and you might deploy multiple services on the same machine, but the idea is that you should have the capacity to deploy each service independently.
Though we have not looked at the data storage part, ideally, each service will manage its own data. There should be a single point of managing one data entity. This helps in the decentralization for data, which helps with easy scalability and maintenance.
Communication between the services is another important aspect you should consider when choosing a Microservices-based architecture. We need to decide whether the communication needs to be synchronous or asynchronous, through REST, Queue-based, or some other communication medium. A well-architected system will be fault-tolerant, as a failure in no single service can bring down the system as a whole, so there is no single point of failure.
There are no fixed, industry-wide set of rules to follow for a microservice-based architecture. This causes a lot of confusion, as well as flexibility. But to keep it simple, let’s take a look at some of the common characteristics of a good microservice-based architecture:
- Decoupled architecture
- Independent deployables
- Decentralized data
- Smaller code bases and teams
- Decentralized management
Next, let’s take a look at some of the advantages and challenges that can be expected when using a microservice-based architecture.
Advantages of Microservices
Now that you’re comfortable with the concept of microservices, let’s take a look at the advantages they provide. Most of the challenges of Monolithic applications can be handled by the use of a microservices-based approach. The following are some of the advantages of a microservices-based architecture:
- Easy-to-manage Code: As we are able to modularize and divide our huge application code base into various Microservices, we are not dealing with the whole application code at any point in time.
- Flexibility of choosing the tech stack: As every Microservice we create is potentially a separate application in itself with a different deployable, it is easy to choose a technology stack based on need. For example, if you have many Java-based services in an application, and a new requirement comes in which you feel can be easily handled by using Python instead of Java, you can go ahead build that service in Python, and deploy it without worrying about the rest of the application.
- Scalability: As every Microservice can be deployed independently, it is easy to scale them without worrying about the impact on others. For example, let’s say we know the reporting service is used heavily at every end of a quarter – we can scale only this Microservice by adding more instances, and the rest of the services remain unaffected.
- Testing: Unit testing, to be more specific, is easy with a Microservices-based approach. If you are modifying the leave-management service with some new rules, you need not worry about other services, such as Employee Project Management. In the worst case, if your leave-management service breaks down due to faulty code, you can still edit and update the Employee project-related information without even knowing that some other service is broken.
- Faster time to market: As we are dealing with only one part of the application at a time, it is easier to make changes and move to production. Testing and deployment efforts are minimal as we are dealing with a subset of the whole system at a time.
- Easy to upgrade or modify: Let’s say we need to upgrade a Microservice, upgrade software or hardware, or completely rewrite the service, this is much easier in a Microservice based architecture, as we are only upgrading one part of the application.
- Higher fault tolerance: In a monolith architecture, one error can cause the whole system to crash. In a Microservice-based architecture, in the worst case, a single service will crash, but no other services will be impacted. We still need to make sure we are managing errors properly to take advantage of Microservice-based architecture.
Challenges with Microservices
However, microservices are not a silver bullet. Along with all the advantages that come with microservices, we need to be aware of the challenges that they bring if not used properly:
- The right level of modularization: You need to be very careful in determining how your application can be divided into microservices. Too few would mean you’re not getting the proper advantage of microservices, and too many services means a heavy dev-ops requirement, to make sure all the microservices work well when deployed together. Too many microservices can also have a performance impact due to inter-service communication needs. You need to carefully analyze the application and break it down into logical entities, based on what would make sense to be thought of as a separate module.
- Different tech stacks to manage: One of the advantages of a microservices-based architecture is that you are not dependent on one technical stack or language. For example, if one of the services is coded in Java, you can easily build another one in .NET or Python. But if you are not careful, this advantage can quickly become a problem. You might end up supporting dozens of technical stacks and managing expertise for each service independently. Movement of team members between projects or among teams is not an option if required, as one team might be working on a completely different tech stack than other.
- Heavy reliance on Dev-Ops: If you are using too many microservices, you need to monitor each one and make sure all the communication channels are healthy at all times.
- Difficult fault management: If you have dozens of services communicating with each other, and one of those goes down or is slow to respond, it becomes difficult to identify the problem area. Also, you do not want that problem in a single service to impact other services, so you will need to make sure arrangements are in place to handle error situations.
- Managing the data: As a rule of thumb, we try to make sure every microservice manages its own data. But this is not always easy when data is shared among services, so we need to determine how much data each service should own and how the data should be shared among services.
When you are architecting the system, you need to make sure you understand these challenges and take care of them before committing to a solution.
Hope you found this article insightful and interesting. If you’d like to learn more about microservices, you should check out Java EE 8 Microservices. A step-by-step guide to building flexible and scalable microservice architectures using the various components of Java EE 8, Java EE 8 Microservices is a must-read for Java EE developers keen on building microservice-based applications