Part III — Microservices and Reactive Architectures · Chapter 10

Microservices Patterns Overview

~45 min read4 interactive widgets4 plates

In this chapter

  1. What a pattern is, and how patterns are structured
  2. The pattern catalogue and its three layers
  3. Patterns for decomposing an application into services
  4. Communication patterns
  5. Data consistency patterns for transaction management
  6. Patterns for querying data
  7. Service deployment patterns
  8. Observability patterns
  9. Patterns for the automated testing of services
  10. Patterns for cross-cutting concerns
  11. Security patterns
  12. Architecture, process and organisation
  13. Check your understanding

1. What a pattern is, and how patterns are structured

A pattern is a reusable solution to a problem that occurs in a particular context. Microservices patterns are high-level design patterns, where the solution consists of collaborating services. The module’s overview is based on chapter 1 of Richardson’s Microservices Patterns [MP].

Each pattern has a standard structure:

Key idea

Patterns are not silver bullets: every pattern resolves some forces and leaves others unresolved, and introduces new issues of its own. Reading the resulting context is as important as reading the solution.

2. The pattern catalogue and its three layers

The patterns are grouped based on the kind of problem they solve:

  1. Patterns for decomposing an application into services
  2. Communication patterns
  3. Data consistency patterns for implementing transaction management
  4. Patterns for querying data in a microservice architecture
  5. Service deployment patterns
  6. Observability patterns providing insight into application behaviour
  7. Patterns for the automated testing of services
  8. Patterns for handling cross-cutting concerns
  9. Security patterns

The catalogue is divided into three layers, according to who is affected:

Patterns that solve problems that are mostly infrastructure issues outside of development — for example the service deployment patterns and most observability plumbing: log aggregation servers, metrics servers, deployment platforms.

Patterns for infrastructure issues that also impact development — the middle layer of the catalogue: service discovery, circuit breaker, API gateway, externalized configuration, and the microservice chassis that packages the cross-cutting machinery.

Patterns that solve problems faced by developers — the top layer: decomposition into services, communication styles, sagas for data consistency, CQRS and API composition for querying, contract and component testing.

THE PATTERN CATALOGUE: THREE LAYERS APPLICATION PATTERNS decomposition · communication · data consistency (saga, event sourcing) · querying (API composition, CQRS) · testing problems faced by developers APPLICATION INFRASTRUCTURE discovery · reliability (circuit breaker) · external API (API gateway) · externalized configuration · microservice chassis infrastructure issues that also impact development INFRASTRUCTURE PATTERNS deployment (service instance per VM/container, serverless) · observability (health check, logs, tracing, metrics, exceptions) infrastructure issues outside of development security patterns (access token) cut across the layers
Plate 10.1 — The three layers of the microservices pattern catalogue, with the problem groups each layer contains. The same pattern group can appear in more than one layer — communication, for instance, spans style (application) and discovery (application infrastructure).

3. Patterns for decomposing an application into services

The strategies to decompose a system into a set of services were discussed in module 2.2 (Chapter 9):

Both are themselves patterns in the catalogue — and the module points out that they are only the first step: the rest of the catalogue exists because decomposing an application creates a whole family of new problems.

4. Communication patterns

Communication patterns cover a variety of architectural and design decisions about how your services communicate with one another and the outside world. The module groups them into five communication groups:

FIVE COMMUNICATION GROUPS Communication style what kind of IPC mechanism should you use? Discovery how does a client find a service instance’s IP address? Reliability — Circuit Breaker communication stays reliable when services are unavailable Transactional messaging integrate sending messages with database transactions External API — API Gateway how do the application’s clients communicate with the services?
Plate 10.2 — The five communication groups: style, discovery, reliability, transactional messaging, and the external API. Two of the named patterns — Circuit Breaker and API Gateway — are examinable landmarks in this catalogue.

The first group — communication style — was already covered in Chapter 9 (interaction styles and IPC technologies: REST, gRPC, messaging, GraphQL). The remaining four groups give the questions the patterns answer: discovery (how a client of a service determines the IP address of a service instance so that it can make an HTTP request), reliability (how to keep communication reliable even though services can be unavailable — the Circuit Breaker pattern), transactional messaging (how to integrate the sending of messages and publishing of events with the database transactions that update business data), and external API (how the application’s clients communicate with the services — the API Gateway pattern).

5. Data consistency patterns for transaction management

