TL;DR

1. The problem: why should a system designer care about protocols?

When you tap the Instagram icon in Mumbai, the app must fetch your feed from servers that may be thousands of kilometres away. That one tap turns into a DNS lookup, a TCP connection, a TLS handshake, an HTTP request, and then dozens of image downloads β€” each a conversation made of packets bouncing across undersea cables, routers, carrier networks and load balancers.

System design decisions that look "high level" are really networking decisions in disguise:

You don't need to be a network engineer to design systems, but you do need a solid mental model of what a request costs. This lesson gives you that model and the vocabulary interviewers expect.

🧠 Analogy Sending a request is like mailing a letter through a very bureaucratic postal system. You write the letter (HTTP), lock it in a tamper-proof box only the recipient can open (TLS), hand it to a courier service that numbers every page, confirms delivery and resends lost pages (TCP), who puts it in an envelope with the destination building's street address (IP) and the apartment number (port), and the envelope then travels truck by truck (links) through sorting centres (routers). Before the first letter, the courier insists on a phone call to agree on terms (handshake) β€” and if the recipient lives overseas, every call takes a long time.

2. Layers: the simplified OSI and TCP/IP models

Networking is organised in layers. Each layer solves one problem and relies on the layer below, so HTTP doesn't need to know whether it's travelling over Wi-Fi or 5G. The academic OSI model has 7 layers; the practical TCP/IP model used on the internet collapses them into 4–5. You'll hear engineers say "L4" and "L7" constantly β€” those numbers come from OSI.

OSI layerTCP/IP layerJobExamplesUnit / addressing
L7 Application
(L6 Presentation, L5 Session folded in)
ApplicationWhat the program means: requests, responses, encryption and encodingHTTP, gRPC, DNS, WebSocket, TLS*Messages; URLs, hostnames
L4 TransportTransportProcess-to-process delivery, reliability, ordering, congestion controlTCP, UDP, QUIC (over UDP)Segments / datagrams; ports
L3 NetworkInternetHost-to-host delivery across many networks; routingIPv4, IPv6, ICMP, BGP (routing protocol)Packets; IP addresses
L2 Data linkLinkDelivery to the next hop on the same local networkEthernet, Wi-Fi (802.11), LTE/5G radioFrames; MAC addresses
L1 PhysicalBits as light, electricity or radio wavesFibre, copper, radioBits

*TLS sits between transport and application; people variously call it L5/L6 or "part of L7". In QUIC it is built into the transport itself.

Why it matters for design: an L4 load balancer sees only IPs and ports (fast, protocol-agnostic), while an L7 load balancer parses HTTP and can route by URL path, header or cookie (smarter, more expensive). See Load balancing.

2.1 Encapsulation

As data goes down the stack, each layer wraps it with its own header β€” like nested envelopes. The receiver unwraps them in reverse order.

L2 Link frame β€” Wi-Fi / Ethernet / LTE header (next-hop MAC) L3 IP packet β€” header: source IP 49.36.x.x β†’ destination IP 157.240.x.x, TTL L4 TCP segment β€” header: ports 51234 β†’ 443, sequence no., ACK no., window TLS record β€” encrypted + authenticated (AES-GCM / ChaCha20) L7 HTTP: GET /api/v1/feed/timeline/ Host: i.instagram.com Authorization: Bearer … Accept-Encoding: gzip (body: none)
Encapsulation: the HTTP request is encrypted by TLS, numbered by TCP, addressed by IP and finally framed for the physical link. Each router only looks at the IP header; only the destination (or a proxy that terminates TLS) can read the HTTP.

3. IP addresses, ports and NAT

3.1 IP addresses

An IP address identifies a network interface on the internet, like a building's street address. IPv4 addresses are 32 bits, written as four numbers (157.240.22.174) β€” about 4.3 billion total, which ran out long ago. IPv6 addresses are 128 bits (2a03:2880:f12f:83:face:b00c:0:25de β€” yes, Meta embeds "face:b00c" in some of its IPv6 addresses), enough for every device many times over. Large mobile carriers increasingly run IPv6-first networks, and big services serve both.

Some IPv4 ranges are private (10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16): usable inside a home, office or data center but not routable on the public internet. The /8 notation (CIDR) says how many leading bits are the network prefix β€” /8 means the first 8 bits are fixed, leaving 24 bits (16.7M addresses) for hosts.

Routers forward packets based on the destination address using routing tables. Between organisations (called autonomous systems), routes are exchanged with BGP (Border Gateway Protocol): each network announces "I can reach these address prefixes". If a network stops announcing its prefixes, the rest of the internet literally forgets how to reach it β€” which is exactly what happened in Facebook's October 2021 outage (see DNS).

3.2 Ports

