Be Software Architecture Wise
Be Wise Apps

Leer en español · Lire en français · Auf Deutsch lesen

Chapter 9 of 12 · Intermediate to advanced

Performance, Scalability, Resilience and Operability

This chapter turns Chapter 2's performance and availability scenarios into working systems. It covers scaling up and out and the scale cube, load balancing and stateless services, queues, back pressure and rate limiting, the resilience patterns that stop failures spreading (timeouts, retries, circuit breakers, bulkheads), SLIs, SLOs and error budgets, observability with logs, metrics and traces, capacity planning and performance testing, and chaos engineering and incident learning. It is for developers and architects who know the distributed styles of Chapter 6 and must keep a system fast and running under real load.

Video introduction to Chapter 9

7 min · narrated, with captions
Listen only (audio)
Read the transcript

Welcome to Chapter 9, Performance, Scalability, Resilience and Operability. A design that meets its targets in a diagram can still fall over at half past twelve on a Friday, when every office in the city orders lunch. The difference is rarely clever code. It is a set of architectural decisions about how capacity is added, how load is spread, how work waits, how failures are contained, and how the people running the system know what it is doing.

This chapter is for developers and architects who know the distributed styles of Chapter 6, and who must keep a system fast and running under real load. It builds on Chapter 2, which made performance and availability precise as testable quality attribute scenarios. Here you learn to achieve those scenarios in a running system, and keep them true on the busiest day of the year. It links back to Chapter 7 for replication, partitioning and caching, rather than repeating them. And it leads to Chapter 10, on the cloud platforms, Kubernetes features and multi-region designs these systems usually run on.

Two running examples carry through the chapter. A food delivery platform, with sharp lunchtime and evening peaks. And a ticket on-sale, where demand rises from almost nothing to many times the system's capacity within seconds. Section nine point one compares scaling up with scaling out, uses the scale cube to separate cloning, splitting by function and splitting by data, and explains why autoscaling on CPU is often the wrong choice. Section nine point two covers what sits in front of the instances: load balancers, the algorithms they use, health checks, connection draining, and why sticky sessions should give way to session state kept outside the instance. Section nine point three is about what happens when work arrives faster than it can be done: bounded queues, back pressure, load shedding and rate limiting, which decide what is accepted, what waits and what is refused politely. Section nine point four deals with failure between services: timeouts and deadlines, retries with backoff and jitter, circuit breakers, bulkheads and fallbacks.

Section nine point four's worked example shows how one missing timeout lets a single slow dependency take down everything that calls it. The payment provider normally answers in zero point three seconds. Today it has stopped answering. The order service calls it without a timeout, so one by one, all two hundred of its threads end up waiting on payment calls. Now checkout fails. But so do order history and tracking, which never touch payments, because there are no free threads left to serve them. The database is perfectly healthy, but no thread is free to call it. Timeouts, circuit breakers and bulkheads are the patterns that stop this kind of cascade.

The second half turns from mechanisms to operation. Section nine point five shows how to state reliability from the user's point of view, and how an error budget turns an availability target into an amount of allowed failure that teams can spend on change. Section nine point six covers the logs, metrics and traces that let engineers ask new questions of a production system, and distributed tracing with OpenTelemetry. Section nine point seven closes the loop between forecasts and evidence, with load, stress, soak, spike and breakpoint tests, and a capacity plan for a ticket on-sale. And Section nine point eight deals with the failures that happen anyway: deliberate experiments to find weaknesses before customers do, clear roles during incidents, and blameless reviews that change the system rather than the people.

This diagram from Section nine point five puts three terms on one scale, using the availability of checkout over a rolling twenty eight days. The service level objective, or SLO, is the internal target: here, ninety nine point nine per cent. The service level agreement, or SLA, is a contract with partners, set looser, at ninety nine point five per cent. The service level indicator, or SLI, is the measurement. This month it is ninety nine point nine four per cent, inside the zone where the service is within its budget. Below the SLO, the target is missed, and a written error budget policy says what happens next. Only below the SLA are service credits owed. The gap between the SLO and the SLA is the warning zone. The error budget is simply one minus the SLO. Over thirty days, a target of ninety nine point nine per cent allows forty three point two minutes of complete outage, or one request in every thousand failing.

The sections form a chain, and they lead to one idea. Every resource is finite, so every system has a breaking point. The architect's job is to decide in advance what happens when it is reached. A well designed system under excessive load slows down gracefully, and sheds the least important work first. It refuses clearly, rather than timing out silently. It isolates the failing part. And it recovers by itself when the pressure passes. A poorly designed one queues without limit, retries until it collapses, and takes its neighbours with it. These mechanisms are cheap to add at design time and expensive to retrofit. Whether a service is stateless, whether a queue is bounded and whether a request carries a deadline are all decided long before the first incident.

