Skip to content

    System Design

    System Design: The Request Lifecycle

    Follow one web request from the URL bar to the response: DNS, TCP, TLS, HTTP versions, CDN, load balancer, app and database, plus where the time goes and how sessions work.

    By Published 15 min read

    Share

    This lesson is part of System Design Foundations: From Zero to Your First Design. Enroll for free, then sign in, to read it in full.

    What you'll learn: By the end of this lesson you will be able to trace what happens between typing a URL and seeing a page, step by step. You will be able to explain how HTTP/1.1, HTTP/2 and HTTP/3 differ, say where a request spends its time, and describe the difference between stateless and stateful servers and how sessions and tokens fit in.

    Sending a letter looks simple from the outside: write, stamp, post. Inside, it passes through a local post box, a sorting office, a truck, another sorting office and a delivery round, and each hand-off adds time and a chance of loss. If you wanted the letter to arrive faster, you would have to know which hand-off is the slow one.

    A web request is a letter with a dozen hand-offs. You cannot make a system fast or reliable until you know what those hand-offs are. This lesson follows one request, step by step, using a shop's checkout page as the example. Later lessons on load balancing, caching and CDNs zoom in on individual steps.

    The core idea

    When you open https://shop.example.com/checkout, the browser knows only a name. To get a page it must:

    1. Find out where the server is (DNS).
    2. Open a reliable connection to it (TCP).
    3. Make that connection private (TLS).
    4. Ask for the page (HTTP).
    5. Let the server side work out the answer, passing through edge, load balancer, application, cache and database.
    6. Receive and render the response.

    Steps 1 to 3 are overhead that happen before a single byte of your page is requested. Each can cost a whole round trip time (RTT): the time for a message to travel to the server and for the reply to come back. On a nearby server an RTT is a few milliseconds. To a server on another continent it is easily 100 milliseconds. Since each setup step costs whole round trips, distance multiplies cost, and much of web performance engineering is about doing fewer round trips.

    The whole journey in one picture

    sequenceDiagram participant B as Browser participant R as DNS resolver participant E as CDN edge participant L as Load balancer participant A as App server participant C as Cache participant D as Database B->>R: Where is shop.example.com R-->>B: IP address of the edge B->>E: TCP handshake then TLS handshake B->>E: GET /checkout E->>L: Cache miss so forward to origin L->>A: Pick a healthy instance A->>C: Look up cart C-->>A: Miss A->>D: Query cart rows D-->>A: Rows A->>C: Store result A-->>L: Response L-->>E: Response E-->>B: Response

    How to read it: time runs downward. Everything above the GET is setup cost. Everything between the edge and the database is work only the first request pays if the cache and CDN are doing their job.

    Step 1: DNS, the phone book

    DNS (Domain Name System) translates a name into an IP address. Your browser asks a recursive resolver, usually run by your internet provider or a public DNS service. If it does not already know the answer, it works down a hierarchy: a root server says who handles .com, the .com servers say who is responsible for example.com, and that domain's authoritative server gives the final record.

    Every answer carries a TTL (time to live): how many seconds it may be cached, at the browser, the operating system and the resolver. Most lookups therefore never walk the hierarchy. A cold lookup may cost tens of milliseconds, a cached one almost nothing.

    The TTL is a design lever. A long TTL (hours) reduces lookups and survives short DNS outages but makes changes slow to spread. A short TTL (a minute) lets you move traffic quickly in a failover but increases lookups. Many teams lower the TTL before a planned migration, then raise it again.

    NOTE

    DNS is also a basic traffic-steering tool. An answer can differ depending on where the asker is, pointing users to a nearby data centre or edge. We return to this in the load-balancing and multi-region lessons.

    Step 2: TCP, a reliable connection

    Most web traffic runs over TCP (Transmission Control Protocol), which gives an ordered, reliable stream of bytes on top of an unreliable network. Before data flows the two sides perform a three-way handshake: the client sends a SYN, the server answers SYN-ACK, the client replies ACK. That costs one round trip before the client can send data. TCP also resends lost packets and slows down under congestion. The price is waiting: if one packet is lost, later data on that connection waits for the missing piece. Remember that for HTTP/3.

    Step 3: TLS, making it private

    TLS (Transport Layer Security) encrypts the connection and lets the browser verify, through a certificate, that it is really talking to shop.example.com. It is the "S" in HTTPS. With TLS 1.3 the handshake needs about one extra round trip; older TLS 1.2 needs about two; resuming a recent session can be quicker still.

    So on a brand-new connection, before the first request, the client has paid roughly a DNS lookup, one RTT for TCP and one for TLS 1.3. Opening a fresh connection per request would be very costly. The next section shows how connections are kept.

    stateDiagram-v2 [*] --> Lookup Lookup --> Connecting: DNS answered Connecting --> Secure: TCP and TLS done Secure --> Active: Request sent Active --> Idle: Response complete Idle --> Active: Reused via keep-alive Idle --> Closed: Idle timeout Closed --> [*]

    How to read it: the cost sits in the first three states. A connection that loops between Active and Idle pays that cost once. One that goes to Closed after every response pays it every time.

    Step 4: HTTP, asking for the page

    HTTP is the language of the request. A request has a method (GET), a path (/checkout), headers (accepted languages, cookies) and sometimes a body. The response has a status code (200 OK), headers and a body.

    Version Key idea Strength Weakness
    HTTP/1.1 One request at a time per connection; connections can be kept alive and reused Simple and universal A slow response blocks those behind it; browsers open several connections to compensate
    HTTP/2 Many requests share one connection at once (multiplexing); headers are compressed Far fewer connections, faster pages with many assets Still on TCP, so one lost packet stalls every stream
    HTTP/3 Runs over QUIC (built on UDP); streams are independent; transport and encryption are set up together A lost packet delays only its own stream; faster setup; handles network changes such as wifi to mobile Newer; some networks block UDP, so clients fall back to HTTP/2

    In everyday terms: HTTP/1.1 is a single-lane road, HTTP/2 a multi-lane road with one shared gate, and HTTP/3 gives each lane its own gate.

    Keep-alive means the connection stays open after a response so the next request skips DNS, TCP and TLS. It is a quiet but huge win, and the same idea applies between servers: an application keeps a pool of open connections to its database, because opening one per request is slow (see Databases Basics). Set sensible idle timeouts so a half-dead connection does not linger.

    Step 5: edge, load balancer, application

    CDN edge. If the URL points to something cacheable (an image, a script, perhaps a public page), the nearest edge server answers immediately without touching your servers, which is the cheapest and fastest outcome. A personalised page usually passes through to the origin (your own servers behind the CDN).

    Load balancer. It chooses one of several application instances, skipping any that fail health checks. See Load Balancing. It often terminates TLS, meaning it decrypts traffic so the instances do not have to.

    Application. The instance authenticates the caller, validates the request and builds the answer. It checks the cache first (typically around a millisecond on a hit), otherwise queries the database, stores the result and returns. Slow work, such as sending an email, goes on a queue so the response is immediate.

    Response. It travels back the same way. Headers such as Cache-Control tell the browser and CDN how long each piece may be reused.

    Where the time goes

    Here is a rough timeline for a cold visit by a user far from the server. Every number is an illustrative assumption: 80 ms round trip to the origin, no CDN in the path.

    Phase Cost Illustrative time
    DNS lookup (uncached) resolver lookup 25 ms
    TCP handshake 1 RTT 80 ms
    TLS 1.3 handshake 1 RTT 80 ms
    HTTP request and response (network) 1 RTT 80 ms
    Server work (cache hit or database query) n/a 5 to 30 ms
    Total, first request about 270 to 300 ms

    A warm visit, with DNS cached and the connection reused, skips the first three rows and takes roughly 85 to 110 ms. Put the same content on a CDN edge 10 ms away and each round trip costs 10 ms instead of 80. In this example the server's own work is the smallest piece. That is typical: for distant users, network round trips often dominate, not your code. It is also why ten sequential browser calls, where one would do, feel slow.

    TIP

    Before optimising, measure. Browser developer tools show the timing of every phase (DNS, connect, TLS, waiting, download). Fix the biggest slice first.

    Stateless versus stateful servers

    A stateful server remembers things about earlier requests in its own memory, such as "this user is logged in". A stateless server keeps nothing between requests: everything it needs arrives with the request or lives in a shared store.

    Why it matters: with ten instances behind a load balancer, if instance 3 holds your login in memory and the next request goes to instance 7, you appear logged out. With stateless servers any instance can handle any request, so you can add, remove or replace instances freely.

    Approach How it works Benefit Cost
    Stateful server Session data in server memory Simple for one server Breaks when scaled out or restarted; forces sticky routing
    Stateless with shared store Session data in Redis or a database Easy to scale the app tier; instant revocation An extra lookup per request; the store must be reliable
    Stateless with tokens Identity carried in a signed token No lookup on most requests Harder to revoke before expiry

    HTTP has no memory, so sessions are built on top. A cookie is a small value the server asks the browser to store and send back. A session is the server's record of who you are: the cookie holds a random ID, and the server looks it up, so it can revoke it instantly. A token (such as a JSON Web Token, JWT) carries the claims itself, signed, so no lookup is needed, but you cannot easily cancel it before expiry without a deny-list or short lifetimes. Mark cookies Secure, HttpOnly and set a sensible SameSite. The Security lesson covers tokens in depth.

    In practice: the checkout page is slow in one region only

    NOTE

    A realistic scenario, not a case history. This is a composite example built from common production patterns. It does not describe any specific company, and every number in it is an illustrative assumption.

    The situation

    An online retailer's checkout page feels fine in the home region and slow in one distant region. Support reports "checkout takes forever" from that region, and the dashboard shows the checkout conversion rate lower there. Assume the page is interactive in about 2 seconds for most users and about 4 seconds in the distant region, which is more than the extra distance alone should cost. Three engineers own the web tier. The stack: managed DNS, a CDN, Nginx ingress on Kubernetes in a single origin region, PostgreSQL, and Redis for sessions. Assume the round trip from the distant region to the origin is about 220 ms.

    Starting architecture

    Checkout page, starting architectureShopper to Managed DNS; Shopper to CDN edge; CDN edge to Nginx ingress (miss); Nginx ingress to App pods; App pods to Redis; App pods to PostgreSQLSINGLE ORIGIN REGIONShopper: distant regionShopperdistant regionManaged DNSManaged DNSCDN edge: nearby, all missCDN edgenearby, all missNginx ingress: originNginx ingressoriginApp podsApp podsRedis: sessionsRedissessionsPostgreSQLPostgreSQLmiss

    How to read it: the edge is close to the shopper, but every request is a miss and travels the long way to the single origin.

    Options considered

    The team first needs to find out which hand-off is slow. This decision flow is the diagnosis they use.

    flowchart TD S["One region is slow"] --> Q1{"Is DNS lookup time high from that region?"} Q1 -->|yes| F1["Check resolver and GeoDNS answers and TTL"] Q1 -->|no| Q2{"Is connect plus TLS time high?"} Q2 -->|yes| F2["Check edge location, TLS version and certificate chain"] Q2 -->|no| Q3{"Does the CDN report a cache MISS?"} Q3 -->|yes| F3["Check Cache-Control, Vary and Set-Cookie headers"] Q3 -->|no| Q4{"Is time to first byte high on a HIT?"} Q4 -->|yes| F4["Check edge to origin path and origin time"] Q4 -->|no| F5["Look at the browser, JavaScript and payload size"]

    How to read it: a few curl timing variables (time_namelookup, time_connect, time_appconnect, time_starttransfer), run from a probe in the region, answer the first two questions. The CDN's cache-status response header answers the third.

    Option What it fixes What it costs Risk
    Do nothing, or add origin pods Nothing for a network-bound problem Cheap More pods near the origin do not shorten a 220 ms round trip
    Make static assets cacheable at the edge and keep the HTML dynamic Removes most origin round trips for distant users Header and build changes, a few days Stale assets if versioning is wrong
    Add a second origin region in the distant geography Shortens every dynamic call A second region of app, Redis and a database replica; a large cost and a data-residency question Complexity far beyond a header bug

    The probes show DNS and TLS are fine. The cache status is MISS for the JavaScript and CSS, because the framework adds Set-Cookie and Vary: Cookie to static files. Every asset crosses the world, and assets that depend on one another load in sequence.

    The decision

    Field Record
    Context Static files marked uncacheable by accident. Distant users pay about 220 ms per sequential origin call.
    Decision Serve fingerprinted assets (for example app.3f9c.js) with Cache-Control: public, max-age=31536000, immutable, strip cookies from them, and keep the HTML dynamic (no edge caching, or only a few seconds). Enable origin keep-alive tuning so the CDN reuses connections.
    Consequences Good: cached assets cost one short round trip to the edge. Bad: the deploy process must upload new assets before switching HTML, and old assets must be kept for a while.
    Revisit when Dynamic API calls from the distant region are still the largest slice after the fix, which would justify a regional origin.

    The saving, illustratively. Before, a chain of dependent calls: HTML, then CSS, then the JS bundle, then a lazy-loaded chunk, then the cart API, then the payment-config call, each about 280 ms (220 ms round trip plus about 60 ms of work), roughly 1.7 seconds of waiting on origin round trips. After: the CSS, bundle and chunk come from the edge at about 15 ms each, so the chain is roughly 280 + 15 + 15 + 15 + 280 + 280, close to 885 ms, a saving of about 0.8 seconds, and warm repeat visits skip even more.

    Rollout and verification

    flowchart LR P["Probe from the region before"] --> C["Change headers for one asset path"] C --> W["Watch cache hit ratio and TTFB"] W --> R["Roll to all assets"] R --> V["Probe again and compare"]

    Change one asset path first, then all of them. Watch the CDN cache hit ratio by region, time to first byte by region (from real-user measurement or synthetic probes in that region), the origin request rate (it should fall) and checkout conversion by region. The target, not a promise: asset cache hit ratio above 95% in the region and the page interactive within about 3.2 seconds there (down from about 4).

    The 2 a.m. failure

    During the 02:00 release window the checkout page goes blank for some users. The page says "checkout asset 404 rate above 5%". The cause: the deploy deleted last release's assets, but the edge still has the previous HTML cached for a few minutes, and that HTML points at the deleted files.

    sequenceDiagram participant B as Browser participant E as CDN edge participant O as Origin B->>E: GET checkout page E-->>B: Cached HTML naming app.OLD.js B->>E: GET app.OLD.js E->>O: Cache miss so ask origin O-->>E: 404 deleted by the deploy E-->>B: 404 and a blank page

    First three checks: curl -sI https://shop.example.com/assets/app.OLD.js for status and cache status, the CDN log filtered to status 404 by path, and the Age header on the HTML to see how stale it is. Mitigation: purge the HTML cache or restore the previous assets from object storage. Follow-up: upload new assets before switching the HTML, keep the last two releases' assets, and give the HTML a very short edge TTL.

    Architect's notes

    • Measure by phase and by region before deciding. One curl timing breakdown from a probe in the affected region usually names the guilty hop in minutes.
    • Look for accidental uncacheability. Set-Cookie, Vary: Cookie and Cache-Control: no-store on static files are common and invisible from the home region.
    • Ask in the review: how many sequential round trips does this page need? The count times the RTT is the floor. Parallelise or remove calls.
    • Own the headers. Somebody must own cache headers and CDN rules, and releases must keep old assets alive.
    • Defer a second region. It fixes dynamic latency but multiplies cost, data and operations. Try caching and connection reuse first.

    Common mistakes

    • Ignoring distance. All servers in one region serving the world adds hundreds of milliseconds per round trip. Fix: a CDN and, when needed, regional deployments.
    • New connections for every call. Skipping reuse repeats DNS, TCP and TLS. Fix: keep-alive and connection pools.
    • Chatty clients. Many small sequential requests multiply round trips. Fix: batch, combine endpoints, or use HTTP/2.
    • Sessions in server memory while scaling out. Users get logged out at random. Fix: a shared store or tokens.
    • Forgetting DNS TTL in a migration. Some users stay on the old address. Fix: lower the TTL ahead of time.
    • No timeouts at any hop. One slow hop pins resources back to the user. Fix: explicit connect and read timeouts at each hop.
    • Assuming the network is reliable. Packets are lost and routes change. Fix: retries on idempotent operations (safe to repeat) and failure handling.

    Key takeaways

    • A request is a chain of hand-offs. DNS, TCP, TLS, HTTP, edge, load balancer, application, cache and database each add time and can fail.
    • Round trips are the unit of cost. Setup steps cost whole round trips, and distance multiplies them.
    • DNS caching is governed by TTL. Long TTLs reduce lookups but slow changes.
    • Reuse connections. Keep-alive and pools avoid repeating handshakes.
    • HTTP versions solve different blocking problems. HTTP/2 multiplexes on one TCP connection; HTTP/3 uses QUIC so a lost packet only slows its own stream.
    • For distant users the network dominates. CDNs and fewer round trips help most.
    • Stateless servers scale. Keep session state in a shared store or signed tokens.
    • Diagnose by phase. Timing breakdowns and cache-status headers localise a slow region fast.

    Practice exercises

    Exercise 1 — Starter (30 min): Open your browser's developer tools on any website, go to the Network tab, and reload with the cache disabled. For the main document request, write down the time spent in DNS, connecting, TLS, waiting and downloading. Which phase is largest? Then reload normally and note what changed.

    Exercise 2 — Intermediate (2 hours): Using the timeline table, assume the round trip to the origin is 120 ms and to a CDN edge is 15 ms. Calculate the total for a cold first request to the origin and for a cold request answered at the edge (assume DNS 25 ms, TCP and TLS one round trip each, one round trip for the request, and 20 ms of server work at the origin or 2 ms at the edge). Then calculate the warm-connection times. Write one paragraph on where to invest.

    Exercise 3 — Advanced (half day): Design the session handling for a checkout service so it survives a server restart and scales to twenty application instances. Compare server-side sessions in Redis with signed tokens against four criteria: per-request cost, ability to log a user out instantly, impact if the session store goes down, and complexity. Choose one, justify it, and describe what would make you change your mind.

    • Estimation - the latency numbers used here, and how to turn them into load.
    • API Design - the next lesson: designing the HTTP contract itself.
    • Load Balancing - a close look at step 5 and how traffic is spread.
    • CDN and Object Storage - how edge caching removes whole round trips.
    • Security - tokens, TLS and authentication in more depth.

    Enroll to keep reading

    Lesson 4 of 12 · System Design Foundations: From Zero to Your First Design

    Follow one web request from the URL bar to the response: DNS, TCP, TLS, HTTP versions, CDN, load balancer, app and database, plus where the time goes and how sessions work.

    In the rest of this lesson

    • Step 4: HTTP, asking for the page
    • Step 5: edge, load balancer, application
    • Where the time goes
    • Stateless versus stateful servers
    • In practice: the checkout page is slow in one region only
    • Architect's notes

    Enrolling is free. It unlocks every lesson in System Design Foundations: From Zero to Your First Design, tracks your progress across devices and keeps your quiz scores. The newsletter is optional.

    Ask about this article

    Get answers grounded in this post. AI-generated — based on this article, and may be imperfect.

    Scaled AI Weekly

    Enjoyed this? Get more like it every Monday.

    Real architecture decisions, LLMOps patterns that survive production, and engineering leadership advice — from 12+ years of building at enterprise scale. Free. No spam. Unsubscribe anytime.

    Get new articles by email

    Free. We email a confirmation link first, and you can unsubscribe from any email.

    Join engineers building production AI systems

    Comments