← Better Programmer course
03
Intermediate
3 hours

Performance and Scale

Measure system behavior and apply the simplest effective scaling technique.

Learning outcome

Use latency and throughput evidence to locate bottlenecks, evaluate scaling, caching, and CDN options, and produce a measured performance plan.

Jump to a chapter
  1. 1. Latency and Throughput
  2. 2. Percentiles and Bottlenecks
  3. 3. Vertical Scaling
  4. 4. Horizontal Scaling and Load Balancers
  5. 5. Browser and Application Caching
  6. 6. Content Delivery Networks
  7. 7. Build a Measured Performance Plan
  8. Applied exercise
  9. Knowledge check

Chapter 1

Latency and Throughput

Measure how long work takes and how much work a system completes.

Latency is elapsed time for one operation, measured from a defined start to a defined finish. Throughput is the number of completed operations per unit of time. They answer different questions: a service can complete many requests each second while some individual requests remain slow. Clear boundaries matter because browser latency includes network and rendering work that server processing latency does not.

As incoming work increases, resources such as CPU, connections, or workers become busier. Near capacity, requests wait in queues before processing, so latency can rise sharply even if each operation's service time is unchanged. Throughput eventually reaches a ceiling. Measuring offered requests, completed requests, errors, queue time, and active work reveals whether the system is keeping up or merely accumulating a backlog.

For example, an image service completes 500 images per minute with two-second median latency. A burst of 700 per minute grows its queue and pushes completion latency higher while throughput remains near 500. In practice, define user-visible latency goals, measure throughput by meaningful operation, test behavior near expected peaks, and include failures rather than counting only successful work.

Key insight

Latency describes one operation's wait; throughput describes the system's completion rate, and queues connect the two near capacity.

How to apply this

  • Name the exact start and finish boundary for every latency metric.
  • Track offered load, successful throughput, errors, and queue depth together.
  • Set targets from user and business needs rather than from an isolated benchmark.
Scenario — A worker queue grows all afternoon

Situation

Jobs arrive faster than workers complete them, though the processing time reported inside each worker looks stable.

Decision

Measure end-to-end latency including queue wait and compare arrival rate with completion throughput before tuning worker code.

Chapter 2

Percentiles and Bottlenecks

Describe the distribution of experience and find the limiting resource.

A latency percentile is a value below which a percentage of observations fall. If the 95th percentile is 800 milliseconds, 95 percent of measured operations finished in 800 milliseconds or less, while 5 percent took longer. Percentiles exist because one average can hide a slow minority. They should always include a time window, operation, population, and measurement boundary.

A bottleneck is the resource or stage that currently limits throughput or dominates delay. To locate it, split a request into timed stages and correlate latency with resource saturation, queueing, errors, and workload type. Compare percentile distributions rather than one anecdote. Then change one likely constraint and repeat the same measurement; if the limit moves, the evidence supports the diagnosis.

An API has a 120-millisecond median but a two-second 99th percentile. Traces show that requests with a large account history perform repeated database calls and occupy all connection slots. Practical work segments those requests, measures database wait and query time separately, fixes the repeated access, and verifies both tail latency and resource utilization under the same load.

Key insight

Percentiles expose tail behavior; stage timings and saturation evidence identify the bottleneck causing it.

How to apply this

  • Report median and tail percentiles with operation, population, and time window.
  • Segment measurements by request type, region, or data size to avoid mixed signals.
  • Validate a bottleneck by changing it and rerunning a comparable test.
Scenario — The average is healthy but customers complain

Situation

Most searches are fast, but searches for a small set of large organizations time out.

Decision

Inspect high-percentile latency by organization size and trace those requests instead of relying on the overall average.

Chapter 3

Vertical Scaling

Increase the capacity of one machine or service instance.

Vertical scaling gives a single node more resources, such as CPU cores, memory, faster storage, or network capacity. It exists because a larger node can handle more work without changing how requests are distributed. This is often the simplest response when one instance is resource-limited and a larger reliable size is available.

First identify the saturated resource. Choose a larger instance that increases that resource, verify software and license limits, then benchmark a representative workload. Plan the resize or replacement, observe capacity and latency afterward, and retain a rollback path. Added resources help only if the workload can use them; a single-threaded CPU path may not benefit from many additional cores.

