A Deep Dive into the Journey of a Web Request from Browser → DNS → Network → AWS → Kubernetes → Microservices → Database → Observability → Browser
Follow one request across the entire distributed system — from the user's keyboard to the browser and back — while understanding every network hop, AWS component, application layer, data store, security boundary, observability signal, latency contribution, and failure mode.
What actually happens when we type:
https://example.com
and press Enter?
Most answers stop at "DNS resolves the name, then the browser makes an HTTP request." That is roughly 2% of the story. The real answer crosses a dozen independent systems, each with its own caches, timeouts, retry semantics, failure modes, and blast radius.
Browser
→ DNS
→ Network
→ TCP/QUIC
→ TLS
→ HTTP
→ CDN
→ WAF
→ Load Balancer
→ Kubernetes
→ Microservices
→ Cache
→ Database
→ Message Broker
→ Observability
→ Response
→ Browser Rendering
This repository documents that journey step by step — and then, more importantly, documents what happens when each step fails.
There is no shortage of "what happens when you type google.com" write-ups. Almost all of them describe the happy path on a single machine. Real systems are defined by their edges:
- The 30-second DNS TTL that turns a 10-second failover into a 5-minute outage.
- The connection pool sized for p50 that collapses at p99.
- The Redis cache whose absence takes down the database it was protecting.
- The retry policy that turns a 2% error rate into a self-sustaining traffic amplification loop.
This repo is written for the engineer who has to reason about all of that at 3 a.m. Every layer chapter ends with latency contribution, failure modes, and what you would actually see in your telemetry.
| # | Layer | What it covers |
|---|---|---|
| 01 | Browser | URL parsing, DNS cache, HTTP cache, cookies, Service Workers, connection reuse |
| 02 | DNS | Browser/OS caches, resolver, root → TLD → authoritative, Route 53, A/AAAA/CNAME, TTL, failover |
| 03 | Network | ARP, IP, routing, NAT, ISP, BGP, VPC, subnets, route tables, IGW, NAT Gateway |
| 04 | Connection | TCP 3-way handshake, SYN/SYN-ACK/ACK, congestion control, QUIC, HTTP/3 |
| 05 | Security | TLS handshake, certificate validation, cipher negotiation, mTLS, WAF, authn/authz, JWT, OAuth 2.0, Zero Trust |
| 06 | AWS Edge | Route 53, CloudFront, WAF, ALB / API Gateway, VPC ingress |
| 07 | Compute | EKS / ECS / EC2, Kubernetes Service, Ingress, Pod, container, the Go process |
| 08 | Application | HTTP server internals, middleware, authn/authz, rate limiting, business logic, goroutines, connection pools |
| 09 | Data | Redis, Aurora/PostgreSQL, DynamoDB, Kafka, SQS/SNS, consistency, transactions, caching patterns |
| 10 | Response | Service → ALB → CloudFront → Internet → Browser, compression, caching headers |
| 11 | Browser Rendering | HTML → DOM, CSSOM, JavaScript, render tree, layout, paint, composite, screen |
| 12 | Observability | Logs, metrics, traces, profiles; OpenTelemetry, Prometheus, Grafana, Datadog, Splunk, CloudWatch |
Start here: docs/00-overview.md — the whole journey in one page, with the end-to-end sequence diagram.
Don't stop at the happy path.
Sixteen failure scenarios, each written as an incident walkthrough: what breaks, what the user sees, what your dashboards show, what the blast radius is, how long recovery takes, and how you design so it doesn't page you.
| # | Scenario | Blast radius |
|---|---|---|
| 01 | DNS fails | Global, total |
| 02 | DNS returns the wrong IP | Global, silent, worst-case |
| 03 | TLS certificate expires | Global, total, cliff-edge |
| 04 | CloudFront is unavailable | Global or per-POP |
| 05 | WAF blocks the request | Segment of users |
| 06 | ALB has no healthy targets | Per-region, total |
| 07 | A Kubernetes Pod crashes | Small, usually invisible |
| 08 | 50% of Pods crash | Partial → cascading |
| 09 | Redis is unavailable | Cascading to the database |
| 10 | Aurora becomes unavailable | Writes down, reads degraded |
| 11 | Kafka is down | Async paths, delayed damage |
| 12 | An AWS AZ fails | 1/3 capacity, survivable |
| 13 | An entire AWS Region fails | Everything, hours |
| 14 | The network partitions | Split-brain, data risk |
| 15 | Latency goes 50ms → 5s | Queue collapse |
| 16 | Traffic increases 100x | Everything, at once |
Index with cross-cutting patterns: docs/failure-modes/README.md
Every layer chapter reports its slice of the budget. The consolidated view — cold start vs. warm connection vs. CDN hit — lives in docs/latency-budget.md.
The one-line version for a warm, well-tuned system serving a dynamic response from us-east-1 to a user in Frankfurt:
DNS (cached) 0 ms
TCP + TLS (reused) 0 ms
Browser → POP 8 ms
POP → origin ALB 88 ms ← the speed of light, and it is not negotiable
ALB → Pod 1 ms
App + Redis 4 ms
App + Aurora 11 ms
Response back ~96 ms
─────────────────────────
Total ~208 ms
Note which line dominates. Most "performance work" attacks the 4 ms line.
make runFrom a clean clone that is the only command you need. Everything in go/ is
standard library only — go.mod has no require block, there is nothing to
download, and no network is needed to build. make run starts the demo edge
service and walks through it:
1. cold read of order 1042 — X-Data-Source names where the bytes came from
X-Data-Source: database
2. the same order again
X-Data-Source: cache
3. 200 requests as fast as one client can send them ...
66 served, 134 refused with 429
4. counters
{"breaker_state":"closed","cache_hits":67,"cache_misses":6,...}
Each program is a self-contained demonstration of one layer:
make run # the edge service, then a guided walkthrough (no network)
make run-resilient # retries vs budgets vs breakers vs hedging (no network)
make run-httptrace # every phase of a real request, timed (needs network)
make run-dnswalk # the delegation chain from a root server (needs UDP/53)
make run-tlsinspect # handshake, chain, session resumption (needs network)
make check # gofmt, vet, test, build — everything CI runs| Command | Layer | What it demonstrates |
|---|---|---|
go run ./cmd/dnswalk example.com |
02 | Walks root → TLD → authoritative yourself, prints every referral and TTL |
go run ./cmd/tlsinspect example.com:443 |
05 | Full handshake dump: version, cipher, ALPN, chain, expiry, OCSP staple |
go run ./cmd/httptrace https://example.com |
01–05 | httptrace hooks timing every phase: DNS, connect, TLS, TTFB, transfer |
go run ./cmd/resilient |
08 | Retry with jitter, circuit breaker, hedged requests, load shedding — side by side |
go run ./cmd/edgeservice |
07–12 | A production-shaped HTTP service: middleware chain, pools, graceful shutdown, health probes, OTel |
See go/README.md for details on each.
If you have 10 minutes — read docs/00-overview.md.
If you have an hour — read the overview, then 02-dns, 05-security, and 09-data. Those three contain most of the ideas that generalize.
If you are preparing for a systems design interview — read all 12 layer docs, then work through the failure modes and try to answer each one before reading the answer.
If you are on call — bookmark docs/failure-modes/README.md.
The reference architecture used throughout:
Browser
→ Route 53 (alias)
→ CloudFront (with AWS WAF attached)
→ ALB in a VPC across 3 AZs
→ EKS: Ingress → Service → Pods running a Go service
→ ElastiCache (Redis) + Aurora PostgreSQL + DynamoDB
→ MSK (Kafka) for async work
→ OpenTelemetry → Prometheus / CloudWatch / a vendor backend
This is not the only valid architecture, and several chapters discuss the alternatives (API Gateway vs. ALB, ECS vs. EKS, DynamoDB vs. Aurora, SQS vs. Kafka). But committing to one concrete stack keeps the numbers honest — you cannot write a latency budget for an abstraction.
Corrections are extremely welcome, especially numbers. If a stated latency, timeout default, or AWS behaviour is wrong or has changed, open an issue with a source. See CONTRIBUTING.md.