One machine runs many programs, so an IP address alone isn't enough. A port (a 16-bit number, 0–65535) identifies the program/socket β€” the apartment number in the building. Well-known server ports: 443 HTTPS (and HTTP/3 over UDP 443), 80 HTTP, 53 DNS, 22 SSH, 5432 PostgreSQL, 6379 Redis, 9092 Kafka. Clients use a random ephemeral port (e.g. 51234) for each outgoing connection.

A TCP connection is uniquely identified by its 5-tuple: (protocol, source IP, source port, destination IP, destination port). Load balancers hash this tuple to keep all packets of one connection on the same backend.

3.3 NAT (Network Address Translation)

Because IPv4 addresses are scarce, your home router gives devices private addresses (192.168.1.23) and translates them to its single public address on the way out, remembering the mapping in a table so replies can be sent back to the right device. Mobile carriers do the same at enormous scale β€” carrier-grade NAT (CGNAT) β€” so thousands of phones may share one public IPv4 address.

 Phone 10.20.3.7:51234 ──┐                         β”Œβ”€β”€> 157.240.x.x:443 (Instagram edge)
 Phone 10.20.9.1:40001 ──┼─> Carrier NAT 49.36.1.5 ──   sees both as 49.36.1.5 (ports 61001, 61002)
 Phone 10.20.4.4:33333 β”€β”€β”˜   table:                 └──> ...
                             10.20.3.7:51234 ⇄ 49.36.1.5:61001
                             10.20.9.1:40001 ⇄ 49.36.1.5:61002   (entries expire when idle!)

Design consequences:

4. TCP vs UDP

The transport layer offers two classic choices:

TCPUDP
ConnectionConnection-oriented (handshake first)Connectionless β€” just send
ReliabilityGuaranteed delivery via ACKs and retransmissionBest effort; packets may be lost
OrderingStrictly in orderNone β€” may arrive out of order or duplicated
Congestion / flow controlBuilt inNone (app must be polite itself)
Header size20–60 bytes8 bytes
Setup latency1 RTT before data0 RTT
Head-of-line blockingYes β€” one lost packet stalls everything behind itNo (each datagram independent)
Typical usesHTTP/1.1 & HTTP/2, databases, Kafka, SSH, emailDNS queries, VoIP/video calls, gaming, QUIC/HTTP/3

Rule of thumb: if losing or reordering data is unacceptable and you don't want to build reliability yourself, use TCP. If timeliness beats completeness (a video call would rather skip a late frame than wait), or you want to implement a smarter transport in user space (QUIC), use UDP.

5. How TCP works

5.1 The three-way handshake

Before any data flows, client and server agree to talk and exchange starting sequence numbers (counters used to number every byte so the receiver can reorder and detect gaps):

 Client (phone)                                         Server (edge LB)
     |  SYN  seq=x            "I want to talk; my bytes start at x"   |
     |----------------------------------------------------------->  |
     |  SYN-ACK  seq=y, ack=x+1   "OK; mine start at y; got your x"   |
     |  <----------------------------------------------------------- |
     |  ACK  ack=y+1   (can already carry the first request bytes)    |
     |----------------------------------------------------------->  |
     |<================= 1 full RTT before the request goes ========>|

The client can send data together with the final ACK, so the handshake costs exactly one round trip before the request leaves. Closing a connection uses a FIN/ACK exchange; an abrupt close uses a RST packet. (TCP Fast Open can send data in the SYN on repeat connections, but middlebox problems limited its adoption β€” one of the motivations for QUIC.)

5.2 Reliability: sequence numbers, ACKs and retransmission

5.3 Congestion control: the intuition

The network itself has limited capacity. If every sender blasted at full speed, router queues would overflow and everyone's packets would be dropped (congestion collapse). TCP therefore keeps a congestion window (cwnd) β€” how many unacknowledged bytes it may have "in flight":

  1. Slow start: a new connection starts small β€” typically 10 segments (β‰ˆ14 KB) β€” and doubles cwnd every RTT while ACKs keep coming back: 14 KB β†’ 28 β†’ 56 β†’ 112…
  2. Congestion avoidance: after a threshold, grow more gently (roughly +1 segment per RTT).
  3. On loss: assume congestion and cut cwnd (classic algorithms halve it β€” "additive increase, multiplicative decrease", AIMD). Modern Linux defaults to CUBIC; Google's BBR instead estimates bottleneck bandwidth and RTT directly and copes better with random (non-congestion) loss common on wireless links.

The consequence for designers: a new connection is slow even on a fat pipe. Downloading a 100 KB feed response on a fresh connection needs several RTTs of slow start (14 + 28 + 56 = 98 KB after 3 RTTs). On a reused, "warm" connection whose cwnd has already grown, the same response may arrive in one RTT. That's another reason to reuse connections and to place servers close to users.