In microservices, to ensure loose coupling, each service has its own database — which poses the problem: how to preserve data consistency across services? The traditional approach of using distributed transactions (two-phase commit) isn’t a viable option for a modern application.

Among the patterns in this group:

Editor’s note

Both patterns were introduced in Chapter 7 (domain events and sagas as the aggregate rules’ escape hatch) and in Chapter 9 (sagas as the answer to the cross-service consistency obstacle). Here they return as named entries in the catalogue — and the lab notes on designing event-driven microservices will go much deeper.

6. Patterns for querying data

Often in microservices, queries need to query and join data owned by multiple services — and we can’t use distributed queries against the services’ databases. Among the patterns:

7. Service deployment patterns

Deploying a microservices-based application is complex: there may be tens or hundreds of services written in a variety of languages and frameworks, and many more moving parts to manage. The traditional — and often manual — way of deploying applications in a language-specific packaging format (for example WAR files) doesn’t scale to support a microservice architecture: a highly automated deployment infrastructure is needed. Ideally, a deployment platform should provide the developer with a simple UI (command-line or GUI) for deploying and managing their services.

Several patterns exist for deploying microservices:

In any case, a service deployment platform is needed: an automated, self-service platform for deploying and managing services.

8. Observability patterns

A key part of operating an application is monitoring and understanding its runtime behaviour — observability — for diagnosing and troubleshooting problems (failed requests, high latency) and, more generally, for ensuring quality attributes. Observability is more challenging in microservices systems than in monolithic ones: a request can bounce around between multiple services before a response is finally returned to a client, so there isn’t one log file to examine, and latency problems are harder to diagnose because there are multiple suspects.

The patterns to design observable services:

OBSERVABILITY: ONE SERVICE, MANY STREAMS Service /health · logs · traces · metrics Health check API Log aggregation Distributed tracing Exception tracking Application metrics Audit logging a request bounces across many services — no single log file: traces stitch the hops back together
Plate 10.3 — The six observability patterns. Health checks, log aggregation, distributed tracing, exception tracking, application metrics and audit logging turn a distributed system into something diagnosable.

9. Patterns for the automated testing of services

The microservices architecture makes individual services easier to test because they are much smaller than the monolithic application. At the same time, it is important to test that the different services work together — while avoiding complex, slow and brittle end-to-end tests that test multiple services together. The patterns simplify testing by testing services in isolation:

10. Patterns for handling cross-cutting concerns

In a microservices architecture there are numerous concerns that every service must implement — including the observability patterns and the discovery patterns. It must also implement the Externalized Configuration pattern, which supplies configuration parameters such as database credentials to a service at runtime.

When developing a new service, it would be far too time-consuming to reimplement these concerns from scratch: a much better approach is to apply the Microservice Chassis pattern and build services on top of a framework that handles these concerns for them.

11. Security patterns

In a microservices architecture, users are typically authenticated by the API gateway. It must then pass information about the user — such as identity and roles — to the services it invokes. A common solution is the Access Token pattern: the API gateway passes an access token, such as a JWT (JSON Web Token), to the services, which can validate the token and obtain information about the user.

12. Architecture, process and organisation

Besides choosing the right architecture, a main concern of software architects is process and organisation: an architecture succeeds only if the teams and the delivery process fit it.

Software development and delivery organisation

Large teams have communication trouble: Fred Brooks noted in The Mythical Man-Month that the communication overhead of a team of size N is O(N²). If the team gets too large it becomes inefficient — imagine trying to do a daily standup with 20 people. The solution is to refactor a large single team into a team of teams:

Small teams bring two benefits. Higher velocity: the microservices architecture enables the teams to be autonomous — each team can develop, deploy and scale its services without coordinating with others, and it is very clear who to contact when a service isn’t meeting its SLA. Higher scalability of the organisation: we grow the organisation by adding teams; if a team becomes too large, we split it and its associated service or services; because teams are loosely coupled, we can add people without impacting productivity.

CONWAY’S LAW — AND THE REVERSE CONWAY MANEUVER Team A (front-end) Team B (back-end) Order service Kitchen service organisations constrained to produce copies of their communication structures design the organisation so that its structure mirrors your microservice architecture Conway Reverse Conway loosely coupled teams ↔ loosely coupled services
Plate 10.4 — Conway’s law: organisations produce designs that are copies of their communication structures. The Reverse Conway Maneuver inverts it deliberately: design the organisation so its structure mirrors the microservice architecture, ensuring teams are as loosely coupled as the services.

