Your country

Tools that support it use your country for local currency, number formats, units and paper size. Your choice is saved only in this browser.

Type a name or a two-letter code. Use the up and down arrow keys to move through the countries, Enter to choose one and Escape to close.

System Design (High-Level Design)  Module 19 – Building blocks: traffic, storage and messaging

Design a software load balancer

Design a layer-4 load balancer from ordinary servers, with ECMP, Maglev hashing, connection tables, direct server return and a separate control plane.

  • Advanced
  • 25 minutes
  • Examples run with Python 3.14.8, Pyodide 314.0.7, Node.js 24.21.0 and quickjs 0.32.0
  • By MySmartCoPilot
Free intro, Pro: 5 of 25 minutes free
Free: Requirements and estimate: direct return and 30 million open connections. With a pass: the other 14 sections and 3 interview answers, about 20 minutes.

What you will learn

  • Estimate the packets, connections and connection-table memory of a region's load balancer
  • Design a layer-4 balancer tier that scales out behind ECMP with direct server return
  • Build a Maglev lookup table and measure how many flows move when backends change
  • Prevent broken connections when balancer nodes fail, restart or change
  • Separate the control plane from a data plane that keeps forwarding without it

Before you start

What you’ll learn · Before you start

What you will learn

  • Estimate the packets, connections and connection-table memory of a region's load balancer
  • Design a layer-4 balancer tier that scales out behind ECMP with direct server return
  • Build a Maglev lookup table and measure how many flows move when backends change
  • Prevent broken connections when balancer nodes fail, restart or change
  • Separate the control plane from a data plane that keeps forwarding without it

Before you start

On this page

A software load balancer is a fleet of ordinary servers that share one virtual IP address (VIP): An IP address that belongs to a service rather than to one machine: several servers answer for it, so clients keep one address while the servers behind it come and go., or VIP: in the design below, 10 nodes for 30 million packets a second. The network’s routers spread the packets of that address over the fleet with equal-cost multipath (ECMP): A routing feature that spreads the traffic for one destination over several next hops of equal cost, usually by hashing each packet's addresses and ports, so that every packet of a flow takes the same next hop. (ECMP); each balancer node then picks a backend for the packet’s flow and tunnels the packet to it, and the backend replies to the client directly. The design has to keep every packet of a connection on the same backend while balancer nodes and backends come and go, so every node must choose the same backend for the same flow: a consistent-hashing table that all nodes build alike, plus a connection table: A load balancer node's memory of the backend it chose for each flow it has seen, so that the flow's later packets go to the same backend without a new choice. on each node. A control plane hands out backend lists, and the nodes keep forwarding without it.

Requirements and estimate: direct return and 30 million open connections

A region serves web pages and APIs to millions of users through a few public addresses. A pair of hardware balancers carries it today, and every traffic peak is a capacity problem, because a pair grows only by replacing both boxes. Ask first:

Question Assumed here
Which protocols: TCP only, or UDP and QUIC as well? TCP and UDP
What are the peak packet and connection rates, how large are packets, and how long do connections last? 30 million packets a second arriving, 120 bytes on average; 1.5 million new connections a second that stay open 20 seconds
How fast must a dead backend stop receiving new connections, and may connections break when a balancer node fails? Out of new flows within seconds; no connection broken by a change in the balancer tier
Do backends need the client’s address, and do they end TLS themselves? L7 proxies that end TLS and need it
Who changes the backend lists, how often, and what happens to forwarding while that system is down? Hundreds a day; forwarding never waits

Functional requirements: forward TCP and UDP for many VIPs; spread flows over a VIP’s backends by weight; health checks, draining and slow start; connection limits per backend; configuration by API. Non-functional requirements: line-rate forwarding of small packets; growth by adding nodes; no broken connections when a node fails or restarts; forwarding that continues while the control plane is down.

The first estimate, to change and run again:

Packets, nodes and connection tables Python · plan/lb_estimate.py
# The first estimate for a region's layer-4 software load balancer. Every input is an assumption, written down so
# that you can change it and run the script again.
import math

