LearnastraTHE DESIGN COURSE

Understand the building blocks / CHAPTER 09

Load balancing

Distribute requests across healthy capacity while preserving deadlines and safe failure behavior.

Beginner1h of deliberate study10 questions

Builds on System design building blocks, Characteristics of distributed systems.

By the end, you can
  • Explain the role of a load balancer.
  • Distinguish transport and application routing.
  • Plan health checks, draining, and overload behavior.

01One front door, several workers

A shopper requests the product catalog. Four application servers, A through D, can all answer the request. The client uses one public address; a load balancer receives the request and chooses a server behind that address. These application servers are often called backends.

Work through capacity before choosing the routing rule:

  1. Tests show that each server handles 350 representative requests per second within the response-time target.
  2. At a peak of 900 requests per second, four servers receive about 900 / 4 = 225 each under even routing.
  3. If D is removed, three servers receive about 900 / 3 = 300 each.
  4. Compare 300 with the tested limit of 350. The survivors have some margin, provided the request mix and routing remain similar.

The balancer makes these servers usable as a pool. It cannot make a slow shared database faster or decide which shopper may claim the last item.

Two routing approaches inspect different information:

  • A transport-layer balancer chooses a destination using connection information, such as addresses and ports. It need not read the HTTP request.
  • An application-layer balancer can read HTTP information, such as the website name or /catalog path, and route accordingly.
  • If the balancer ends the client’s encrypted connection so it can read HTTP, that is TLS termination. TLS protects that connection; the separate connection to the application needs its own protection.

02Follow health and safe replacement

D starts successfully, but is still loading the catalog data needed to answer requests. Its process exists, yet sending shoppers to it would cause errors. Separate two checks:

  • A liveness check asks whether restarting this process is likely to help.
  • A readiness check asks whether this instance can handle new requests now.

For a planned replacement, the operator and routing layer follow this sequence:

  1. Mark D unready so the routing layer stops selecting it for new work.
  2. Allow time for that change to reach the routing layer.
  3. Let requests already running on D finish, up to a stated deadline. This is draining.
  4. Close remaining long-lived connections according to the reconnect policy, then stop D.
  5. Start the replacement. Route new requests to it only after its required data and services are ready.

A WebSocket connection cannot simply move intact to another server. The client must reconnect, and the application needs saved state from which it can resume. A session that exists only in D’s memory may disappear with D.

Health checks also have limits:

  • An active check periodically probes a server. The interval creates a delay before a failure is noticed.
  • Passive observations use real responses, errors, and timeouts. A healthy flag should not override repeated failed requests.
  • An optional recommendation service can fail while the catalog remains useful. Marking every catalog instance unready for that optional failure can unnecessarily remove the whole pool.

Some traffic may still reach a failed instance before the routing layer reacts. Safe deadlines and retry rules remain necessary.

03State, overload, and shared limits

Suppose one shopper makes many requests. Always routing that shopper to the same server may reuse information already loaded there, but can overload that server while others are idle. This routing preference is session affinity. It does not copy session data or preserve it after a crash.

Check the complete request path:

  1. Measure how much work each application server is doing, rather than checking request totals alone.
  2. Check the shared database. If all servers wait for the same slow query, adding application servers can increase the database’s waiting queue.
  3. Set maximum counts for running requests and queued requests. When the queue limit is reached, reject new excess work rather than keep adding it. Remove requests that are still queued when their caller’s deadline expires; do not start work after that deadline.
  4. Carry the caller’s time budget through the path. From a 300 ms allowance, 100 ms already spent leaves at most 200 ms for remaining work and returning the response.
  5. Retry only if time remains and the operation can safely repeat. A purchase may have committed even if its response disappeared. Repeated reads also add load to an overloaded service.

The balancer is part of the required path too. One unprotected balancer process can make every healthy application server unreachable if it fails.

Test specific disruptions:

  • Remove one application server at peak demand and measure the survivors’ response times.
  • Replace a server while requests and long-lived connections are active.
  • Start a replacement with an empty cache or unloaded data.
  • Fail part of the balancer’s serving path.
  • Slow the shared database and verify that waiting remains bounded.

Successful balancing means callers receive useful responses within their limits, including during the named failure. Equal request counts are only one possible means to that outcome.

A drain changes assignment before termination

