Software Development

Microservices

A microservice is a small, focussed piece of software that can be developed, deployed and upgraded independently. Commonly, it exposes it 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 problem 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 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 probably 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. This is especially true the larger, more dispersed and more bureaucratic a team is.

  • 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 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 the next point of share libraries…

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 focussed 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 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 code in a monolith is easy. Doing it in a microservice can be much more difficult e.g. moving code between microservices
  • 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

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

  • Separate interface and implementation

Separate the API and implementation modules, using a Maven multi-module project or similar. For example, clients should depend on CustomerDao rather than CustomerDaoImpl, or JpaCustomerDao.

  • Use monitoring!

For example AppDynamics and New Relic

  • Have health checks built into your services
  • 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 asymmetry. [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 Continuos Delivery infrastructure in place, and a good devops mentality within in the team. Cross functional and multidisciplinary teams using automation are 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
  8. The Unix Philosophy
  9. Conway’s Law
  10. Amazon Architecture
  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
Reference: Microservices from our JCG partner Shaun Abram at the Shaun Abram’s blog blog.
Subscribe
Notify of
guest

This site uses Akismet to reduce spam. Learn how your comment data is processed.

0 Comments
Inline Feedbacks
View all comments
Back to top button