By the end of the chapter, you will be able to choose how to scale, and size a fleet for a known peak with Little's law and headroom. You will be able to combine timeouts, deadlines, retries with backoff and jitter, circuit breakers, bulkheads and fallbacks to contain failures. You will be able to define service level indicators and objectives from the user's point of view, calculate error budgets, and design alerts on how fast they are being spent. And you will be able to plan capacity and performance tests, run chaos experiments safely, and lead blameless post-incident reviews.

Because the sections form a chain, reading them in order works best. But each one also stands on its own, so you can go straight to the section you need. Allow about three and a half hours to read the whole chapter. At the end of each section there are self-check questions. Answer them in your head before you look at the answers. When you are ready, there is an optional chapter test, which takes about forty five minutes. It has twenty multiple choice questions and two written answers. The pass mark is eighty per cent.

That is the shape of the chapter. Start with Section nine point one, on scaling up, scaling out and the scale cube. See you there.

Download chapter (PDF)Read in the app

At a glance

You will learn to

  • Choose between vertical and horizontal scaling and among the X, Y and Z axes of the scale cube, and size a fleet for a known peak with Little's law and headroom.
  • Select autoscaling signals and settings that avoid lag and flapping, and explain why CPU is often the wrong metric.
  • Compare layer 4 and layer 7 load balancing and the main algorithms, design health checks and connection draining, and externalise session state.
  • Apply queues, bounded buffers, back pressure, load shedding and rate limiting (including the token bucket) to keep overload under control.
  • Combine timeouts, deadlines, retries with backoff and jitter, retry budgets, circuit breakers, bulkheads and fallbacks to contain failures.
  • Define SLIs and SLOs from the user's point of view, calculate error budgets and burn rates, and design alerts on them.
  • Instrument a system with logs, metrics and traces using OpenTelemetry, and use the RED and USE methods to diagnose problems.
  • Plan capacity and performance tests, run chaos experiments safely and lead blameless post-incident reviews.

Before you start

Chapter 2, especially the sections on performance and scalability and on availability and reliability; Chapter 6, especially why distribute, communication and APIs; and Chapter 7's sections on replication, partitioning and caching.

Time

About 3½ hours to read; 45 minutes for the test.

Key terms

scale cube · autoscaling · stateless service · layer 7 load balancer · power of two random choices · back pressure · load shedding · token bucket · circuit breaker · bulkhead · error budget · burn rate · distributed tracing · chaos engineering

From qualities on paper to qualities in production

Chapter 2 made performance and availability precise: latency percentiles, throughput, Little's law, utilisation and the nines, written as testable quality attribute scenarios. This chapter is about achieving those scenarios in a running system and keeping them true on the busiest day of the year. A design that meets its targets in a diagram can still fall over at 12:30 on a Friday when every office in the city orders lunch, or at 10:00 on the morning concert tickets go on sale. The difference between the two is rarely clever code. It is a set of architectural decisions about how capacity is added, how load is spread, how work waits, how failures are contained, and how the people running the system know what it is doing.

Two running examples carry through the chapter. The food-delivery platform has a sharp daily lunchtime and evening peak, dozens of services and third-party dependencies such as payment providers and mapping APIs. The ticketing on-sale is the extreme case: demand that rises from almost nothing to many times the system's capacity within seconds, for a fixed stock of seats, with the whole country watching. Between them they exercise every technique in the chapter.

Handling load: scaling, balancing and waiting

The first four sections are about load. Scaling strategies compares scaling up with scaling out, uses Abbott and Fisher's scale cube to separate cloning, splitting by function and splitting by data, and explains why autoscaling on CPU is often the wrong choice and how to size a fleet for a known peak with Little's law and headroom. Load balancing, statelessness and sessions covers what sits in front of the instances: layer 4 and layer 7 load balancers, the algorithms they use (including the power of two random choices), health checks that do not take a whole fleet out at once, connection draining, and why sticky sessions should give way to externalised session state.

Asynchrony, queues and back pressure is about what happens when work arrives faster than it can be done. Queues turn spikes into backlogs, which is useful only if the backlog is bounded and drains in an acceptable time. Back pressure, load shedding and rate limiting decide which work is accepted, which waits and which is refused politely with HTTP 429. Timeouts, retries, circuit breakers, bulkheads and graceful degradation then deals with failure between services: timeouts and deadlines, retries with backoff and jitter and the budgets that stop retry storms, circuit breakers, bulkheads, fallbacks, idempotency and hedged requests. Its worked example shows how one missing timeout lets a single slow dependency take down everything that calls it.