PACKETS_IN = 30e6          # packets a second arriving for the region's virtual IPs at peak (requests and ACKs)
PACKET_BYTES = 120         # average size of an arriving packet
RESPONSE_RATIO = 12        # bytes sent back for every byte that arrives (pages, images, API responses)
NEW_CONNECTIONS = 1.5e6    # new TCP connections a second at peak
LIFETIME = 20              # seconds an average connection stays open
NODE_PPS = 8e6             # packets a second one balancer node can forward
TARGET = 0.5               # run the nodes at half their capacity at peak
SPARE = 2                  # nodes that may be down or in maintenance at the same time
ENTRY_BYTES = 64           # one connection-table entry: flow key, backend, timestamps

inbound = PACKETS_IN * PACKET_BYTES * 8 / 1e9
print("Traffic")
print(f"  arriving: {PACKETS_IN / 1e6:.0f} million packets a second x {PACKET_BYTES} bytes = {inbound:.1f} Gbit/s")
print(f"  leaving: {inbound * RESPONSE_RATIO:.1f} Gbit/s, sent by the backends straight to the clients")
print(f"  through the balancer, both ways would be {inbound * (1 + RESPONSE_RATIO):.1f} Gbit/s, "
      f"{1 + RESPONSE_RATIO:.0f} times as much")

nodes = math.ceil(PACKETS_IN / (NODE_PPS * TARGET))
print("Balancer nodes")
print(f"  {PACKETS_IN / 1e6:.0f} million / ({NODE_PPS / 1e6:.0f} million x {TARGET:.0%}) = {nodes} nodes, "
      f"plus {SPARE} spare = {nodes + SPARE}")

open_now = NEW_CONNECTIONS * LIFETIME
per_node = open_now / (nodes + SPARE)
print("Connection tables")
print(f"  open connections (Little's law): {NEW_CONNECTIONS / 1e6:.1f} million a second x {LIFETIME} s "
      f"= {open_now / 1e6:.0f} million")
print(f"  per node: {per_node / 1e6:.0f} million entries x {ENTRY_BYTES} bytes = {per_node * ENTRY_BYTES / 1e6:.0f} MB")
print(f"  when one node fails, at least its share, {open_now / (nodes + SPARE) / 1e6:.0f} million connections, "
      f"arrives at nodes that have never seen them")

Output

Traffic
  arriving: 30 million packets a second x 120 bytes = 28.8 Gbit/s
  leaving: 345.6 Gbit/s, sent by the backends straight to the clients
  through the balancer, both ways would be 374.4 Gbit/s, 13 times as much
Balancer nodes
  30 million / (8 million x 50%) = 8 nodes, plus 2 spare = 10
