Microservice Architecture: An Incisive Overview

Divide and conquer

You may know it to be a type of algorithm design paradigm.

But:

On a basic level, the phrase aptly describes a concept that stems from an evergreen desire in the software industry to build systems by joining several individual components—much like how most industries create things in the real world.

This desire is the crux of the micro service architecture, known simply as microservices or MSA.

A really simple description of the microservice architecture is that it uses a set of loosely coupled, collaborating parts to build and maintain an application.

Each individual part, called a microservice, is:

  • small;
  • modular;
  • composable;
  • developed separately;
  • independently deployable;
  • runs a unique process; and
  • communicates via a lightweight mechanism

microservice diagram

Do one thing and do it well

That is the UNIX philosophy in one sentence. It is also an integral tenet of the microservice architectural style, which guides the development of each fine-grained microservice.

By having a microservice is a self-contained unit of functionality that a team can develop, deploy, and scale independently; MSA enables the methodological development, continuous delivery, and continuous deployment of large, complex applications; particularly enterprise and SaaS applications.

That said, to understand microservices better, it is vital to contrast it to the traditional, inverse way of building applications—the monolithic architectural style.

Monolithic Architecture versus Microservice Architecture

A monolith and its issues

Say you want to build an application using the client-server model. You’d have three main parts—a client-side user interface, a database, and a server-side application.

An oft-used approach is to build the server-side application as a single logical executable. This application would do it all—handle HTTP requests, execute logic, and retrieve & update data in the database.

At the outset, developing, testing, and deploying an application of this type is simple. And to scale, you’d simply run multiple copies behind a load balancer.

However:

As time progresses, this application grows and expands to a point where it is a huge, monstrous monolith, with issues that are far from wieldy.

  • Modifying a small section or module usually means building, testing, and deploying an entirely new version
  • Ditto for scaling—you’d have to scale the entire application even if you initially intend to scale only specific parts.
  • Continuous deployment is challenging for the first two reasons mentioned above.
  • Agile development and delivery becomes prohibitive as is fixing bugs and implementing new features.
  • Tight coupling means a bug in any section can potentially take down the entire process. Furthermore, with all instances of the application being identical, a bug will typically affect availability of the entire application.
  • Adopting new, more-efficient technologies, be it a language, framework, or hardware, is near impossible.

Microservices to the rescue

MSA is essentially dedicated to tackling the future complexity of a system. Rather than have a single monolithic application, you’d split this application into a suite of microservices—each of which is practically a mini-application.

  • A microservice implements a set of specific functionality or features, say order management.
  • It offers a firm module boundary, in the form of an RPC- or message-driven API.
  • It typically has its database.
  • Different teams may manage different microservices.
  • Microservices may use asynchronous, message-based communication, usually HTTP/REST with JSON, Protobuf; although developers are free to use any communication protocol deemed more suitable.

The implication is that you can:

  • develop, test, deploy, and scale each microservice independently, often without enacting any change to other microservices; a team could use a different programming language or use a more suitable type of database in a polyglot persistence architecture for a microservice.
  • adopt new, emerging technologies relatively easily, since rewriting or optimizing a microservice is at least an order of magnitude smaller than doing same to an entire monolith.
  • practice continuous delivery and deployment relatively easily; ditto for implementing new features, isolating any problem following deployment, and making rollbacks.
  • keep the application up even if a part (microservice) is down or being deprecated.
  • support a range of existing platforms and devices as well as future devices that you may need to support later on.

Service-Oriented Architecture Vs. Microservice Architecture

If MSA sounds familiar to you, that’s because you’ve being introduced to a similar concept—the Service-Oriented Architecture, abbreviated as SOA—in the past.

SOA is about a decade older than MSA, and yeah, they share a couple of similarities.

Similarities

The first is obvious. Both architectures place a premium on services. In addition, both architectural styles reiterate the philosophy of loose coupling, making parts (services) technology agnostic, and enabling inter-service communication.

There are quite a few others.

Still:

There is enough of a difference to warrant different nomenclatures, or at the very least, make MSA a subset of SOA.

Ambiguity versus specificity

An easily relatable reason why microservices isn’t merely a synonym of SOA is that SOA means too many different things, Which is a tad ironic considering SOA has a set of six core values, while MSA doesn’t have a formal, standard definition yet.

Quite some projects that may be accurately described as adopting a service-oriented architecture actually have a style that is significantly different from the microservice architectural style.

Furthermore, in a general sense, SOA and MSA have distinctly different approaches to messaging, coordination of services, and scalability.

Coordination

A typical SOA model focuses on an ESB (Enterprise Service Bus), whereas MSA avoids ESBs and opts for faster, simpler, lighter communication protocols such as REST.

Logical cohesion versus functional cohesion

While both architectures thrive on the concept of cohesion—a service performs specific functionality that is a mesh of related functions, the approach is different.

SOA focuses on reuse. And so lays emphasis on logical cohesion where the functionality of a service relates to a bunch of similar tasks—say a “data service” to handle all communication with a database.

