Module 1 · Foundations that hold everything up

Lesson 02 — Networking basics

DNS, TCP, latency, load balancers and Nginx in front of your Django.

Published
In this lesson
  1. Exercise 1 — DNS with
  2. Exercise 2 — The phase breakdown with
  3. Exercise 3 — Simulate the 502 and fix Nginx
  4. Exercise 4 — Balancing across two workers
  5. Exercise 5 — Proxy headers and a 404 that bites
  6. Exercise 6 — Balancer health check (design)
  7. Exercise 7 — Reservation latency (senior discussion)
  8. Exercise 8 — Route tracing (optional, theoretical)
  9. Submit

Do them in order on your local TicketFlow. Submit the trimmed outputs and your answers in the chat. Do not look at solutions.md before submitting.

Setup (3 min):

bash
cd ~/dev/ticketflow && source .venv/bin/activate
python manage.py runserver 8000   # terminal 1

Exercise 1 — DNS with dig (warm-up)

  1. Run dig +short python.org and note which record type it returns.
  2. Run dig python.org and find the TTL in the ANSWER section. Repeat 10 seconds later: did the TTL go down? Why?
  3. dig +trace python.org 2>/dev/null | tail -20: list the chain (root → TLD → authoritative) you saw.
  4. Compare dig @1.1.1.1 python.org with dig @9.9.9.9 python.org: do the answers match? What does that imply for an IP migration?

Exercise 2 — The phase breakdown with curl -w

Create the file curl-format.txt:

text
            dns:  %{time_namelookup}s
            tcp:  %{time_connect}s
            tls:  %{time_appconnect}s
          ttfb:  %{time_starttransfer}s
         total:  %{time_total}s
     remote_ip:  %{remote_ip}
  1. Measure your local API: curl -w @curl-format.txt -o /dev/null -s http://127.0.0.1:8000/api/health/. What are DNS and TCP against localhost? Why?
  2. Repeat against https://django.com and https://www.python.org. Which phase accumulates the most? Does it match the physical distance?
  3. Repeat the same external URL 3 times without pausing. Do DNS/TCP/TLS drop on the 2nd and 3rd? Explain which cache acts at each phase.

Submit: the three trimmed tables and your explanation of question 3.

Exercise 3 — Simulate the 502 and fix Nginx

Without installing Nginx yet (we will in Module 9), demonstrate the concept with Gunicorn:

  1. Install Gunicorn: pip install gunicorn and start it: gunicorn config.wsgi --bind 127.0.0.1:8000.
  2. In another terminal: curl -i http://127.0.0.1:8000/api/health/. It works.
  3. Kill Gunicorn (Ctrl+C) and repeat the curl. What exact error do you get on the client side? That is, conceptually, the 502 Bad Gateway: the proxy cannot talk to the app.
  4. Name 2 things you would look at in a real Nginx (error.log) for that 502.

Exercise 4 — Balancing across two workers

  1. Start Gunicorn with two workers and verbose logs: gunicorn config.wsgi --bind 127.0.0.1:8000 --workers 2 --log-level debug.
  2. Fire 6 requests in a row: for i in $(seq 6); do curl -s -o /dev/null http://127.0.0.1:8000/api/health/; done.
  3. Watch the logs: do two PIDs serve the requests? Which algorithm is Gunicorn using by default? (hint: --worker-class sync spreads by accepting connections, something different from an HTTP balancer's round robin; explain the difference in your own words).
  4. What happens if one worker blocks for 10 seconds on a slow request and 3 more arrive at that same worker? (reason with "least connections" vs "accept-based").

Exercise 5 — Proxy headers and a 404 that bites

In config/settings.py temporarily add:

python
SECURE_PROXY_SSL_HEADER = ("HTTP_X_FORWARDED_PROTO", "https")
  1. curl -i http://127.0.0.1:8000/api/health/: what response do you get and why? (this header makes Django believe the proxy already terminated TLS).
  2. Remove the line. Now: which client IP would Django see if the request arrives via Nginx without X-Forwarded-For configured? And which scheme (request.scheme)?
  3. Write in 2 lines which proxy_set_header configuration is needed for Django to see the real IP and https.

Exercise 6 — Balancer health check (design)

Design (on paper, 5 lines) the balancer-grade /api/health/ endpoint:

  1. What should it check: just "process alive", or also database and Redis? What is the cost of checking the DB on every check every 5 seconds?
  2. What code do you return if the DB is slow but responding: 200 or 503? Justify with the effect on the balancer (drop from pool vs keep).
  3. What should it return: the deployment version, boot time, the PID? Why do those hints help debugging?

Exercise 7 — Reservation latency (senior discussion)

TicketFlow's POST /api/events/42/reserve currently does: validate JSON, 2 SELECTs, 1 reservation INSERT, 1 item INSERT, 1 COMMIT (all local).

  1. Estimate the added latency if the DB moves from localhost to a different region (~90 ms RTT), knowing there are 5 round trips to the DB. How does a single transaction solve it? (save it: it is Lesson 10).
  2. The events listing is cached 60 s on a CDN. A buyer sees an seat as "available" that another user just reserved. What is that at the network level, and what business decision do you propose?

Exercise 8 — Route tracing (optional, theoretical)

  1. traceroute -n ticketflow.app (or tracepath): how many hops to the destination? What do the * on some hops mean?
  2. Why is the first hop usually your router and the last one may not answer ICMP?

Submit

Paste the trimmed outputs and your answers in the chat. With this I close Lesson 02 and mark it taught; next up: Lesson 03 — Concurrency and asynchrony (the one that makes it possible for two buyers not to take the same seat without the database saying a word).