bytes delivered after k RTTs of slow start β‰ˆ initcwnd Γ— (2^k βˆ’ 1)
initcwnd = 14 KB:  k=1 β†’ 14 KB, k=2 β†’ 42 KB, k=3 β†’ 98 KB, k=4 β†’ 210 KB
β†’ a 200 KB image on a brand-new connection needs ~4 RTTs of transfer time.
   Mumbai ⇄ local PoP (20 ms RTT): ~80 ms.  Mumbai ⇄ US (220 ms RTT): ~880 ms.

6. TLS: encryption and its handshake cost

TLS (Transport Layer Security) β€” the "S" in HTTPS β€” gives three guarantees: confidentiality (nobody on the path can read the data), integrity (nobody can modify it undetected) and authentication (you're really talking to instagram.com, not an impostor on the cafΓ© Wi-Fi).

6.1 The building blocks

6.2 TLS 1.2 vs TLS 1.3 handshakes

 TLS 1.2 (after TCP handshake)                    TLS 1.3 (after TCP handshake)
 Client                     Server                Client                     Server
   | ClientHello -------------> |                   | ClientHello + key share -> |
   | <- ServerHello, Cert,       |                   | <- ServerHello + key share,|
   |    ServerKeyExchange, Done  |   RTT 1           |    Cert, Finished          |  RTT 1
   | ClientKeyExchange,          |                   | Finished + HTTP request -> |
   | ChangeCipherSpec, Finished->|                   | <------- HTTP response ---- |  RTT 2
   | <- ChangeCipherSpec,Finished|   RTT 2           |
   | HTTP request -------------->|                   |  Resumed with PSK + 0-RTT:
   | <------------ HTTP response |   RTT 3           |  ClientHello + early data (request) ->
                                                     |  <- response               |  RTT 1 (total)
SetupHandshake RTTs before requestCold request total (incl. request RTT)Notes
TCP + TLS 1.21 (TCP) + 2 (TLS) = 34 RTTLegacy; still common on old devices
TCP + TLS 1.2 with session resumption1 + 1 = 23 RTTSession IDs / tickets skip the certificate step
TCP + TLS 1.31 + 1 = 23 RTTKey share sent in the first message
TCP + TLS 1.3 0-RTT1 + 0 = 12 RTTRequest rides with ClientHello on resumption
QUIC (HTTP/3), first visit1 (transport + crypto combined)2 RTTTLS 1.3 built into QUIC
QUIC 0-RTT resumption01 RTTRequest in the very first packet
⚠️ 0-RTT and replay attacks 0-RTT "early data" is sent before the handshake proves the client is live, so an attacker who records it can replay it. Servers should only accept 0-RTT for idempotent, safe requests (e.g. GET feed), never for "post this comment" or "transfer money". This is another place where idempotency (see API design) matters.

Where TLS ends is a design decision. Instagram-style systems terminate TLS at the edge β€” the CDN PoP or the edge load balancer β€” close to the user, so the expensive handshake round trips are short. Traffic from the edge to the data center travels over long-lived, pre-warmed, re-encrypted connections. Inside the data center, service-to-service calls are increasingly encrypted too (mutual TLS) β€” see Security.

7. HTTP: the language of the web and of APIs

HTTP (HyperText Transfer Protocol) is a request/response protocol: the client sends a request, the server sends exactly one response. Every Instagram API call β€” load feed, like, follow, get an upload URL β€” is an HTTP request (REST/GraphQL-style, see API design), and every image download from the CDN is an HTTP GET.

7.1 Anatomy of a request and response

POST /api/v1/media/3141592653/like/ HTTP/1.1         ← request line: METHOD  PATH  VERSION
Host: i.instagram.com                                ← headers: metadata about the request
User-Agent: Instagram 300.0.0.0 Android (33/13; …)
Authorization: Bearer eyJhbGciOi…                    ← who you are (see Authentication lesson)
Content-Type: application/json
Content-Length: 46
Idempotency-Key: 7f3e2a10-…                          ← makes retries safe
Accept-Encoding: gzip, br
                                                     ← blank line ends the headers
{"container_module":"feed_timeline","radio":"wifi"}  ← body (optional)

HTTP/1.1 200 OK                                      ← status line: VERSION  CODE  REASON
Content-Type: application/json
Content-Encoding: gzip
Cache-Control: private, no-store                     ← personalised: never cache in shared caches
X-Request-Id: 9b1c…                                  ← for tracing (see Observability)

{"status":"ok","like_count":57,"has_liked":true}

Parts to know: the method (what to do), the path (which resource), headers (metadata β€” auth, content type, caching, compression), and the optional body. Responses carry a status code, headers and body. In HTTP/2 and HTTP/3 the same concepts exist, but the request line becomes "pseudo-headers" (:method, :path, :authority) in a compressed binary encoding.

7.2 Methods

MethodMeaningSafe? (no side effects)Idempotent? (repeat = same effect)Instagram example
GETRead a resourceβœ…βœ…Load feed page, fetch a profile, download an image
HEADLike GET but headers onlyβœ…βœ…Check whether a media object exists / its size
POSTCreate / perform an action❌❌ (unless you add an idempotency key)Create a post, add a comment
PUTCreate or replace at a known URLβŒβœ…Upload a chunk to a pre-signed URL; set "I like this"
PATCHPartially update❌Not necessarilyEdit bio or caption
DELETERemoveβŒβœ…Delete a comment, unfollow
OPTIONSAsk what's allowedβœ…βœ…Browser CORS pre-flight for the web app

Idempotency matters because networks fail: if a response is lost, the client doesn't know whether the server acted. Retrying an idempotent request is always safe; retrying a non-idempotent one needs an idempotency key the server deduplicates. See Resilience patterns.

7.3 Status codes

CodeMeaningWhen you'll see it in Instagram's designRetry?
200 OKSuccess with bodyFeed page returnedβ€”
201 CreatedResource createdNew post or comment createdβ€”
204 No ContentSuccess, no bodyUnfollow doneβ€”
206 Partial ContentRange of bytes returnedVideo player fetching byte ranges from the CDNβ€”
301 / 302 / 307 / 308Redirect (permanent / temporary)http:// β†’ https://; short linksFollow
304 Not ModifiedYour cached copy is still validETag revalidation by the app or CDNβ€”
400 Bad RequestMalformed requestMissing field, invalid JSON❌ fix the request
401 UnauthorizedNot authenticatedExpired access token β†’ refresh it, then retryAfter re-auth
403 ForbiddenAuthenticated but not allowedViewing a private account you don't follow; blocked user❌
404 Not FoundNo such resourceDeleted post❌
409 ConflictState conflictUsername already taken❌
413 Payload Too LargeBody too bigVideo exceeds upload size limit❌
429 Too Many RequestsRate limitedToo many follows/likes per hour (see Rate limiting)βœ… after Retry-After
500 Internal Server ErrorBug / unhandled failureService exceptionβœ… with backoff (if idempotent)
502 Bad GatewayProxy got a bad response from upstreamLB/gateway couldn't reach a healthy serviceβœ… with backoff
503 Service UnavailableOverloaded or downLoad shedding during a spikeβœ… with backoff
504 Gateway TimeoutUpstream didn't answer in timeFeed service exceeded the gateway's timeoutβœ… with backoff (if idempotent)

Memory aid: 2xx = success, 3xx = go elsewhere / use your cache, 4xx = you (the client) did something wrong, 5xx = we (the server) did.

8. HTTP/1.1: keep-alive and head-of-line blocking

HTTP/1.0 opened a new TCP connection for every request β€” a handshake (and later a TLS handshake) per image. HTTP/1.1 (1997) made connections persistent by default (keep-alive): after a response, the connection stays open for the next request, saving the handshake round trips and keeping TCP's congestion window warm.

But HTTP/1.1 is still one request at a time per connection: the response to request #1 must be fully received before #2's response can start. (HTTP pipelining tried to let clients send several requests without waiting, but responses still had to come back in order, and buggy proxies made it unusable β€” browsers disabled it.) If response #1 is slow β€” a big image or a slow database query β€” everything queued behind it waits. This is application-level head-of-line (HOL) blocking.

Workarounds became folklore:

All of these are hacks around a protocol limitation β€” and they actively hurt under HTTP/2.

9. HTTP/2: multiplexing over one connection

HTTP/2 (2015) keeps HTTP's semantics (methods, headers, status codes) but changes how they travel:

The remaining problem: HTTP/2 still runs over TCP, which delivers one ordered byte stream. If a single packet is lost, TCP holds back all later bytes β€” belonging to all streams β€” until the retransmission arrives. On a lossy mobile network, HTTP/2's one-connection design can actually suffer more than HTTP/1.1's six connections. This is transport-level head-of-line blocking, and it's what HTTP/3 fixes.

HTTP/1.1one conn, in order HTTP/2 over TCPmultiplexed, 1 TCP stream HTTP/3 over QUICindependent streams A1 A2 A3 B1 B2 B3 C1 C2 C3 A1 B1 C1 A2 B2 βœ– C2 A3 B2↻ C3 A1 B1 C1 A2 B2 βœ– C2 A3 B2↻ C3 B and C wait until allof A is delivered C2, A3 arrived but are helduntil B2 is resent (TCP HOL) C2, A3 delivered at once;only stream B waits for B2 time / packets on the wire β†’
Three requests A, B, C (e.g. three feed images). HTTP/1.1 serialises them; HTTP/2 interleaves them but one lost TCP packet (B2) stalls every stream; HTTP/3 over QUIC only stalls the stream that lost data.

10. HTTP/3 and QUIC: built for mobile

QUIC is a transport protocol originally developed at Google and standardised by the IETF in 2021 (RFC 9000); HTTP/3 is HTTP mapped onto QUIC. QUIC runs over UDP β€” not because it wants to be unreliable, but because UDP passes through existing routers, NATs and firewalls, letting QUIC implement its own reliable transport in user space instead of inside the OS kernel. That means it can evolve with an app update rather than waiting years for operating systems to change.

10.1 What QUIC changes

Costs: QUIC uses more CPU per byte than kernel TCP (encryption of every packet, user-space processing), some corporate networks block UDP 443 (so clients must fall back to TCP β€” typically racing both, "happy eyeballs" style, or remembering what worked), and L4 load balancers must route by connection ID rather than the 5-tuple to support migration.

HTTP/1.1HTTP/2HTTP/3
TransportTCPTCPQUIC over UDP
FormatTextBinary framesBinary frames
Concurrency per connection1 request at a timeMany multiplexed streamsMany independent streams
Head-of-line blockingHTTP-level and TCP-levelTCP-level onlyNone across streams
Header compressionNoneHPACKQPACK
New connection setup (with TLS)2–3 RTT2–3 RTT1 RTT (0 on resumption)
Survives network changeNoNoYes (connection migration)
Typical connections per host~611
πŸ“Έ Meta and QUIC Meta has publicly described moving the bulk of its app traffic β€” Facebook and Instagram API requests and media β€” to QUIC/HTTP/3, using its open-source QUIC implementation mvfst together with its open-source HTTP framework Proxygen at the edge. Its engineering posts reported meaningful reductions in request errors, tail latency and video stalls, with the biggest gains on the slowest, lossiest networks β€” precisely the mobile users in emerging markets that matter most for growth.

11. Latency math: what a request really costs

11.1 The physics

Light in optical fibre travels at about 200,000 km/s (two-thirds of its speed in vacuum). So:

one-way delay β‰ˆ 5 Β΅s per km   β†’   1 ms per 200 km
round trip (RTT) β‰ˆ 1 ms per 100 km of distance   (theoretical floor)

Mumbai β†’ US East (Virginia): ~13,000 km great-circle
  floor RTT = 2 Γ— 13,000 km / 200,000 km/s = 130 ms
  real cables detour (via Europe or Asia-Pacific), plus router hops and queues
  β†’ assume a measured RTT of ~220 ms

No amount of engineering beats the speed of light. You can only (1) reduce the number of round trips or (2) reduce the distance each round trip travels, by moving servers (or at least the connection endpoint) closer to the user.

11.2 Worked example: the first request from Mumbai to a US data center

Assume a user in Mumbai on a good fibre/Wi-Fi connection opens the app and fetches a 60 KB (compressed) feed response. Assume: the DNS answer is cached at a nearby ISP resolver (20 ms), RTT to the US data center is 220 ms, RTT to an Instagram edge PoP in Mumbai is 15 ms, the server takes 50 ms to build the response, and TCP's initial window is ~14 KB (so 60 KB needs the first window plus 2 more RTTs of slow start: 14 + 28 + 56 β‰₯ 60).

StepA: TCP + TLS 1.2, direct to USB: TCP + TLS 1.3, directC: QUIC (1-RTT), directD: QUIC 0-RTT resumption, directE: TLS 1.3 terminated at Mumbai edge, warm edge→US link
DNS lookup2020202020
TCP handshake220220220 (combined)015
TLS handshake440 (2 RTT)220 (1 RTT)15
Request β†’ response first bytes220 + 50220 + 50220 + 50220 + 5015 + 220 + 50
Rest of response (slow start: 2 more RTT)44044044044030 (2 × 15; edge→US link already warm)
Total (ms)β‰ˆ 1,390β‰ˆ 1,170β‰ˆ 950β‰ˆ 730β‰ˆ 365

Lessons from the numbers:

11.3 Latency vs bandwidth

Bandwidth is how wide the pipe is; latency is how long it is. For the small requests that dominate API traffic (a few KB), latency dominates: doubling bandwidth from 50 to 100 Mbps changes almost nothing for a 5 KB request, while halving the RTT nearly halves its time. For big transfers (a 50 MB video upload), bandwidth dominates. The bandwidth-delay product (bandwidth Γ— RTT) tells you how many bytes must be in flight to fill the pipe: 100 Mbps Γ— 0.22 s β‰ˆ 2.75 MB β€” far more than a fresh connection's 14 KB window, which is why long-distance transfers take many RTTs to reach full speed.

12. Forward proxies vs reverse proxies

A proxy is an intermediary that receives a request and makes it again on someone's behalf. The key question is: on whose behalf?

client's side (e.g. company network) πŸ’» Office laptops known, trusted clients Forward proxy acts for the clients 🌐 Any website sees only the proxy's IP server's side (e.g. Instagram's network) πŸ“± Any client anyone on the internet Reverse proxy LB Β· API gateway Β· CDN App servers hidden, private IPs
Same mechanics, opposite loyalties: a forward proxy hides and controls clients; a reverse proxy hides and protects servers.
Forward proxyReverse proxy
Acts on behalf ofClientsServers
Who configures itThe client side (browser/OS settings, corporate network)The service owner (DNS points at it)
Client knows it's there?Usually yesNo β€” it looks like the real server
Typical usesCorporate filtering and logging, caching for an office, anonymity/VPN-like egress, bypassing geo-restrictionsLoad balancing, TLS termination, caching, compression, auth, rate limiting, DDoS protection, routing to microservices
ExamplesSquid, corporate secure web gatewaysNGINX, HAProxy, Envoy, Proxygen, CDNs, AWS ALB, API gateways