Running the system: objectives, observability, testing and learning

The second half turns from mechanisms to operation. SLIs, SLOs, SLAs and error budgets shows how to state reliability from the user's point of view, how an error budget turns an availability target into a quantity of allowed failure that teams can spend on change, and how burn-rate alerts page people only when that budget is genuinely at risk. Observability covers the logs, metrics and traces that let engineers ask new questions of a production system, the RED and USE methods and the four golden signals, distributed tracing with OpenTelemetry, and the cost of high-cardinality data.

Capacity planning and performance testing closes the loop between forecasts and evidence: load, stress, soak, spike and breakpoint tests, open and closed workload models, coordinated omission, and a capacity plan for a ticket on-sale. Chaos engineering, incidents and blameless learning deals with the failures that happen anyway: experimenting deliberately in production to find weaknesses before customers do, running incidents with clear roles, and holding blameless reviews whose action items change the system rather than the people.

How the sections fit together

The sections form a chain. Scaling and load balancing add capacity; queues and back pressure decide what happens when capacity runs out anyway; resilience patterns stop a local problem becoming a global one. SLOs say how good is good enough, observability shows whether the system is meeting that standard and why not, testing and capacity planning predict when it will stop doing so, and chaos engineering and incident reviews find the gaps in all of the above. Most of the mechanisms are cheap to add at design time and expensive to retrofit, which is why they are architecture rather than operations detail: whether a service is stateless, whether a call is idempotent, whether a queue is bounded and whether a request carries a deadline are all decided long before the first incident.

The chapter assumes the distributed styles of Chapter 6 and the data architecture of Chapter 7. It links back to them for idempotency keys, delivery guarantees, replication and caching rather than repeating them, and forward to Chapter 10 for the cloud platforms, Kubernetes features and multi-region designs these systems usually run on.

The one idea to take away

Every resource is finite, so every system has a breaking point; the architect's job is to decide in advance what happens when it is reached. A well-designed system under excessive load slows down gracefully, sheds the least important work first, refuses clearly rather than timing out silently, isolates the failing part and recovers by itself when the pressure passes. A poorly designed one queues without limit, retries until it collapses and takes its neighbours with it. The difference is made of small, deliberate choices (a timeout here, a bounded queue there, a retry budget, a readiness check) and of the habit of measuring, testing and learning from the system as it actually runs.

The 8 sections

9.1 · Intermediate · 28 minScalingScaling up and out and their limits, Abbott and Fisher's scale cube, statelessness, reactive, scheduled and predictive autoscaling, choosing a scaling signal, avoiding flapping, and sizing a fleet for a peak.Read →9.2 · Intermediate · 27 minLoad balancingLayer 4 and layer 7 load balancers, the main algorithms including the power of two random choices, liveness and readiness checks, connection draining, the trouble with sticky sessions, externalised session state and global load balancing.Read →9.3 · Intermediate · 29 minQueues and back pressureHow queues turn spikes into backlogs, competing consumers, sizing queues with Little's law, back pressure, load shedding and prioritisation, token-bucket and other rate limiters, HTTP 429 with Retry-After, and dead-letter queues.Read →9.4 · Advanced · 32 minResilience patternsThe stability patterns that stop one slow dependency taking down a system: timeouts and deadlines, retries with backoff, jitter and budgets, circuit breakers, bulkheads, fallbacks, idempotency and hedged requests.Read →9.5 · Intermediate · 24 minSLOs and error budgetsHow to measure reliability from the user's point of view with SLIs, set SLO targets, turn them into error budgets and policies, alert on burn rate and keep SLAs safely looser than internal objectives.Read →9.6 · Intermediate · 26 minObservabilityHow to see inside a running distributed system: structured logs, metric types and histograms, RED, USE and the golden signals, distributed tracing with W3C Trace Context and OpenTelemetry, cardinality and symptom-based alerting.Read →9.7 · Advanced · 25 minCapacity and testingHow to plan capacity before demand arrives and test that it is really there: forecasting, headroom and lead times, load, stress, soak, spike and breakpoint tests, open and closed workloads, coordinated omission and performance budgets.Read →9.8 · Intermediate · 25 minChaos and incidentsHow to find weaknesses before users do and learn from failures that happen anyway: chaos experiments and game days, incident command, severity levels and status pages, blameless reviews, the limits of MTTR and actions that change the system.Read →

Chapter test

Test your understanding of Chapter 9

Optional: 20 multiple-choice questions and 2 short written answers, drawn afresh from a bank of 72 questions. Pass mark 80%. Passing every chapter test, then the final assessment, earns the Be Wise Certificate of Completion.

Take the Chapter 9 test in the app

Further reading