A drain changes assignment before terminationThe routing layer stops assigning new requests to D. Existing work on D finishes within the drain deadline. The three survivors each receive about 300 requests per second, assuming even work. The operator checks their response times and the shared database before declaring the replacement safe. Numbered arrows correspond to the connection key below. All connections are directional.900 requests/sCatalog workloadResilientbalancerRoutes only readycapacityA, B, C survive300/s each underassumptionsD is drainingNo new work; existingresponses finishShared databaseSeparate capacityboundary1234A drain changes assignment before terminationThe routing layer stops assigning new requests to D. Existing work on D finishes within the drain deadline. The three survivors each receive about 300 requests per second, assuming even work. The operator checks their response times and the shared database before declaring the replacement safe. Numbered arrows correspond to the connection key below. All connections are directional.900 requests/sCatalog workloadResilientbalancerRoutes only readycapacityA, B, C survive300/s each underassumptionsD is drainingNo new work; existingresponses finishShared databaseSeparate capacityboundary1234A drain changes assignment before terminationThe routing layer stops assigning new requests to D. Existing work on D finishes within the drain deadline. The three survivors each receive about 300 requests per second, assuming even work. The operator checks their response times and the shared database before declaring the replacement safe. Numbered arrows correspond to the connection key below. All connections are directional.900 requests/sCatalog workloadResilientbalancerRoutes only readycapacityA, B, C survive300/s each underassumptionsD is drainingNo new work; existingresponses finishShared databaseSeparate capacityboundary1234

Follow the numbered arrows

  1. 900 requests/s → Resilient balancercaller deadline accompanies work
  2. Resilient balancer → A, B, C surviveassign new requests
  3. D is draining → Resilient balancerfinish existing responses only
  4. A, B, C survive → Shared databasequeries can still bottleneck
D stops receiving new requests before it shuts down. The same 900 requests per second now go to A, B, and C, about 300 each. Their database remains a separate capacity check.
Trace the diagram in words
  1. The routing layer stops assigning new requests to D.
  2. Existing work on D finishes within the drain deadline.
  3. The three survivors each receive about 300 requests per second, assuming even work.
  4. The operator checks their response times and the shared database before declaring the replacement safe.

DRAW. CALCULATE. EXPLAIN.

Plan one failure during peak

20 minutes · guided practice

Five workers each handle 250 representative requests per second within the target response time. Peak demand is 1,000 per second.

  1. Calculate the load after one worker fails.
  2. Repeat for a demand of 1,200 per second.
  3. Explain how to replace a worker and handle excess demand without unbounded waiting.
Your self-check
Compare the worked solution
  1. One failure leaves four workers. At 1,000 requests per second, 1000 / 4 = 250 reach each worker under even routing. This is exactly the tested limit, so uneven work or retries may exceed it.
  2. At 1,200 requests per second, 1200 / 4 = 300 reach each survivor. That exceeds the tested 250-per-second capacity.
  3. During replacement, stop new assignments before stopping the worker. Let existing work finish within a deadline and give long-lived clients a reconnect path backed by saved state.
  4. For the higher demand, add tested capacity or reject excess work according to policy. Limit waiting and retries; neither creates more processing capacity.
  5. Measure survivor response times and the shared database’s load. Even perfect application routing cannot repair a saturated database.

The checkboxes record your own assessment. The worked solution gives you a way to check the reasoning.

RETRIEVE BEFORE YOU REVEAL

Keep the important ideas.

Say the answer aloud, then turn the card over.

CARD 01What does balancing solve?
  1. The balancer receives a request at one public endpoint.
  2. It selects a ready application server.
  3. The server performs the operation.

The database still needs enough capacity, and a repeated write still needs its original request identifier and saved result so it does not repeat the purchase.

CARD 02What do liveness, readiness and draining each control?
  • Liveness asks whether a restart would help.
  • Readiness controls new request assignments.
  • Draining stops new assignments and lets existing work finish within a limit.

Long-lived clients need to reconnect and recover saved state.

CARD 03How do I plan failure capacity?
  1. Remove the machines covered by the failure assumption.
  2. Divide peak demand among the survivors.
  3. Compare their load with tested capacity at the response-time target.
  4. Allow for uneven work, retries, and shared dependencies.
Practise this topic in the revision deck ↗

CHECK THE REASONING

Can you explain the choice?

Answer every question, then finish for an immediate score and an explanation for each answer. Aim for 80%, then revisit any gaps.

1 / 10Four catalog instances share 900/s. D is drained. Approximate survivor load under even routing?
2 / 10D is alive but has not loaded required state. What should readiness do?
3 / 10Before terminating D, what should happen first?
4 / 10A WebSocket client is connected to D during replacement. What else is needed?
5 / 10What can application-layer balancing use for HTTP routing?
6 / 10All four instances wait on one saturated database. Which action directly addresses the diagnosis?
7 / 10An optional recommendation service fails. Should every catalog instance become unready?
8 / 10Why can session affinity make load less even?
9 / 10Why bound a balancer’s waiting queue?
10 / 10What must the balancer itself have for a high-availability goal?
0 of 10 answered

CLOSE THE LOOP

Explain it without the page.

Summarise the mechanism, one trade-off, and one failure mode. Then mark this chapter complete.