A database repeatedly reaches its memory limit and reads hot pages from slow storage. Moving to a node with enough memory may sharply reduce read latency without partitioning data. In practice, estimate cost per unit of useful capacity, leave headroom for bursts and failover, test restart or migration time, and document the maximum viable node size so vertical scaling is not mistaken for an unlimited strategy.

Key insight

Vertical scaling is operationally simple, but bounded and effective only when added resources match the measured constraint.

How to apply this

  • Scale the constrained resource rather than selecting a larger label blindly.
  • Benchmark representative data and concurrency before and after resizing.
  • Plan for the cost, downtime, and hard ceiling of the largest practical node.
Scenario — A database cache no longer fits in memory

Situation

Storage reads and query latency rise after the active data set outgrows RAM, while CPU remains moderate.

Decision

Test a memory-focused vertical resize and compare cache-hit and latency metrics before considering a distributed redesign.

Chapter 4

Horizontal Scaling and Load Balancers

Add equivalent instances and distribute requests among them.

Horizontal scaling adds service instances rather than enlarging one. A load balancer accepts client traffic and selects a healthy instance for each request. This exists to increase aggregate capacity, replace failed instances, and permit gradual deployment. It works best when instances are interchangeable and essential state is held in shared durable services.

Instances register with or sit behind the load balancer. Health checks remove instances that cannot safely serve traffic, and a routing algorithm spreads new requests. When load rises, automation can add instances; when it falls, instances can drain existing work and stop. The database or another downstream service must also support the resulting concurrency, or horizontal application scaling merely moves the bottleneck.

If one API instance safely handles 100 requests per second, four may approach 400 under a suitable workload, minus coordination and downstream limits. In practice, make shutdown graceful, separate process liveness from readiness to serve, set per-instance concurrency limits, test instance loss, and avoid session data that silently pins a user to one machine.

Key insight

Horizontal scaling increases interchangeable compute capacity, while the load balancer routes only to instances ready to serve.

How to apply this

  • Keep request handlers stateless or put required state in shared services.
  • Design readiness checks around the ability to serve safely, not merely a running process.
  • Load-test downstream dependencies as instance count and concurrency increase.
Scenario — Adding API instances makes the database slower

Situation

Ten new instances each open a large connection pool, overwhelming the database connection limit.

Decision

Set a system-wide connection budget and right-size each pool before increasing application replicas further.

Chapter 5

Browser and Application Caching

Reuse previous results close to where repeated work occurs.

A cache stores a result so a later request can reuse it instead of repeating expensive work. A browser cache keeps responses near one user; an application cache keeps computed or fetched values near server code and may serve many users. Caches exist to lower latency, reduce downstream load, and sometimes continue serving safe older data during a brief dependency problem.

A request first constructs a cache key and checks for a valid entry. On a hit, it returns the stored value; on a miss, it computes or fetches the value, stores it with an expiration, and returns it. Browser response headers control reuse and revalidation. Application caches also need rules for invalidation, size eviction, concurrent misses, and failure. Every key must include all input that changes the result, including authorization scope.

A product catalog page can cache public item details for five minutes, while a user's private price agreement requires a user or account-specific key and possibly a shorter lifetime. Practically, choose data with high reuse and acceptable staleness, measure hit rate and miss cost, prevent a flood of identical misses, and treat the source store rather than the cache as the durable authority.

Key insight

Caching trades freshness and complexity for faster reuse, so keys, lifetime, and invalidation are correctness decisions.

How to apply this

  • Include every result-changing input and security scope in the cache key.
  • Define expiration and invalidation from acceptable staleness.
  • Measure hit rate, miss latency, eviction, and load on the source system.
Scenario — One customer sees another customer's discount

Situation

An application cache keys product prices only by product ID even though prices vary by account.

Decision

Disable the unsafe entry and redesign the key to include account scope, then test for cross-account isolation.

Chapter 6

Content Delivery Networks

Serve cacheable content from geographically distributed edge locations.

A content delivery network, or CDN, is a distributed set of edge servers that receives requests through a service's public host name. It exists to serve reusable content closer to users, reduce traffic to the origin server, and absorb large request volumes across many locations. A CDN is an independent network layer, not the same thing as a browser cache or an application cache.