On the other hand, MSA focuses on autonomy or business capability—the ability of a service to provide business value on its own. And so emphasizes functional cohesion where the functionality of service relates to tasks that are not similar but contribute to a well-defined business capability—say a “shipping service” or “customer service.”

Decoupling

Ideally, in theory both SOA and MSA pledge to implement the loose coupling concept for improved modularity. However, in practice, SOA models are often tightly coupled because of a focus on logical cohesion; especially with data (owing to an emphasis on sharing as much as possible between services).

On the other hand, microservices thrive on the bounded context concept, owing to its functional cohesion style. Consequently, each service is bound to its data in a self-contained association.

Interaction versus Dependence

Certainly, services would have to communicate in both architectures. However, with microservices, adherence to the loose/low coupling concept is strict.

For starters, rather than share parts of services, MSA advocates replicating similar functions across different services. A common example is building different databases for different microservices, rather than only sharing data from one mega database.

This discourages the practice of having a microservice dependent on another microservice, which takes away from the core benefits of the microservice architecture.

A basic requirement to adhering to the MSA style faithfully is to understand the difference between interaction and dependency. For instance, while an ‘order’ microservice would interact with a ‘shipping’ microservice. Both have all necessary functions to operate independently.

Such that if the ‘shipping’ service goes down, the ‘order’ service would still take orders and send them to the ‘shipping’ service. Since the ‘shipping’ service is down, there would be a backlog and orders would not be processed immediately. However, when the ‘shipping’ service comes back up, it will process all orders in the backlog. Meanwhile, at no point would the ‘order’ service stop taking new orders.

In addition to these pronounced differences, there are several others, including:

  • MSA rejecting the concept of a canonical schema.
  • MSA focusing on responsive-actor programming while SOA focuses on imperative programming.
  • MSA frequently using micro-SQL databases, while SOA models often swear by an outsized relational database.

In general, how much of a difference exist between SOA and MSA depends on who you converse with. In any case, MSA offers more specificity relating to the use of services, and so deserves a term that more crisply alludes to the architectural style.

Common Characteristics Of A Microservice Architecture

MSA may not have a formal definition or a standard model, but most systems that adopt the microservice architectural style share a number of common, notable characteristics.

Componentization

A rudimentary feature of MSA systems is that they are essentially a network of distinct components. As described earlier on, each component is a unit of software that a team can develop, upgrade, and replace independently.

Although componentization unlocks a desirable slew of benefits, it has some drawbacks.

  • It uses relatively expensive remote calls as opposed to in-process calls.
  • It requires remote APIs to be coarse-grained.
  • Re-allocating responsibilities between components is a tad more complicated.

Business capability- and priority-based organization

Resolving to split an application into autonomous components is only one piece of the puzzle. How you go about splitting an application is just as crucial. Systems using the microservice architecture typically make splits based on business capability and/or priority.

Each component (microservice) offers a business value and so comprehensively implements software functions for the business area it focuses on—including storage, user interface, and any external collaborations.

Products over projects

Consequently, management organizes product teams that are cross-functional, with requisite full range of skills to handle all myriad parts—database, user experience, and project management.

This is different from the traditional monolithic development approach, where management organizes project teams based on technology layers—database teams, UI teams, and server-side logic teams.

The major advantage of the MSA approach is that changes are implemented without the entire application project being held up (taking time). And developers do not have to wait for budgetary approval before improving individual services.

Smart endpoints and dumb pipes

Communication is necessary.

But how do you structure communication within an application?

Many approaches favor making the communication mechanism smart. For instance, an ESB would typically have sophisticated facilities for choreography, message routing, transformation, and applying business rules.

On the flip side, the MSA approach is to have a dumb communication. The reason for this is to ensure loose coupling and high functional cohesion. Each microservice is usually beefed up with its own domain logic, in that it

  • receives a request,
  • processes the request (by applying logic as appropriate), and
  • generates a response.

Thus, a microservice acts more like a filter in the classical UNIX sense. MSA systems typically use HTTP request-response with resource APIs and lightweight messaging.

An alternate approach is to use a lightweight message bus; with a simple implementation such as ZeroMQ or RabbitMQ (that practically do no more than provide a reliable asynchronous fabric).

With both approaches, the end-result is the same. A dumb pipe (for communication) and a smart end point within the service (for consuming and producing messages).

Decentralized governance

Traditionally, most managements adopt a centralized governance approach. Development often adheres to single technology platforms, a set of defined standards, and devolution of responsibility is restricted.

The microservices community prefers the decentralized governance approach. With a team being cross-functional and in charge of the development, testing, and upgrading of a part of the application that offers business value; the idea is to give teams more control over their products.

This results in:

  • developers being able to use technologies more suited for their product, when necessary;
  • producing, sharing, and utilizing useful tools to solve similar problems, rather than sticking rigidly to a set of defined standards; and in select cases.
  • adopting a “build it / run it” ethos, where teams are completely in charge of running the software they build round the clock.

Astute management of failures

With several functionally cohesive microservices running within an MSA application, a failure of one or more parts is bound to occur sooner or later. To stay on top of this eventuality, microservices are designed to tolerate and effectively manage service failures.

The objectives include:

  • to have microservices function independently
  • quick detection of failures and possible automatic restoration of a failed service; often made possible by implementing mechanisms that monitor the application in real time.