In Instagram's diagram, every box between the client and the services is a reverse proxy: the CDN edge, the load balancer and the API gateway. Each terminates a connection from the previous hop and opens (or reuses) one to the next. A practical consequence: the backend sees the proxy's IP, not the user's, so proxies add headers like X-Forwarded-For (or the standard Forwarded) carrying the original client IP β€” needed for rate limiting, abuse detection and geo features. Only trust those headers when set by your own proxies.

Forward proxies matter to Instagram mainly as a fact of life: users behind corporate proxies and middleboxes, which may block UDP (forcing a QUIC β†’ TCP fallback) or interfere with long-lived connections.

13. Real-time on the web: long polling, SSE and WebSockets

HTTP's request/response model has a limitation: the server can only answer, never speak first. Features like DMs, typing indicators, live comments and "new posts" banners need the server to push data when something happens. Three techniques build that on top of HTTP-era infrastructure:

GET /chat HTTP/1.1
Host: edge-chat.instagram.example
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Key: dGhlIHNhbXBsZSBub25jZQ==
Sec-WebSocket-Version: 13

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: Upgrade
Sec-WebSocket-Accept: s3pPLMBiTxaQ9kYGzzhZRbK+xOo=
… from here on: binary/text frames in both directions …
Short pollingLong pollingSSEWebSocket
DirectionClient pullsClient pulls, server delays answerServer β†’ clientBoth ways
LatencyUp to the poll intervalNear real-timeReal-timeReal-time
Overhead per messageFull HTTP request, mostly emptyFull HTTP requestSmallVery small (2–14 byte frame header)
Server costMany wasted requestsOne held request per clientOne open connection per clientOne open connection per client
Good forRare updates, prototypesFallback when sockets are blockedLive counters, feeds, notifications on webChat, typing indicators, presence, games