DNS or network routing directs a user to a nearby edge. The edge evaluates its cache key and freshness rules. On a hit, it responds without contacting the origin; on a miss, it fetches from the origin, may store the response, and forwards it to the user. Cache-control headers, explicit purge operations, and versioned asset names govern freshness. Dynamic requests can pass through without being cached.

A site can publish app.4f2c.js with a content-based name and a one-year cache lifetime. New deployments use a new name, so no purge is needed, and users worldwide fetch it from nearby edges. In practice, cache public immutable assets first, keep authenticated or personalized responses private by default, monitor edge hit ratio and origin traffic, and test purge behavior before an emergency.

Key insight

A CDN is a shared geographic edge layer whose routing, keys, and freshness rules determine whether the origin is contacted.

How to apply this

  • Use versioned names and long lifetimes for immutable static assets.
  • Do not edge-cache personalized responses without an explicit isolation design.
  • Monitor CDN hit ratio, edge errors, origin latency, and origin request volume separately.
Scenario — A homepage update appears differently by region

Situation

Some CDN edges still hold a fresh copy of the old HTML after a deployment.

Decision

Use the planned purge or short HTML freshness policy, verify several regions, and keep immutable asset versioning separate.

Chapter 7

Build a Measured Performance Plan

Combine metrics, scaling, caching, and CDN choices in an evidence-driven sequence.

A measured performance plan connects a user outcome to a baseline, a diagnosed constraint, one proposed change, and a verification method. It prevents teams from applying fashionable techniques without knowing whether they address the limiting stage. The plan also states a capacity target and guardrails for correctness, cost, and reliability.

Start with a service-level goal and representative workload. Capture latency percentiles, throughput, errors, saturation, queueing, cache behavior, and request traces. Locate the current bottleneck, then choose the smallest fitting intervention: tune work, scale a constrained node vertically, add stateless instances horizontally, cache repeated computation, or move public reusable delivery to a CDN. Predict an outcome, test safely, compare against the baseline, and keep, revise, or roll back.

Suppose an international catalog has a 2.5-second 95th percentile against a one-second goal. Traces show static assets cross an ocean while API processing remains under 200 milliseconds; a CDN and versioned assets are the first experiment, not database sharding. In practice, assign owners and dates, estimate cost, protect data freshness and access control, and repeat measurements because removing one limit often exposes the next.

Key insight

Performance work is a loop: define, measure, locate, change one constraint, verify, and repeat.

How to apply this

  • Tie every optimization to a user-visible target and baseline metric.
  • Write the predicted metric change and safety guardrails before implementation.
  • Compare under the same workload and retain a rollback decision rule.
Scenario — A launch is expected to triple traffic

Situation

The team proposes more servers, a new cache, and a CDN at once without a current load test.

Decision

Build a representative baseline, find the first capacity limit, and stage independently measurable changes with explicit rollback criteria.

Applied exercise

Create a performance improvement proposal

Use measurements from a real service or a clearly labeled sample workload to propose one safe, testable improvement.

  1. 01Define one user journey, its latency percentile target, expected peak throughput, and acceptable error rate.
  2. 02Collect or specify a baseline including stage timings, resource saturation, queue depth, and cache or CDN behavior where relevant.
  3. 03Identify the evidence-supported bottleneck and explain why at least two other components are not the first constraint.
  4. 04Select one intervention from tuning, vertical scaling, horizontal scaling, browser or application caching, or CDN delivery.
  5. 05Write the expected metric change, load-test method, correctness guardrails, cost limit, rollout steps, and rollback trigger.
  6. 06Describe which metric you will inspect next if the experiment succeeds and exposes a new bottleneck.

Deliverable

A two-page performance plan with baseline evidence, one hypothesis, an experiment, success criteria, safety checks, and rollback steps.

Knowledge check

Check your understanding before finishing

Answer from the reasoning and trade-offs, not keyword memory. After submitting, review the explanation for every question.

Q1What often happens when incoming work exceeds maximum throughput?
Q2What does a 95th-percentile latency of 800 milliseconds mean?
Q3When is vertical scaling a strong first option?
Q4What is required for a safe shared cache key?
Q5Which is the best performance improvement sequence?