Stack: Django + DRF · Proyecto: TicketFlow Estado: Publicada — impartición cuando entregues los ejercicios de la 00b y la 01 Prerrequisito: Lección 01 — HTTP a fondo
Objetivos
Al terminar esta lección podrás:
- Explicar el viaje completo de una petición: DNS → TCP → TLS → HTTP → respuesta.
- Razonar sobre latencia: qué la compone, cómo se mide y por qué el ancho de banda casi nunca es el problema.
- Decidir dónde va un balanceador de carga y qué tipo de algoritmo conviene a cada caso.
- Configurar Nginx como proxy inverso delante de Gunicorn, con TLS y cabeceras correctas.
- Diagnosticar problemas de red con
dig,curl,ping,tracerouteyss.
1. El viaje de una petición (en 6 saltos)
Cuando el navegador pide https://ticketflow.app/api/events/, ocurre esto:
1. DNS "¿Quién es ticketflow.app?" → 203.0.113.42
2. TCP 3-way handshake (SYN, SYN-ACK, ACK)
3. TLS handshake (1-RTT en TLS 1.3)
4. HTTP petición → Nginx (proxy inverso) → Gunicorn → Django
5. Render Django consulta PostgreSQL, Redis y monta el JSON
6. Vuelta respuesta al revés, con keep-alive la conexión queda reutilizableCada salto añade latencia. Un senior no memoriza la lista: sabe cuánto cuesta cada salto y por eso coloca las cosas donde las coloca.
Clave: la Lección 01 estudió el salto 4 a fondo (HTTP). Esta lección estudia los saltos 1-3 y el "dónde" físico: quién recibe la conexión y cómo se reparte entre máquinas.
2. DNS: la agenda de Internet
DNS traduce nombres a direcciones. La cadena completa:
Cache del navegador → Cache del SO → Resolver del ISP (recursivo)
→ Root (.) → TLD (.app) → Autoritativo (ns.ticketflow.app) → A/AAAATipos de registro que usarás de verdad:
| Registro | Qué responde | Uso en TicketFlow |
|---|---|---|
| A / AAAA | IPv4 / IPv6 | ticketflow.app → 203.0.113.42 |
| CNAME | alias a otro nombre | www → ticketflow.app |
| ALIAS/ANAME | alias en el apex | ticketflow.app → balanceador |
| MX | servidores de correo | los correos de confirmación no reboten |
| TXT | texto arbitrario | verificación de dominio y SPF |
Dos propiedades que importan en producción:
- TTL: cuánto tiempo una respuesta vive en caché. Bajar el TTL (por ejemplo a 60 s) antes de una migración de IP te permite volver atrás rápido; con TTL de 86400 s estás atado un día entero a tu error.
- Propagación: no es que "la red se actualice"; es que cada caché respeta su copia hasta que vence su TTL. Por eso los cambios de DNS son de "unos minutos a 48 horas".
Nota: DNS es UDP 53 normalmente (rápido, sin estado); TCP 53 para respuestas grandes o transferencias de zona. Si "el dominio resuelve en tu máquina pero no en producción", lo primero es preguntar a qué resolver le preguntaste.
3. TCP: fiabilidad antes que velocidad
HTTP vive sobre TCP (o QUIC sobre UDP en HTTP/3). Lo que TCP te da:
- Handshake de 3 vías (SYN → SYN-ACK → ACK): una RTT antes de enviar un solo byte de aplicación.
- Entrega fiable y ordenada: retransmite lo perdido, reordena lo desordenado.
- Control de congestión (slow start): arranca lento y acelera mientras no pierde paquetes. Una conexión recién abierta va más despacio que una establecida: otra razón para el keep-alive.
Coste total de abrir una conexión nueva contra ticketflow.app desde Europa a un servidor en Virginia:
| Salto | Coste típico |
|---|---|
| DNS (en caché / sin caché) | ~0 ms / 20-150 ms |
| TCP handshake | 1 RTT (~90 ms) |
| TLS 1.3 handshake | 1 RTT (~90 ms) |
| Primera respuesta HTTP | 1 RTT + tiempo del servidor |
Latencia total de la primera petición: ~270 ms + procesamiento. Con keep-alive y TLS reutilizado, las siguientes peticiones se quedan en ~RTT + servidor. Esto es la Lección 01 (keep-alive) vista desde el cable.
Clave: el ancho de banda importa para respuestas grandes (ficheros, vídeos). Para APIs JSON pequeñas, casi todo es latencia y número de peticiones. Optimizar la compresión de un JSON de 2 KB rinde menos que quitar una petición de la cadena.
4. Latencia: de qué se compone y cómo se mide
Latencia de una petición = DNS + conexión + TLS + transmisión + procesamiento del servidor + vuelta. Herramientas:
ping ticketflow.app # RTT a la máquina (ICMP; ignorado a veces)
curl -w '...' -o /dev/null URL # desglose por fases (lo haremos en ejercicios)
traceroute ticketflow.app # saltos de red hasta el destinoLa descomposición de curl que usarás siempre:
time_namelookup: DNS
time_connect: TCP (acumulado)
time_appconnect: TLS (acumulado)
time_starttransfer: primer byte (TTFB, acumulado)
time_total: fin de la respuesta (acumulado)Reglas de bolsillo:
- Luz en fibra: ~1 ms por cada 100 km de ida y vuelta aproxima bien entre regiones. Madrid-Virginia ~90 ms no es "tu código lento": es física.
- TTFB alto con DNS/TCP/TLS bajos = el servidor tarda: mira tu app (queries N+1, cola llena, GC).
- DNS lento = caché o resolver: no lo arregles optimizando Python.
5. Balanceadores de carga: repartir el trabajo
Con un solo servidor tienes un único punto de fallo y techo de capacidad. El balanceador recibe el tráfico y lo reparte entre varias instancias idénticas (¡tu app debe ser sin estado! Lección 27).
Algoritmos que debes saber nombrar:
| Algoritmo | Cómo reparte | Cuándo usarlo |
|---|---|---|
| Round robin | turno rotatorio | instancias iguales, casos generales |
| Least connections | al que menos conexiones activas tenga | peticiones de duración variable (tu caso: pagos largos) |
| IP hash / sticky | misma IP siempre al mismo backend | sesiones en memoria (a evitar: sesiones externas) |
| Weighted | por peso (máquina mayor pesa más) | despliegues canary o hardware mixto |
En el stack del curso: Nginx delante de 2+ workers de Gunicorn ya es un balanceador local; en producción, el balanceador lo pone la nube (ALB en AWS, Cloud Load Balancing en GCP) o Nginx/HAProxy en tu VM.
Dos decisiones de balanceador que la gente olvida:
- Terminación TLS: el certificado vive en el balanceador y descifra; hacia la app viaja plano en red privada (o mTLS si el compliance lo exige). Lo viste en la Lección 01, Ejercicio 8.
- Health checks: el balanceador pregunta
GET /api/health/a cada backend y saca del pool al que falla. Por eso el primer endpoint de la Lección 00 no era capricho.
6. Nginx como proxy inverso (tu caso concreto)
Arquitectura de TicketFlow en una VM:
Internet → Nginx (:80/:443) ─┬→ /api/ → Gunicorn (:8000) → Django
├→ /admin/→ Gunicorn
└→ /static/ → ficheros servidos por NginxConfiguración mínima (comentada en los ejercicios):
server {
listen 443 ssl;
server_name ticketflow.app;
ssl_certificate /etc/letsencrypt/live/ticketflow.app/fullchain.pem;
ssl_certificate_key /etc/letsencrypt/live/ticketflow.app/privkey.pem;
# Estáticos: Nginx es rápido sirviendo ficheros; Django ni los ve.
location /static/ {
alias /srv/ticketflow/static/;
expires 30d;
}
location / {
proxy_pass http://127.0.0.1:8000;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_read_timeout 60s;
}
}Por qué cada cabecera X-Forwarded-* existe: tu Django, detrás del proxy, vería como IP del cliente la del propio Nginx y como esquema http si no se lo dices. Con USE_X_FORWARDED_HOST y el middleware apropiado, Django reconstruye la verdad. Sin esto: paginación con URLs malas, CSRF gritando y logs de auditoría inútiles.
Nota fina:
proxy_read_timeoutpor defecto (60 s) mata respuestas largas. Una exportación de informe que tarda 3 minutos morirá con 504 aunque Django siga trabajando. La respuesta correcta es devolver 202 y procesar en cola (Lección 06), no subir el timeout a 10 minutos.
7. Diagnóstico: la pila de herramientas
| Síntoma | Herramienta | Qué mirar |
|---|---|---|
| "No resuelve" | dig +short dominio | registro, TTL, resolver usado |
| "No conecta" | curl -v | en qué fase se queda (DNS/TCP/TLS/HTTP) |
| "Va lento" | curl -w por fases | qué fase acumula el tiempo |
| "502 Bad Gateway" | Nginx error.log | Gunicorn caído o puerto equivocado |
| "504 Gateway Timeout" | proxy_read_timeout | petición más lenta que el timeout |
| "Conexiones colgadas" | ss -tan | estados CLOSE_WAIT/ESTAB anómalos |
La regla del oficio: localiza la fase antes de tocar nada. Cambiar código Python porque DNS tarda 300 ms es cómo no se arregla nada.
Autoevaluación (respóndeme en el chat)
- ¿Por qué bajar el TTL de DNS es el primer paso antes de una migración de IP y no después?
- Una petición tarda 400 ms; DNS 5 ms, TCP 90 ms, TLS 90 ms, TTFB 210 ms. ¿Dónde está el problema y qué mirarías?
- ¿Por qué "least connections" es mejor que "round robin" para TicketFlow, donde el POST de pago es más lento que un GET?
- ¿Qué rompe en Django si Nginx no envía
X-Forwarded-Proto https? Nombra dos síntomas. - ¿Qué endpoint de tu API es el health check del balanceador y por qué debe ser barato?
Continúa con los ejercicios. Las soluciones solo tras intentarlo.