Over the past few years, we’ve been building the frameworks and libraries that will enable us to move our application infrastructure to a microservice based architecture. So what, exactly is a microservice?
According to Martin Fowler, who has written extensively on the topic:
In short, the microservice architectural style is an approach to developing a single application as a suite of small services, each running in its own process and communicating with lightweight mechanisms, often an HTTP resource API. These services are built around business capabilities and independently deployable by fully automated deployment machinery. There is a bare minimum of centralized management of these services, which may be written in different programming languages and use different data storage technologies.
So when it comes time to implement a microservice, what are it’s characteristics? What goes into a service and, perhaps more importantly, what does not go into a service? The following are 4 key microservice characteristics:
Responsible for Only One Thing
A microservice should follow the SOLID software development principle–particularly the “S” of SOLID: The Single Responsibility principle. This means that it should have one and only one reason for changing. So, for example, you might have a user registration service, a billing service, and a review service. Each of these services is responsible for a single aspect of the overall application.
It can sometimes get a bit tricky deciding what the single responsibility of the service should be. Should there be a single “billing” service which manages all aspects of charging customers? Maybe there are separate services related to managing payment methods, sending invoices, charging credit cards, etc.
Shares Nothing
The microservice manages it’s own functionality and data and doesn’t share either of these with other services. If another service needs something the microservice is responsible for, it should use the established communication protocols (HTTP, message queues, etc) to get at that information.
Private Data
The microservice manages it’s own data storage mechanism. It doesn’t share that with other services. That is, the service defines whether the data store is a relational or NoSQL database, flat files, or stone tablets. No other service should be accessing this data store directly.
Instead, the microservice should define APIs or other communication channels that allow other applications to access the data. This encapsulates the data and allows the microservice to change how it’s stored, add caching in front of the data, if necessary, and ensure that the data is always in a consistent state. It should not have to worry about the data changing out from under it.
Private Implementation
Microservices should not share their implementation via a shared library. The idea is to share functionality via a deploy-time dependency.
If an application needs to run a particular process, it should call one of the APIs exposed by the microservice. If multiple applications share a common library, it makes it harder to make changes to the underlying system. For example if the data storage mechanism changes (see previous point) or some key business logic changes, you must deploy a new version of every service that uses that library instead of just deploying a new version of the microservice.
Has Strength in Numbers
As with most things in life, microservices work best when deployed in groups. That is, you should endeavor to build microservices such that multiple instances can be deployed simultaneously.
This allows the service to be scaled horizontally in order to respond to increased demand. It provides redundancy, allowing the service to continue running when one instance fails. This means that if there is any functionality that should only run once, it should be protected by some kind of locking mechanism. This might be a shared cache, Zookeeper, Quartz scheduler, or flat file on an NFS mount. For example, a scheduled job that wakes up to process some records in a database table.
Gives Frequent Status Updates
Since microservices are relatively small and come in packs, you tend to end up with a lot of them. This makes it harder to keep track of each individual process. As a result, microservices should provide frequent feedback on how it’s doing.
This usually means exposing endpoints that allow an external monitoring system, such as Nagios, to constantly monitor the health of the service and alert someone when the service starts to look sick.
This also means collecting metrics about how the service is performing. This might be the rate at which requests or other messages are processed, the number of failed requests, how often an invalid response is received from a downstream service, and more. Whatever data can be collected that allows the service to provide some measure of how well it’s performing makes it easier to troubleshoot the service when it starts misbehaving.
These are the four microservice characteristics. What characteristics do you see as important in defining a microservice?