Persistent connections shift the scaling problem: instead of many short requests, servers must hold millions of mostly idle connections, send heartbeats to keep NAT mappings alive, and route a message to whichever server holds the recipient's connection. That's the core of Direct messaging; protocol selection is compared in API design, and load-balancing long-lived connections is covered in Load balancing. On mobile, Meta has publicly described using MQTT β€” a lightweight publish/subscribe protocol designed for unreliable networks β€” over persistent connections for its messaging features.

14. How Instagram uses all of this

Put the pieces together for one feed load and one image, following the arrows of the main diagram:

πŸ“± AppMumbai, 4G
β†’UDP 443 (QUIC)
Edge PoPL4 LB + Proxygen, TLS ends
β†’warm, encrypted backbone
DC load balancerL4 β†’ L7
β†’HTTP/2 or gRPC
API Gateway β†’ FeedJSON with media URLs
  1. DNS resolves the API hostname to a nearby edge PoP's (often anycast) address β€” see DNS.
  2. The app opens one QUIC connection (falling back to TCP + TLS 1.3 if UDP is blocked) and keeps it alive for the whole session; all API calls are multiplexed over it.
  3. The edge PoP terminates QUIC/TLS a few milliseconds from the user, then forwards the request over long-lived connections on Meta's private backbone to a data center region β€” so only one long round trip is paid per request.
  4. Inside the data center, the load balancer tiers and the API gateway route to the Feed service; internal calls use HTTP/2-based RPC with pooled connections.
  5. The JSON response contains CDN URLs; the app fetches images and video segments over a separate, also-reused connection to the CDN hostname β€” usually served straight from the PoP's cache. See CDN.
  6. For DMs and live updates, the app keeps a separate persistent connection (MQTT-style) with periodic heartbeats; in the background, notifications arrive through APNs/FCM.
