02 Β· CS Fundamentals
Networking β the life of a request through a stack you operate
You run Kong in front of FastAPI services on Kubernetes. Every concept below is something a packet crosses on its way through your infrastructure. The interview move: answer the theory, then land it with "and this is exactly what happens at my gateway."
01The journey: you type https://api.example.com/users/42 and hit Enter
Step 0 β Layers (30-second mental model)
L7 Application HTTP, gRPC, DNS, TLS handshake payloads "what to say"
L4 Transport TCP, UDP β ports, reliability "which app, delivered how"
L3 Network IP β addressing, routing between networks "which machine"
L2 Link Ethernet/WiFi β same-network hop "next hop"
Each layer wraps the one above (encapsulation): your JSON rides in an HTTP message, in TCP segments, in IP packets, in Ethernet frames.
Step 1 β DNS: name β IP
Nobody routes on names. The resolver chain:
browser cache β OS cache β recursive resolver (ISP/1.1.1.1/CoreDNS)
β (on miss, walks the hierarchy)
βΌ
root servers ββΊ .com TLD servers ββΊ example.com's authoritative NS
β
βΌ A / AAAA record + TTL
203.0.113.7
- Record types worth knowing: A (IPv4), AAAA (IPv6), CNAME (alias), NS, MX, TXT, SRV.
- TTL governs caching β why DNS changes "propagate" slowly and why low TTLs are the standard trick before a migration.
- DNS classically runs on UDP port 53 (single question, single answer β no connection needed), TCP for big responses/zone transfers, and increasingly DoH/DoT.
my-svc.my-namespace.svc.cluster.local resolves to a Service's ClusterIP; headless Services return pod IPs directly. Your services find Postgres/Kafka/each other through this exact mechanism.Step 2 β TCP three-way handshake
You have an IP. Now establish a reliable byte pipe to port 443:
Client Server
β ββ SYN (seq=x) ββββββββββββββΊ β "let's talk, my starting seq is x"
β ββ SYN-ACK (seq=y, ack=x+1) ββ β "sure, mine is y, I heard you"
β ββ ACK (ack=y+1) ββββββββββββΊ β "I heard you too" β ESTABLISHED
- 1 round trip before any data. This is why connection reuse matters: keep-alive, DB connection pools, Kong's upstream keepalive pool β all exist to amortize handshakes.
- A connection = the 4-tuple (src IP, src port, dst IP, dst port). Server listens on one port; each accepted connection is a new socket/FD.
- Teardown: FIN/ACK each way; closer lingers in
TIME_WAIT(why mass short-lived connections can exhaust ephemeral ports). - SYN flood: attacker sends SYNs, never ACKs, fills the half-open backlog β mitigated by SYN cookies.
Step 3 β TLS handshake
On top of the TCP pipe, negotiate encryption (TLS 1.3, one round trip):
ClientHello βββΊ supported ciphers + client key share (+ SNI: hostname!)
ServerHello βββ chosen cipher + server key share + certificate
[both derive session keys via ECDHE β forward secrecy]
Finished β Finished β encrypted application data
- Certificate proves identity: server's public key signed by a CA the client trusts (chain of trust). Client checks signature chain, hostname match, expiry.
- Asymmetric crypto is only for the handshake (key exchange/authentication); the session itself uses fast symmetric encryption (AES-GCM/ChaCha20) with the derived keys.
- SNI: the client names the host in ClientHello so one IP can serve many certs β this is how Kong/any ingress routes TLS for multiple domains.
- TLS termination: in your world, TLS usually ends at the ingress/gateway (Kong); inside the cluster traffic is plaintext or re-encrypted via mTLS (service mesh). Offloads crypto and centralizes cert management (cert-manager + Let's Encrypt).
Step 4 β HTTP request/response
GET /users/42 HTTP/1.1
Host: api.example.com
Authorization: Bearer eyJ...
Accept: application/json
βββ HTTP/1.1 200 OK
Content-Type: application/json
Cache-Control: max-age=60
{"id": 42, "name": "..."}
Then in your infra: request hits the LB β Kong (authn plugin checks the JWT, rate-limit plugin counts it, route matches /users β upstream service) β kube-proxy/Service picks a pod β uvicorn β FastAPI handler β Postgres β response back down the chain, each layer adding headers (x-request-id, CORS...).
Step 5 β Rendering (one sentence for completeness)
Browser parses HTML, discovers CSS/JS/img URLs, repeats this whole dance per origin (with connection reuse), builds DOM+CSSOM, renders. For an API interview, DNSβTCPβTLSβHTTP is the meat.
02TCP vs UDP
TCP β reliable byte pipe
connect() ββ 3-way handshake βββΊ pipe
send("hel"); send("lo")
arrives in order, retransmitted
on loss, congestion-controlled β
but it's ONE byte stream, not
messages: recv() may return "he"
HTTP, Postgres, Kafka, Redis, gRPC
UDP β fire and forget
sendto(datagram, addr) no setup
each datagram independent;
may drop, reorder, duplicate β
and that's YOUR problem (or
no problem at all)
DNS, QUIC/HTTP-3, video/games,
syslog, StatsD
| TCP | UDP | |
|---|---|---|
| Model | Connection, ordered byte stream | Connectionless datagrams |
| Reliability | ACKs + retransmit, dedupe | None β fire and forget |
| Ordering | Guaranteed in-order delivery | None |
| Flow/congestion control | Yes (windows, cwnd, slow start) | No |
| Overhead | Handshake, state, head-of-line blocking | Minimal, no setup |
| Used by | HTTP/1.1&2, Postgres, Kafka, Redis, gRPC | DNS, QUIC/HTTP-3, video/games, syslog, StatsD |
Two TCP subtleties that make you sound experienced:
- It's a byte stream, not messages. One
send()β onerecv(). Application protocols must frame messages themselves (HTTP's Content-Length/chunked, Kafka's length-prefixed binary protocol, Postgres's wire protocol). "Why did my socket read return half a message" = this. - Congestion control: TCP probes for bandwidth (slow start: cwnd doubles per RTT, then AIMD; loss β back off). It's why throughput ramps up on long transfers and why a lossy link crushes TCP throughput.
03HTTP/1.1 vs HTTP/2 vs HTTP/3 β intuition level
HTTP/1.1: one request AT A TIME per TCP connection
conn1: [req A ββββ][resp A ββββ][req B ...] β browsers open 6 conns/host
(head-of-line at HTTP level)
HTTP/2: one TCP connection, many interleaved streams (binary frames)
conn: [A1][B1][A2][C1][B2][A3] ... β multiplexing + header
BUT one lost TCP packet stalls ALL streams compression (HPACK) + prio
(head-of-line moved down to TCP)
HTTP/3: streams over QUIC over UDP
independent streams β a lost packet stalls only ITS stream.
TLS 1.3 built in; 1-RTT (0-RTT resume) setup; connection ID survives
IP changes (wifiβ5G, connection migration).
- 1.1: text protocol, keep-alive reuses the connection but requests are serialized per connection; pipelining existed and failed. Still everywhere server-side (simple, debuggable β
curl -vshows it raw). - 2: binary framing β true multiplexing over one connection, header compression, server push (deprecated in practice). Solves HTTP-level HoL but inherits TCP-level HoL: one lost segment blocks every stream behind it.
- 3: rebuilds the transport as QUIC on UDP β per-stream reliability, so loss is isolated; crypto and transport handshakes merged (fewer RTTs); userspace evolution (no waiting for kernel TCP changes).
04REST semantics
REST = resources (nouns) identified by URLs, manipulated by a uniform verb set, stateless requests.
| Verb | Meaning | Safe? | Idempotent? |
|---|---|---|---|
| GET | Read | yes | yes |
| HEAD | Read, headers only | yes | yes |
| PUT | Full replace at known URL | no | yes (same PUT twice = same state) |
| DELETE | Remove | no | yes |
| POST | Create / non-idempotent action | no | no |
| PATCH | Partial update | no | not guaranteed |
- Safe = no state change (cacheable, prefetchable). Idempotent = N identical calls β‘ 1 call β this is not academic: retries and at-least-once delivery are only sane against idempotent operations. It's why payment APIs use idempotency keys on POST, and the same reasoning as your Kafka consumers needing idempotent handlers.
- Stateless: every request carries what's needed (token, etc.); no server session affinity β any pod can serve any request β horizontal scaling and rolling deploys just work. This property is what makes K8s Services' random pod-picking correct.
- Good REST hygiene: nouns not verbs (
POST /orders, not/createOrder), plural collections, status codes over{"error": ...}-with-200, versioning strategy, pagination on collections.
05Real-time: WebSockets vs SSE vs long polling
The problem: HTTP is requestβresponse; servers can't spontaneously talk. Three workarounds:
Long polling: client ββreqβββΊ(server holds until data or timeout)ββrespβββΊ repeat
~compatible everywhere; latency + reconnect overhead; no infra needs
SSE: client ββGETβββΊ server keeps response open, streams
"data: ...\n\n" events forever. ONE WAY (serverβclient).
Plain HTTP: proxies/LBs happy, auto-reconnect built in (EventSource).
WebSocket: HTTP GET + Upgrade: websocket β 101 Switching Protocols
β same TCP conn becomes a FULL-DUPLEX message pipe (ws:// wss://)
| SSE | WebSocket | Long polling | |
|---|---|---|---|
| Direction | Server β client only | Full duplex | Server β client (per request) |
| Transport | Plain HTTP response, kept open | HTTP Upgrade β raw TCP framing | Repeated plain HTTP |
| Proxy/LB friendliness | High (it's just HTTP) | Needs Upgrade support, idle-timeout care | Highest |
| Reconnect | Built in (EventSource + Last-Event-ID) | Roll your own | Inherent (every poll) |
| Best for | Notifications, live feeds, LLM token streaming | Chat, collab editing, games | Firewall-hell fallback |
data: events over one long-lived HTTP response; that token-by-token typing effect in every AI product is an EventSource-style stream, not a WebSocket. When a serverβclient stream is all you need, SSE is the simplest thing that works: plain HTTP, proxy-friendly, auto-reconnecting.Choosing:
- Serverβclient stream only (notifications, live feeds, LLM token streaming) β SSE.
- Bidirectional, low latency (chat, collab editing, games) β WebSocket.
- Lowest common denominator / firewall hell β long polling fallback.
06Load balancers: L4 vs L7
L4 (transport): routes on IP:port. Sees TCP/UDP, not HTTP.
client ββTCPβββΊ [LB: pick backend, forward/NAT packets] βββΊ backend
Blazing fast, protocol-agnostic, cheap. Can't route by path/header,
can't retry a request, one connection = one backend.
L7 (application): TERMINATES the connection, parses HTTP, makes a new
request upstream.
client ββHTTPβββΊ [LB: read path/headers/cookies] ββHTTPβββΊ chosen backend
Path/host routing, TLS termination, retries, header rewrites,
per-request balancing, canary %, auth β at parsing + memory cost.
- Algorithms: round-robin, least-connections, weighted, consistent hashing (nice segue: same consistent hashing that Kafka-esque systems and caches use to minimize reshuffling).
- Health checks eject bad backends β the LB-level mirror of K8s readiness probes.
07API gateway β what Kong actually does for you
A gateway is an L7 reverse proxy + policy engine: one front door where cross-cutting concerns live so N services don't reimplement them.
βββββββββββββββββββββββββ KONG βββββββββββββββββββββββββ
client βββΊ β route match β [authn: JWT/key] β [rate limit] β β βββΊ upstream
β [transform headers] β [log/metrics/tracing] β proxy β service
ββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
Speak concretely, since you run it:
- Routing: Routes β Services β Upstreams (with its own LB + health checks across targets).
- Auth at the edge: JWT validation / API keys / OAuth introspection before traffic ever reaches a pod β services can then trust identity headers.
- Rate limiting & quotas: per-consumer/route counters (local, or Redis-backed for cluster-accurate limits β a distributed-counter problem, ties to system design).
- Observability: uniform access logs, latency metrics, request-id injection for tracing across services.
- Transformations, CORS, request size limits, canary/traffic-split, plugin ecosystem (Kong = OpenResty = NGINX + Lua/plugins).
- Gateway (north-south, edge policy) vs service mesh (east-west, sidecar-per-pod mTLS/retries/telemetry) β complementary, not competitors.
08Common ports
| Port | What |
|---|---|
| 22 | SSH |
| 53 | DNS |
| 80 / 443 | HTTP / HTTPS |
| 5432 | PostgreSQL |
| 6379 | Redis |
| 9092 | Kafka broker |
| 9200 | OpenSearch/Elasticsearch HTTP |
| 8000 / 8080 | dev HTTP / alt HTTP (uvicorn default 8000) |
| 8001 / 8443 | Kong admin API / proxy TLS (8000 proxy HTTP) |
| 3306 / 27017 | MySQL / MongoDB |
| 6443 | Kubernetes API server |
| 25 / 587 | SMTP |
(Ports < 1024 are privileged β need root/CAP_NET_BIND_SERVICE, why containers often listen on 8080 and let the LB own 443.)
09Status codes that matter
- 2xx β 200 OK Β· 201 Created (+ Location) Β· 202 Accepted (async job queued β your "enqueue to Kafka and return" pattern) Β· 204 No Content (DELETE).
- 3xx β 301 permanent / 302 temporary redirect Β· 304 Not Modified (conditional GET hit: ETag/If-None-Match β caching's handshake) Β· 307/308 (redirect preserving method).
- 4xx (client's fault) β 400 malformed Β· 401 unauthenticated (who are you) vs 403 unauthorized (I know you; no) Β· 404 Β· 405 wrong verb Β· 409 conflict (version/duplicate) Β· 422 validation failed (FastAPI's default for Pydantic errors) Β· 429 Too Many Requests (what Kong's rate limiter returns; include Retry-After).
- 5xx (server's fault) β 500 unhandled error Β· 502 Bad Gateway (proxy got garbage/refusal from upstream β Kong couldn't reach or parse your pod's reply) Β· 503 Service Unavailable (no healthy upstream / overload β what you see when all pods fail readiness) Β· 504 Gateway Timeout (upstream too slow β proxy timeout < app timeout misconfigs live here).
kubectl get endpoints.10Status-code quiz β what does the client see?
1. A request hits Kong with no Authorization header at all. Which status β and which one would it be if the JWT were valid but the user lacked the required role?
2. A consumer blows through the per-minute limit configured in Kong's rate-limiting plugin. What comes back, and which header should ride along?
3. Every pod behind a Service is failing its readiness probe after a bad deploy. What does the gateway return to clients?
kubectl get endpoints (empty endpoints list = readiness failing) and the probe config. This is the classic "all pods fail readiness" signature at the edge.4. A pod crashes mid-response (or refuses the connection), and Kong gets garbage instead of a valid HTTP reply. Status?
5. Your FastAPI handler takes 45 s on a slow Postgres query, but Kong's upstream timeout is 30 s. What does the client see, and what's the misconfiguration pattern called out here?
6. A client POSTs JSON that fails Pydantic validation in FastAPI. And separately: a valid request that just enqueues a job to Kafka and returns immediately β what should each return?
11Self-test β say these answers out loud
Q1. What happens when you type a URL and press Enter?
DNS (cache β recursive resolver β root/TLD/authoritative, get A record with TTL) β TCP 3-way handshake to :443 β TLS 1.3 handshake (SNI, cert chain validation, ECDHE key exchange β symmetric session keys) β HTTP request β server chain (LB β gateway β service β app β DB) β response β render. ~3 RTTs cold before any app work, hence keep-alive, CDNs and HTTP/3.
Q2. TCP vs UDP β and why does anything use UDP?
TCP: connection, ordered reliable byte stream, flow+congestion control β the default for request/response. UDP: connectionless datagrams, no guarantees, no handshake β for cases where retransmission is pointless (live media), trivial (DNS re-ask), or where you build better reliability yourself (QUIC/HTTP-3). Bonus: TCP is a byte stream, so protocols must do their own message framing.
Q3. Difference between HTTP/1.1, 2 and 3?
1.1: one request at a time per connection (parallelism = many connections). 2: binary frames multiplex many streams over one TCP connection + header compression β but TCP-level head-of-line blocking remains (one lost packet stalls all streams). 3: QUIC over UDP β independent per-stream loss recovery, TLS integrated, fewer handshake RTTs, connection migration across network changes. gRPC needs h2.
Q4. What do idempotent and safe mean, and why do they matter?
Safe = no state change (GET/HEAD) β cacheable. Idempotent = repeating has no additional effect (GET/PUT/DELETE; not POST). Matters because retries, at-least-once queues, and network timeouts all re-execute operations β you can only blindly retry idempotent ones; otherwise you need idempotency keys. Same reason my Kafka consumers are written idempotent.
Q5. WebSockets vs SSE vs long polling β how do you choose?
Long polling: hold the request until data; works everywhere, inefficient. SSE: one long-lived HTTP response streaming events, serverβclient only, auto-reconnect, proxy-friendly β ideal for notifications and LLM token streaming. WebSocket: HTTP Upgrade to a full-duplex TCP pipe β for chat/collab/bidirectional. Ops cost of both persistent options: sticky/stateful connections, pub/sub backplane for multi-pod fanout, heartbeats vs idle timeouts, graceful drain on deploys.
Q6. L4 vs L7 load balancing?
L4 forwards TCP/UDP by IP:port β fast, dumb, connection-granular (kube-proxy/NLB). L7 terminates and parses HTTP β routes by path/host/header, does TLS termination, retries, canaries, per-request balancing (Kong/ALB/ingress). Real deployments stack them: NLB β Kong β K8s Service.
Q7. What does an API gateway do? (You run Kong.)
Single L7 front door centralizing cross-cutting policy: route matching to upstreams, edge authentication (JWT/keys), rate limiting (Redis-backed for cluster accuracy), transformations, CORS, and uniform logging/metrics/request-ids. Kong = NGINX/OpenResty + Lua plugins; Services/Routes/Upstreams model with health-checked load balancing. Tradeoffs: added hop, must be HA. Distinct from a service mesh, which handles east-west traffic via sidecars.
Q8. 401 vs 403? 502 vs 503 vs 504?
401 = not authenticated (missing/bad credentials; challenge to log in) vs 403 = authenticated but not allowed. 502 = proxy got an invalid/refused response from upstream; 503 = no available/healthy upstream or overload; 504 = upstream timed out. All three at a gateway mean "look behind the proxy": readiness probes, crashes, timeout budget mismatches.
Q9. Walk through the TCP handshake. Why does connection reuse matter?
SYN (seq x) β SYN-ACK (seq y, ack x+1) β ACK: one RTT to establish, then TLS adds another. At 100+ ms RTTs, per-request handshakes dominate latency and burn ports/FDs β hence HTTP keep-alive, connection pools to Postgres/Redis, and gateway upstream keepalives.
Q10. How does service discovery/networking work inside Kubernetes?
CoreDNS resolves svc.namespace.svc.cluster.local to a Service ClusterIP; kube-proxy programs iptables/IPVS to DNAT that VIP to a ready pod IP (L4, effectively random). Every pod has its own IP (net namespace); readiness probes gate endpoint membership β which is exactly why a failing readiness probe manifests as 503s at the gateway.
Q11. Why is HTTPS not slow / what's actually expensive in TLS?
Handshake costs one RTT (TLS 1.3) and some asymmetric crypto; the session uses hardware-accelerated symmetric ciphers (AES-GCM) β negligible per-byte cost. With session resumption/0-RTT and connection reuse, TLS overhead mostly disappears; terminate at the edge to centralize cert handling.