Connection tables
  open connections (Little's law): 1.5 million a second x 20 s = 30 million
  per node: 3 million entries x 64 bytes = 192 MB
  when one node fails, at least its share, 3 million connections, arrives at nodes that have never seen them

Recorded with Python 3.14.8 on macOS 26 arm64. To run it yourself: mise exec python@3.14.8 -- python3 lb_estimate.py

Two numbers shape the design. Because responses go straight back, the balancer carries a thirteenth of the bytes. And 30 million open connections mean that every node holds millions of table entries, and that a failed node hands millions of connections to nodes that have never seen them.

Checkpoint

Check the estimate

  1. Question 1 of 2 New connections double to 3 million a second, and each still stays open 20 seconds on average. How many connections are open at once?

    Type a number.

    A hint

    Little's law multiplies the arrival rate by the time each connection stays.

    Show the answer: Question 1 of 2

    Answer: 60 million connections (anything from 54 to 66 counts)

    Open connections = arrival rate × time in the system = 3 million a second × 20 s = 60 million, twice the estimate's 30 million. The number of open connections, not the packet rate, sets the size of the tables.

  2. Question 2 of 2 Those 60 million connections spread evenly over 10 balancer nodes, at 64 bytes per connection-table entry. How much memory does each node's table need?

    Type a number.

    A hint

    Divide the connections among the nodes first, then multiply by the size of one entry.

    Show the answer: Question 2 of 2

    Answer: 384 MB (anything from 346 to 422 counts)

    60 million ÷ 10 nodes = 6 million entries per node, × 64 bytes = 384 MB, before any spare room for floods. The estimate's 30 million gave 192 MB.

The first design: every node picks the same backend

A router spreads flows over identical balancer nodes that tunnel packets to backends; backends reply directly; a control plane configures.Clientssend packets to the virtual IP203.0.113.10Routerhashes each flow to one node (ECMP);every node announces the VIP by BGPBalancer nodes, all alikeControl planebackend lists, weights, health;pushes versioned configBackends: each replies to the client directly (DSR)Node 1connection table+ Maglev tableNode 2connection table+ Maglev tableNode 10connection table+ Maglev tableL7 proxyor serverL7 proxyor serverL7 proxyor serverpackets inone flow, one nodepacket tunnelled(GRE or IPIP)config

The first design of the software load balancer

Text description of the diagram

The diagram shows the first design from top to bottom.

  • Clients send packets to the virtual IP, 203.0.113.10.
  • A router hashes each flow to one balancer node by equal-cost multipath (ECMP). Every node announces the virtual IP to the router by BGP.
  • The balancer nodes are all alike: node 1, node 2 and so on up to node 10. Each holds a connection table and a Maglev lookup table.
  • Each node tunnels a packet to the chosen backend, wrapped in GRE or IPIP. The backends are L7 proxies or servers.
  • A dashed arrow shows the control plane, which holds the backend lists, weights and health, pushing versioned configuration to the nodes.
  • The backends send their responses straight back to the clients, without passing through the balancer: direct server return (DSR).

Each part of the design has one job:

  • ECMP at the router: hashes each flow’s addresses and ports to one of the equal-cost next hops, the nodes.
  • VIP announcement by BGP: each healthy node announces the virtual IP, and withdraws it when it is unhealthy.
  • Maglev lookup table: a table of a prime number of entries filled with backends, the same on every node.
  • Connection table: each node’s memory of the backend it chose for every flow it has seen.
  • Encapsulation: the node wraps each packet in GRE or IP-in-IP addressed to the backend, leaving it intact.
  • Direct server return: the backend answers the client from the virtual IP, never back through a node.
  • Control plane: keeps VIPs, pools, weights and health, and pushes versioned configuration to every node.

Follow one connection’s packets through these parts:

Interactive · message by message One connection's packets through the balancer tier Step through the first packets of one connection, from the client to a backend and straight back to the client.
One connection's packets through the balancer tier, step 6 of 6. Messages so far: Client to Balancer node 3: SYN to the VIP; Balancer node 3 to Backend b7: tunnelled packet; Backend b7 to Client: response from the VIP; Client to Balancer node 3: next packet.Clientto VIP 203.0.113.10Balancer node 3flow to b7, in its tableBackend b7L7 proxySYN to the VIPtunnelled packetresponse from the VIPnext packet

The drawing shows the whole scene; its 6 steps are listed below.

Every step as text
  1. The router picks a node. The client's first packet goes to the virtual IP. The router hashes the flow's addresses and ports and sends it to node 3, one of the equal-cost next hops that announce the VIP.
  2. A new flow. Node 3 has no entry for this flow in its connection table, so it looks the flow up in the Maglev table, which every node builds from the same backend list. The table names backend b7.
  3. Remembered, then tunnelled. Node 3 records the flow and b7 in its connection table, wraps the packet in GRE or IP-in-IP addressed to b7 and sends it on, with the client's packet intact inside.
  4. Direct server return. b7 unwraps the packet, sees the client's real address and answers from the virtual IP straight to the client. Responses, 12 bytes for every byte that arrives in the estimate, never pass back through a node.
  5. The next packet. The flow's next packet hashes to node 3 again, which finds the flow in its connection table and tunnels it to b7 without another lookup.
  6. Every node would agree. Every node builds the same Maglev table from the same backend list, so any node would have chosen b7 for this flow. That is the property the deep dives below put to the test.

The deep dives that decide whether the design works:

  1. How is the lookup table built, how even is it, and how many flows move when a backend leaves?
  2. What breaks connections when a node fails, restarts or joins, and what keeps them alive?
  3. What happens when a node fails while the backends change at the same time?
  4. How do the control plane and the data plane stay apart?
  5. How many packets a second can a node forward, and what does a SYN flood do to its tables?
  6. What does encapsulation cost, and where do TLS and HTTP features live?

An answer is judged on requirements and estimates, flow placement, connection persistence, failure handling, control-plane design and operations.

Checkpoint

Check the first design

  1. Question 1 of 3 Arriving traffic grows to 60 million packets a second. Each node forwards 8 million a second, runs at half its capacity at peak, and 2 spare nodes are kept. How many nodes in total?

    Type a number.

    A hint

    A node at half capacity forwards 4 million packets a second.

    Show the answer: Question 1 of 3

    Answer: 17 nodes

    60 million ÷ (8 million × 0.5) = 15 nodes for the load, plus 2 spare = 17. The estimate's 30 million packets needed 8 plus 2.

  2. Question 2 of 3 What does direct server return change in this design?

    Choose one answer.

    Show the answer: Question 2 of 3

    Answer: Backends send their responses to clients without passing back through the balancer

    With direct server return the balancer carries the arriving packets only. Responses are 12 times the bytes of requests in the estimate, so the tier carries a thirteenth of what it would carry both ways.

  3. Question 3 of 3 After a route change, the packets of an open flow reach node 5 instead of node 3, which chose backend b7 for it. Which part of the first design lets node 5 send them to b7 as well?

    Choose one answer.

    Show the answer: Question 3 of 3

    Answer: The Maglev lookup table, which every node builds alike from the same backend list

    A connection table remembers only the flows its own node has seen. What keeps a moved flow on its backend is that every node computes the same answer from the same table.

The API, and three structures in every node Pro: opens with a Pro, Premium or Ultimate pass

In this part:

  • Maglev hashing builds an even table, at the price of a few extra moves
  • Connection tables, and the failures they do not cover
    • A balancer node dies
    • A node dies while a backend changes
    • A rolling restart of every node
  • Second chance: surviving changes on both sides at once
  • Control plane and data plane, kept apart
  • Packets per second, SYN floods and the table, with numbers
  • Encapsulation costs 20 or 24 bytes a packet, and TLS lives a tier behind
  • At 10× the router’s ECMP group gives out, at 100× the pools
  • Six alternatives, and why each loses
  • What each level is expected to cover
  • A sample answer and a 45-minute self-mock
  • Practise: fill the lookup table
    • Fill a Maglev lookup table from the backends' preferences
  • Interview questions
    • What is direct server return in a load balancer, and why do software load balancers use it?
    • During a rolling restart of your layer-4 balancer fleet, a few thousand long-lived connections were reset, although no backend changed. Each node picks a backend for a new flow by its own round robin and remembers it. Explain why connections broke, and redesign the tier so that restarts break none.
    • You must choose between a hash ring and a Maglev lookup table for a layer-4 balancer with 400 backends per virtual IP. Compare them on load balance, disruption when a backend changes, memory and rebuild time, with numbers, and decide.
    • A SYN flood fills the connection tables of your layer-4 balancer nodes. What happens to new and existing connections, and how do you design the tables and the nodes for floods?
  • Key takeaways

2 diagrams · 3 runnable examples (JavaScript, Python) · 1 exercise with sample tests · 3 interview answers · about 48 minutes

Opening this part with your pass…

This part opens with any MySmartCoPilot pass.

  • Pro pass · 1 week₹79$2.99
  • 30 days₹179$5.99
  • 1 year₹1,699$45

One payment; a pass never renews. The price shown is the total you pay: no fees or charges are added at checkout.

It also opens every other in-depth part in Learn and every Pro tool. Sales are final, except where the law gives you a right to withdraw, for example in the EU and the UK (refund policy).

Read a complete sample first: Design a unique ID generator

Terms in this lesson

connection table
A load balancer node's memory of the backend it chose for each flow it has seen, so that the flow's later packets go to the same backend without a new choice.
equal-cost multipath (ECMP)
A routing feature that spreads the traffic for one destination over several next hops of equal cost, usually by hashing each packet's addresses and ports, so that every packet of a flow takes the same next hop.
virtual IP address (VIP)
An IP address that belongs to a service rather than to one machine: several servers answer for it, so clients keep one address while the servers behind it come and go.

References

Related tools

Report a problem with this lesson

Quick answers and tool search

Type to search tools or to get a quick answer, for example 18% of 2500. Use the up and down arrow keys to move through the results, Enter to choose, and Escape to close.