πŸ“Έ Instagram specifics (public information)

Rough numbers

Assume 500M DAU Γ— 50 API requests/day = 25 billion requests/day β‰ˆ 290K QPS average (~600K peak)
If each request opened a NEW connection with TCP + TLS 1.2 (3 extra RTTs at ~100 ms average RTT):
   wasted user time = 25B Γ— 300 ms β‰ˆ 7.5 billion seconds/day β‰ˆ 240 user-years per day
   plus ~290K TLS handshakes/s of server CPU
With one long-lived QUIC connection per session (~10 sessions/user/day):
   handshakes drop to 5B/day β‰ˆ 58K/s, most of them 0-RTT resumptions.

15. Trade-offs & common pitfalls

βœ… Modern choices (HTTP/2–3, TLS 1.3, edge termination)

  • Far fewer round trips per request
  • One connection per host; less handshake CPU
  • Better behaviour on lossy, changing mobile networks (QUIC)
  • Header compression saves uplink bytes
  • Encryption everywhere without a big latency penalty

⚠️ Costs and caveats

  • QUIC costs more CPU per byte and some networks block UDP β†’ need TCP fallback
  • 0-RTT data is replayable β†’ only for idempotent requests
  • One multiplexed TCP connection suffers badly from packet loss (HTTP/2)
  • Long-lived connections complicate load balancing and deploys
  • Edge PoPs and backbones are expensive to build and operate