Future-proof design

A common theme amongst MSA systems is that they are designed on the premise that enacting multiple in the future is inevitable (evolutionary model), and so, it is best to be prepared for quick adaption and scaling.

Adaptation may involve an incremental update or be as radical as replacing (or removing) a microservice. As such, this characteristic trends towards modularity as a way to control changes within an application without slowing down change.

Is MSA Right For You?

Known Uses of MSA

Before you get down to the nitty-gritty of deciding if you should (or should not) adopt the MSA style, you should have an idea of successful implementations of the microservice architecture.

Quite a number of large-scale sites and applications implement MSA to a substantial degree—Amazon, Bluemix, Capital One, Comcast Cable, eBay, Expedia, Forward, Gilt, Groupon, Hailo, Karma, Lending Club, Netflix, PayPal, realestate.com.au, Sound Cloud, The Guardian, the UK Government Digital Service, Twitter, Uber, Zalando.

You can get more insight by reading the respective accounts and case studies shared by some of these sites (click the links).

Key benefits of a microservice architecture

  • Concrete independence or autonomy.
  • Improved decoupling.
  • Ease of deployment.
  • Efficient scalability.
  • Increased specialization.
  • Better organizational alignment.
  • Enhanced resilience
  • Lower cost of failure.
  • Optimized for composability and replaceability.

Not a silver bullet

Every software architecture out there has its drawbacks, and MSA is not an exception.

Much of it relates to the hassle of getting used to new ways of doing things. Tasks like testing, deployment, and monitoring are a tad more complex to perform on MSA systems than on monolithic applications. To put this in perspective, the Amazon web application calls 100 to 150 services to get data used for building a web page, Hailo has 160 different services, Netflix has in excess of 600 services.

Furthermore, the benefits of decoupling may be overwhelmingly convincing; but it also means duplication of efforts, mitigating fault tolerance and network latency, and handling a bunch of issues that were a lot more implicit in monoliths. None of this is rocket science, but compared to a monolithic application, there is an added layer of complexity.

Partitioning an application into microservices isn’t only a science; it is very much an art. And although, rewriting a microservice using newer, more efficient technology later isn’t prohibitive; refactoring the boundary of a microservice (when you find a good reason to, as may happen sometime later thanks to the focus on evolutionary design), say by having to move a responsibility between services, is difficult because of the loose coupling of services.

Adopting a case-by-case approach

Taking a decision on MSA majorly depends on your requirements.

Monolith first

For starters, most of the MSA success stories that have made the rounds were former monoliths evolving to the microservice architectural style.

It is on this basis that some advocate building a monolith at the outset, keeping it modular, and then transitioning into microservices once you start facing common monolith-related issues.

Beyond the multiple scenarios where this approach has worked, there are additional reasons why this is a good idea:

  • You really do not begin to reap the benefits of microservices, especially with respect to the effort you put in, until you have a complex application.
  • It can be hard to work out right, firm service boundaries from the start; even for experienced architects.

Both reasons make the most sense for startups, prototypes, and early betas. You are not overly certain about how useful the application would be (many startups take between 1 and 3 years to align their product vision). And even if you are, speed (and in relation the cycle time for feedback) is of more importance to you than getting it right from the get-go.

Down the road, when performance and overall user experience matter more, you may then transition to MSA.

With that said, the success of this strategy depends a great deal on being disciplined when building the monolith to ensure optimum modularity. Makes breaking up much easier later.

There are a few different ways to execute this strategy:

  • Start with a monolith and later split completely to microservices.
  • Start with a monolith and peel off microservices at the edge gradually; usually leaving a bit of monolith at the heart of the MSA—The Guardian followed this route.
  • Start with a monolith bearing in mind that you’ll discard it later (replace it entirely) for an MSA system.
  • Start with a couple of coarse-grained services (and so it is not strictly an MSA system) that are larger than the services you expect to end up with; use them to get a hang of working in a distributed software architecture (especially if you do not have the skill); and then later break down the services down into finer-grained services.

Going all in

While the monolith-first argument is undoubtedly compelling, another crowd firmly opposes it.

The counter-argument is that if you don’t have any or much experience with services (doesn’t have to be MSA, it may be some other form of SOA), then following the “practice makes perfect” maxim is an excellent way to hone up the skill of developing in a microservice environment.

On the other hand, if you do have the experience, then why go through the labor of taking a detour?

Furthermore, it takes a lot of disciple, sometimes too much than a team can consistently uphold, to build a monolith in a sufficiently modular way for easy partitioning into microservices. Partitioning isn’t exactly a cakewalk.

Starting with microservices allows you to organize teams that are used to developing along service boundaries from the beginning, which allows you to scale up development seamlessly when necessary. Theoretically, the MSA-first strategy would be ideal for system replacements where you are able to come up with stable-enough boundaries early on.

That said, the MSA-first strategy hinges on the understanding that you have better than average knowledge of the project and believe that your system is large enough to warrant having multiple subsystems.

Last modified: March 8, 2019

Comments

Write a Reply or Comment

Your email address will not be published.