Software development and delivery process

Several approaches exist in the literature; the natural choices when developing an application with the microservice architecture are agile development and deployment practices (such as Scrum or Kanban) and DevOps, to practise continuous delivery/deployment. The microservice architecture directly supports them:

The goal of continuous delivery/deployment — and, more generally, of DevOps, “move fast without breaking things” — is to deliver software rapidly yet reliably. Four useful metrics assess software development:

In a traditional organisation the deployment frequency is low and the lead time is high; a DevOps organisation releases frequently, often multiple times per day, with far fewer production issues. The module’s data points: Amazon deployed changes into production every 11.6 seconds in 2014, and Netflix had a lead time of 16 minutes for one software component.

Check your understanding

Define a pattern and give the structure of a microservices pattern.

A pattern is a reusable solution to a problem that occurs in a particular context; microservices patterns are high-level design patterns whose solution consists of collaborating services. Structure: Forces (the issues to address), Resulting context (Benefits — resolved forces; Drawbacks — unresolved forces; Issues — new problems introduced), and Related patterns (successor, predecessor, specialization, generalization, grouping).

List the nine pattern groups and the three layers of the catalogue.

Groups: decomposition into services, communication, data consistency for transaction management, querying data, service deployment, observability, automated testing of services, cross-cutting concerns, security. Layers: Infrastructure patterns (issues outside development), application infrastructure (infrastructure issues that also impact development), application patterns (problems faced by developers).

State the two decomposition strategies and the four other communication groups besides style.

Decomposition: by business capabilities and by subdomains (from module 2.2). Communication groups: style, discovery (finding a service instance’s IP address), reliability (Circuit Breaker), transactional messaging (integrating message sending with database transactions), external API (API Gateway).

Why isn’t two-phase commit viable in a modern application, and which patterns replace it for data consistency and for querying?

Each service owns its database, so cross-service consistency cannot rely on distributed transactions (2PC), which are not a viable option for modern applications. Data consistency: Saga (sequence of local transactions coordinated by messaging, eventually consistent) and Event Sourcing (persistence modelled as events). Querying: API composition (invoke several APIs and aggregate) and CQRS (maintain easily queried replicas).

Why doesn’t language-specific packaging scale for microservices, and what are the modern deployment approaches?

There may be tens or hundreds of services in a variety of languages and frameworks: manual deployment in a language-specific packaging format (e.g. WAR files) doesn’t scale, so a highly automated service deployment platform is needed. Modern approaches: deploy services as VMs or containers, or the serverless approach (upload code, the platform runs it).

Why is observability harder in microservices, and what are the six observability patterns?

A request bounces between multiple services before the response returns, so there isn’t one log file to examine and latency problems have multiple suspects. Patterns: Health check API, Log aggregation, Distributed tracing, Exception tracking, Application metrics, Audit logging.

What are the three testing patterns, and what do they verify?

Consumer-driven contract test — verifies a service meets the expectations of its clients. Consumer-side contract test — verifies the client of a service can communicate with the service. Service component test — tests a service in isolation. Together they replace complex, slow and brittle end-to-end tests.

What are the Externalized Configuration and Microservice Chassis patterns?

Externalized Configuration supplies configuration parameters such as database credentials to a service at runtime. Microservice Chassis is the framework on which services are built, handling the cross-cutting concerns every service must implement (observability, discovery, externalized configuration) so they are not reimplemented from scratch.

How does the Access Token pattern secure a microservice architecture?

Users are typically authenticated by the API gateway, which then passes information about the user (identity and roles) to the services it invokes using an access token such as a JWT; each service validates the token and obtains the user information.

State Conway’s law, the Reverse Conway Maneuver, and the team-of-teams rules.

Conway’s law: organizations which design systems … are constrained to produce designs which are copies of the communication structures of these organizations. The Reverse Conway Maneuver: design your organization so that its structure mirrors your microservice architecture. Team-of-teams rules: teams of 8–12 people, with a clearly defined business-oriented mission (developing and possibly operating one or more services), cross-functional so they can develop, test and deploy without frequent coordination with other teams.

Contrast continuous delivery and continuous deployment, and state the four DevOps metrics.

Continuous delivery: getting changes of all types into production safely and quickly in a sustainable way — software is always releasable. Continuous deployment: automatically deploying releasable code into production. The four metrics: deployment frequency, lead time (check-in to deployment), mean time to recover, change failure rate.