Common pitfalls

16. Real-world technologies

TechnologyWhat it isWhen you'd use / meet it
NGINX, HAProxy, EnvoyReverse proxies / L7 load balancers supporting HTTP/1.1, HTTP/2 (and HTTP/3 in newer versions)Edge and service proxies, TLS termination
Proxygen (Meta), mvfst (Meta)Meta's open-source HTTP library/proxy and QUIC implementationMeta's edge and apps; reference for large-scale HTTP/3
quiche (Cloudflare), MsQuic (Microsoft), Cronet (Chromium)Other QUIC/HTTP/3 implementations; Cronet brings Chrome's network stack to Android/iOS appsAdding HTTP/3 to servers or mobile apps
OpenSSL, BoringSSL, rustlsTLS librariesAnything that terminates or originates TLS
Let's Encrypt / ACME, cloud certificate managersAutomated certificate issuance and renewalAvoiding expired-certificate outages
gRPC (over HTTP/2)RPC framework with Protobuf, streaming, deadlinesService-to-service calls inside the data center
Socket.IO, MQTT brokers, WebSocket gatewaysReal-time persistent connection frameworksChat, presence, live updates
curl, Wireshark, tcpdump, Chrome DevTools, mtrDebugging tools: inspect requests, packets, timing and routesDiagnosing latency, handshake and protocol issues

17. Interview corner

Walk me through what happens when the Instagram app requests the feed.

The app resolves the API hostname via DNS (likely cached; otherwise the recursive resolver walks root β†’ TLD β†’ authoritative and returns a nearby edge IP). It opens a connection β€” ideally reusing an existing one; otherwise a QUIC 1-RTT handshake (or TCP SYN/SYN-ACK/ACK plus a TLS 1.3 handshake) with the nearest edge PoP, which presents a certificate for the hostname. It sends an HTTP GET with an auth token. The edge terminates TLS and forwards the request over a warm backbone connection to a data center, through L4 and L7 load balancers to the API gateway, which authenticates, rate-limits and routes to the Feed service. The JSON response flows back with CDN URLs for media, which the app then fetches from the CDN over another reused connection.

TCP or UDP for a new real-time video-call feature? For DMs?

Video calls: UDP-based (RTP/WebRTC or QUIC datagrams) β€” a late frame is useless, so you'd rather drop it than stall everything waiting for a retransmission; the app handles loss with codecs and FEC. DMs: every message must arrive, in order, exactly once from the user's perspective, so a reliable transport β€” TCP (WebSocket/MQTT) or QUIC streams β€” plus app-level acknowledgements and IDs for deduplication.

What is head-of-line blocking, and how do HTTP/2 and HTTP/3 address it?

HOL blocking is when one slow or lost item delays everything queued behind it. HTTP/1.1 has it at the application level (one response at a time per connection). HTTP/2 multiplexes streams, fixing the HTTP-level problem, but TCP still delivers one ordered byte stream, so a single lost packet stalls all streams. HTTP/3 runs streams over QUIC, which handles ordering per stream; a lost packet only delays the stream it belonged to.

Why is QUIC especially good for mobile apps like Instagram?

Four reasons: (1) fewer round trips β€” 1-RTT setup and 0-RTT resumption, which matters on high-RTT mobile links; (2) no transport HOL blocking, which matters on lossy radio links; (3) connection migration via connection IDs, so switching Wi-Fi ⇄ cellular doesn't kill in-flight requests and video; (4) it lives in user space, so the app and server can ship improved congestion control and loss recovery without waiting for OS updates. Costs: more CPU and the need for a TCP fallback when UDP is blocked.

