Shaun Abram
Technology and Leadership Blog
Microservices
A microservice is a small, focused piece of software that can be developed, deployed and upgraded independently. Commonly, it exposes functionality via a synchronous protocol such as HTTP/REST.
That is my understanding of microservices, at least. There is no hard definition of what they are, but they currently seem to be the cool kid on the block, attracting increasing attention and becoming a mainstream approach to avoiding the problems often associated with monolithic architectures. Like any architectural solution, they are not without their downsides too, such as increased deployment and monitoring complexity. This post will have a look at some of the common characteristics of microservices and contrast them with monolithic architectures.
Definition and Characteristics
Let’s start with some definitions from folks wiser than I:
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.
– Microservices by Martin Fowler and James Lewis [1]
Functionally decompose an application into a set of collaborating services, each with a set of narrow, related functions, developed and deployed independently, with its own database.
– Microservices Architecture by Chris Richardson [2]
Microservices are a style of software architecture that involves delivering systems as a set of very small, granular, independent collaborating services.
– Microservices – Not A Free Lunch by Benjamin Wootton [6]
Some if this may not sound new. Since way back in 1984, the Unix Philosophy [8] has advocated writing programs that do one thing well, working together with other programs through standard interfaces. So perhaps more useful than definitions are some common characteristics of a microservice:
-
Single purpose
Each service should be focussed, doing one thing well. Cliff Moon [4] defined a microservice as “any isolated network service that will only perform operations on a single type of resource”, and gives the example of a user microservice that can perform operations such as new signups, password resets, etc.
-
Loosely coupled
A microservice should be able to operate without relying on other services. That is not to say that microservices cannot communicate with other microservices, it’s just that should just be the exception rather than the rule. A microservice should be, where possible, self-sufficient.
-
Independently deployable
With monoliths, a change to any single piece of the application requires the entire app to be deployed. With microservices, each one should be deployable by itself, independently of any other services or apps. This can provide great flexibility, or ‘agility’. Ideally this should be done in a fully automated way; you’ll want a solid Continuous Integration pipeline, and devops culture, behind you. As discussed below in the disadvantages section, the one caveat here is when you are changing your interfaces.
-
Small
The ‘micro’ in microservice isn’t too important. 10 to 1000 lines of code might be a reasonable ball park but a much better definition might be ‘Small enough to fit in your head’ [3], that is, the project should be small enough to be easily understood by one developer. Another might be ‘Small enough to throw away’, or rewrite over maintain [3]; At one end of the scale, a single developer could create a microservice in a day. At the other end, Fowler [1] suggests that “The largest follow Amazon’s notion of the Two Pizza Team (i.e. the whole team can be fed by two pizzas), meaning no more than a dozen people”.
The main point is that size is not the most important characteristic of a microservice – a single, focused purpose is.
However, perhaps the best way to understand microservices is to consider an alternative, contrasting architectural style: the monolith.
The Monolithic Alternative
A monolithic application is one that is built and deployed as a single artifact (e.g. war file). In many ways this is the opposite of the microservice architecture. Applications often start out life as a monolith, and for good reason. Monoliths are:
- Easy to setup and develop – single project in an IDE
- Easy to deploy – a single war file
- Can be scaled horizontally by adding more servers, typically behind a load balancer
In fact it is generally advisable to start your applications as a monolith . Keep things simple until you have a good reason for changes (avoiding YAGNI architectural decisions). That being said, as monoliths grow, you may well start running into problems…
Problems with Monoliths
- Codebase can be difficult to setup, and understand
A large monolithic app can overload your IDE, be slow to build (and hence run tests), and it can be difficult to understand the whole application. This can have a downward spiral on software quality.
- Forced team dependencies
Teams are forced to coordinate (e.g. on technology choices, release cycles, shared resources etc), even if what they are working on has little, if anything, in common.
For example, two teams working on separate functionality within the same monolith may be forced to use the same versions of libraries. Team A need to use Spring 3 for legacy code reasons. Team B want to use Spring 4. With both Spring3 and Spring4 in your list of dependencies, which one actually gets used? In java-world, it is surprisingly easy to run into these conflicts.
-
How do you split up teams when using a monolithic architecture?
Often teams are split by technology e.g. UI teams, server-side logic teams, and database teams. Even simple changes can require a lot of different teams. It may often be easier to hack the required functionality into the area your own team is responsible for, rather than deal with cross team coordination, even if it was better placed elsewhere – Conway’s Law [9] in action. The larger, more dispersed and more bureaucratic a team is, the more of a problem this can be.
- Obstacle to frequent deployments
When you deploy your entire codebase in one go, each deployment becomes a much bigger, likely organizational wide, deal. Deployment cycles becomes slower and less frequently which in turn makes each deployment more risky.
- A long-term commitment to a technology stack
Whether you like it or not! Would you like to start using Ruby in your project? If the whole app is written in Java, then you will probably be forced to rewrite it all! A daunting, and unlikely, possibility. This all or nothing type setup is closely tied to forced team dependencies
Why use Microservices?
In contrast to monolithic applications, the microservice approach is to focus on a specific area of business functionality, not technology. Such services are often developed by teams that are cross-functional. This is perhaps one of the reasons why so many job descriptions these days say ‘full stack’.
So, what are the advantages of using microservices?
Many of the advantages of microservices relate to the problems mentioned for monolithic architectures above and include:
- Being smaller and focused means microservices are easier to understand for developers, and faster to build, deploy and startup
- Independently deployable
Each can be deployed without impacting other services (with interface changes being a notable exception)
- Independently scalable
Easy to add more instances the services that are experiencing heaviest load
- Independent technology stack
Each microservice can use a completely independent technology stack allowing easier migrate your technology stack
I think it is worth pointing out here that just because you can use a different technology for each microservice doesn’t mean you should! Increasingly heterogeneous stacks bring increasing complexity. Exercise caution and be driven by business needs.
- Improved resiliency;
If one service goes down (e.g. a memory leak), the rest of the app should continue to run unaffected
Disadvantages
- Distributed increases complexity!
Distributed applications are always more complicated! While monoliths typically use in-memory calls, microservices typically require inter-process calls, often to different boxes but in the same data center. As well as being more expensive, the APIs associated with remote calls are usually coarser-grained, which can be more awkward to use.
- Refactoring harder
Refactoring code in a monolith is easy. Doing it in a microservice can be much more difficult e.g. moving code between microservices
- Interface changes are hard
Although microservices allow you to independently release, that is not so straightforward when you are changing the interfaces – requires coordination across the clients and the service that is change. That being said, some ways to mitigate this are:
- Use flexible, forgiving, broad interfaces
- Be as tolerant as possible when reading data from a service.
- Use design patterns like the Tolerant Reader
- be conservative in what you do, be liberal in what you accept from others — Jon Postel
- Operational complexity
Where things can start to get hard with microservices is at an operations level. Runtime management and monitoring of microservices in particular can be problematic. A good ops/devops team is necessary, particularly when you are deploying large numbers of microservices at scale. Where as detecting problems in a single monolithic application can be dealt with by attached a monitor to the single process, doing the same when you have dozens of processes interacting is much more difficult.
Microservices vs SOA
SOA, or Service Oriented Architecture, is an architectural design pattern that seems to have somewhat fallen out of favor. SOA also involved a collection of services, so what are the difference between SOA and microservices? It is a difficult question to answer, but Fowler here used the term ‘SOA done right’, which I like. Adrian Cockroft [15] described Microservice as being like SOA but with a bounded context.
Wikipedia distinguishes the two by saying that SOA aims at integrating various (business) applications whereas several microservices belong to one application only [14]. A related aspect is that many SOAs use ESB (Enterprise Service Buses), where as microservices tend to smart endpoints, dumb pipes [1].
Finally, although neither microservices and SOAs are tied to any one protocol or data format, SOAs did seem to frequently involve Simple Object Access Protocol (SOAP)-based Web services, using XML and WSDL etc, whereas microservices seem to commonly favour REST and JSON.
Who is using Microservices?
Most large scale web sites including Netflix, Amazon and eBay have evolved from a monolithic architecture to a microservices architecture.
Amazon was on of the pioneers of using microservices. Between 100-150 services are accessed to build a single page [10]. If for example, the recommendation service is down, default recommendations can be used. These may be less effective at tempting you to buy, but is a better alternative to errors or no recommendations at all.
Netflix are also pioneers in the microservice world, not only using microservices extensively, but also releasing many useful tools back into the open source world, including Chaos Monkey for testing web application resiliency and Janitor Monkey for cleaning up unused resources. See more at netflix.github.io.
TicketMaster, the ticket sales and distribution company, is also making increasing use of microservices to give them “Boardroom agility or the process of quickly reacting to the marketplace.” [12]
Best practices
Some best practices for microservices might be:
- Separate codebases
Each microservice has its own repository and CI build setup
- Use monitoring!
For example AppDynamics and New Relic
- Built in health checks
For example, every service could have myservice.com/healthcheck
- Have standard templates available
If many developers are creating microservices, have a template they can use that gets them up and running quickly and implements corporate standards for logging and the aforementioned monitoring and health checks.
- Support multiple versions
Leave multiple old microservice versions running. Fast introduction vs. slow retirement [11]
Summary
As an architectural approach, and particularly as an alternative to monolithic architectures, microservices are an attractive choice. They allow independent technology stacks to be used, with each service being independently built and deployed, meaning you are much more likely to be able to follow the ‘deploy early, deploy often’ mantra.
That being said, they do bring their own complexities, including deployment and monitoring.
It is advisable to start with the relative simplicity of a monolithic approach and only consider microservices when you start running into problems. Even then, migrating slowly to microservices is likely a sensible approach. For example, introducing new areas of functionality as microservices, and slowly migrating old as they need updates and rewrites anyway. And all the while, bear in mind that while each microservice itself may be simple, some of the complexity is simply moved up a level. The coordination of dozens or even hundreds of microservices brings many new challenges including build, deployment and monitoring and shouldn’t be undertaken without a solid Continuous Delivery infrastructure in place, and a good devops mentality within in the team. Cross functional and multidisciplinary teams using automation are essential.
Used judiciously and with the right infrastructure in place, microservices seem to be thriving. I like Martin Fowlers’s guarded optimism: “We write with cautious optimism that microservices can be a worthwhile road to tread”. [12]
References and reading materials:
1. Microservices by Martin Fowler and James Lewis
2. Microservices Architecture by Chris Richardson
3. Micro services – Java, the Unix Way by James Lewis
4. Microservices, or How I Learned To Stop Making Monoliths and Love Conway’s Law by Cliff Moon
5. Micro service architecure by Fred George
6. Microservices are not a free lunch by Benjamin Wootton
7. Antifragility and Microservices by Russ Miles
9. Conway’s Law
11. Migrating to microservices by Adrian Cockroft
12. Microservices with Spring Boot
13. Microservices for the Grumpy Neckbeard
14. Microservices definition on Wikipedia
15. Microservices and DevOps by Adrian Cockcroft
Useful Presentations:
Building and Deploying Microservices – Bart Blommaerts
Microservices on the JVM – Alexander Heusingfeld
Tags: microservices, REST, SOA
This article has a lot of good stuff in it Shaun. You cover many points. Microservices are very popular now and we will see where things go in the future. Have you done a lot with Spring Boot?
Hey Tom,
Thanks! Glad you liked article. Yes, I am increasingly using Boot as the basis for my microservices. It certainly makes getting up and running very easy. I am actually working on a Boot blog post, so watch this space! I also recently heard of DropWizard, which seems to be in a somewhat similar space, and perhaps an option when Boot can’t be used (we are stuck on Spring3 in my current job, and hence can’t always use Boot).
Shaun
Great article. Curious to know your thoughts on IDesign’s architecture presentation about functional decomposition leading to duplicate code: https://www.youtube.com/watch?v=VIC7QW62-Tw
Thanks Stuart. I haven’t see the IDesign presentation, but I will check it out. Thanks for the link.
The 7th url under “Reference and reading materials” is missing an ‘s’ at the end and directs to a 404.
http://www.infoq.com/articles/russ-miles-antifragility-microservices
Thanks Paul, fixed.