A user in India sees 1.5 s feed loads while server-side latency is 60 ms. Explain and fix.

The gap is network round trips: DNS, TCP, TLS (2 RTT on TLS 1.2), the request, and slow start for the response — each ~220 ms to a US data center. Fixes: terminate connections at an Indian edge PoP so handshakes happen over ~15 ms; keep warm edge→DC connections; upgrade to TLS 1.3 and QUIC with 0-RTT resumption; reuse one connection per session and pre-connect at launch; reduce response size and the number of sequential calls; eventually serve data from a closer region. The worked example in this lesson shows a drop from ~1,390 ms to ~365 ms just from edge termination and modern protocols.

What's the difference between a forward and a reverse proxy? Which ones appear in Instagram's architecture?

A forward proxy acts for clients (they configure it; destinations see the proxy) β€” e.g. corporate web filters. A reverse proxy acts for servers (clients think it's the server) and provides load balancing, TLS termination, caching, routing, auth and protection. Instagram's CDN edges, load balancers and API gateway are all reverse proxies. They pass the original client IP via X-Forwarded-For/Forwarded headers.

Which HTTP status codes should a client retry, and how?

Retry transient failures: network errors, timeouts, 429 (respecting Retry-After), 502, 503, 504 and usually 500 β€” with exponential backoff and jitter, a retry budget, and only for idempotent requests or ones carrying an idempotency key. Don't retry 400, 403, 404, 409, 413 β€” the same request will fail the same way. 401 means refresh the token, then retry once.

18. Check your understanding

Roughly what is the minimum possible RTT between two cities 6,000 km apart, connected by fibre?

RTT β‰ˆ 2 Γ— 6,000 km Γ· 200,000 km/s = 60 ms. Real paths are longer and add router delays, so expect noticeably more (perhaps 80–100 ms).

With a 100 ms RTT, how long before the first response byte arrives on a brand-new TCP + TLS 1.2 connection, versus TLS 1.3, versus QUIC 0-RTT (ignore DNS and server time)?

TLS 1.2: TCP 1 + TLS 2 + request 1 = 4 RTT = 400 ms. TLS 1.3: 1 + 1 + 1 = 300 ms. QUIC 0-RTT: the request goes in the first flight = 1 RTT = 100 ms.

Your phone walks from home Wi-Fi onto 4G in the middle of a Reel download. What happens with HTTP/2 over TCP, and with HTTP/3?

The phone's IP address changes. TCP connections are bound to the 5-tuple, so they break: the app must detect the failure (often after a timeout), reconnect with a full handshake, and re-request β€” causing a stall. QUIC identifies the connection by a connection ID, so it migrates to the new path after a quick path validation and the download continues.

Why might HTTP/2 perform worse than HTTP/1.1 on a network with 3% packet loss?

HTTP/2 puts all requests on one TCP connection; each lost packet stalls every stream until it's retransmitted, and the single connection's congestion window is cut on each loss. HTTP/1.1's six independent connections each stall only their own request, and losses are spread across six congestion windows.

A fresh TCP connection has an initial window of ~14 KB that doubles every RTT. About how many RTTs does it take to deliver a 400 KB image?

Cumulative: 14, 42, 98, 210, 434 KB β†’ about 5 RTTs. On a 20 ms path to a nearby PoP that's ~100 ms; on a 220 ms path to another continent it's ~1.1 s. This is why media is served from nearby CDN edges and connections are reused (their windows are already large).

Thousands of users of a mobile carrier all appear to your servers from the same IP. Why, and what does that mean for rate limiting?

Carrier-grade NAT maps many private device addresses to one public IPv4 address (distinguished by port). A strict per-IP rate limit would block thousands of innocent users when one misbehaves. Rate limit by authenticated user/token or device instead, and use per-IP limits only as a loose, high threshold for unauthenticated endpoints.

Your DM WebSocket connections keep "silently" dying after a few idle minutes on mobile. What's the likely cause and fix?

NAT devices and intermediate load balancers drop idle mappings/connections after a timeout, without telling either end. Send application-level heartbeats (ping/pong) more often than the shortest idle timeout (e.g. every 30–60 s, tuned to balance battery), detect missing pongs to reconnect quickly, and resynchronise missed messages on reconnect.

Is it safe to accept "POST /comments" as TLS 1.3 0-RTT early data? Why or why not?

No. 0-RTT data can be captured and replayed by an attacker, causing the comment to be posted twice (or more). Only accept safe, idempotent requests (like GET feed) as early data, or require an idempotency key that makes replays harmless.

🎯 Key takeaways

Related lessons