wandres.dev
EL EDGE Y LA CDN · Acercar el byte al usuario

La geografía de la latencia: por qué la distancia manda

Cuánto tarda un bit en cruzar el mundo, cuántas idas y vueltas hay antes del primer byte, la regla de los primeros catorce kilobytes, y qué acerca de verdad un nodo de borde.

⏱ 18 min

Una red de distribución no hace nada más rápido. Lo único que hace es poner los bytes más cerca, y eso importa porque la latencia es el único componente del presupuesto de rendimiento que no ha mejorado en veinte años y no va a mejorar: está limitada por la velocidad de la luz en un trozo de vidrio. Entender la aritmética de las idas y vueltas es lo que permite decidir qué merece la pena mover al borde y qué es teatro.

🎯 Al terminar esta lección sabrás
  • Calcular el tiempo mínimo teórico de una ida y vuelta a partir de la distancia.
  • Contar las idas y vueltas que hay antes del primer byte de una respuesta según el protocolo.
  • Explicar la regla de los primeros catorce kilobytes y su origen.
  • Medir el desglose real de conexión de tu propio sitio con Resource Timing.

La física

La luz viaja a unos 300.000 kilómetros por segundo en el vacío. En una fibra óptica, con un índice de refracción de aproximadamente 1,5, va a unos 200.000. Eso son cinco microsegundos por kilómetro en un sentido, diez por kilómetro de ida y vuelta.

Con esa constante se calcula el suelo teórico de cualquier conexión:

Trayecto Distancia aproximada Ida y vuelta mínima Ida y vuelta real típica
Madrid – Madrid 10 km 0,1 ms 2–5 ms
Madrid – Fráncfort 1.400 km 14 ms 25–35 ms
Madrid – Nueva York 5.700 km 57 ms 85–110 ms
Madrid – São Paulo 8.400 km 84 ms 130–170 ms
Madrid – Sídney 17.600 km 176 ms 280–330 ms

La diferencia entre el mínimo teórico y el real tiene dos causas. La fibra no va en línea recta: sigue cables submarinos y corredores terrestres, y el recorrido efectivo suele ser entre 1,5 y 2 veces la distancia en línea recta. Y en cada salto hay equipos que procesan, encolan y conmutan, lo que añade microsegundos que se acumulan.

Ninguna de las dos va a mejorar de forma significativa. El ancho de banda se multiplica cada pocos años; la latencia está a un factor pequeño de un límite físico duro. Esa asimetría es el hecho estructural más importante del rendimiento de red, y de ella se deducen casi todas las decisiones correctas.

En móvil hay que añadir la latencia del primer salto, el que va del dispositivo a la estación base y de ahí a la red fija. En 4G son típicamente entre 30 y 50 milisegundos, y en 5G menos pero con mucha variabilidad. Es decir, para un usuario móvil, incluso un servidor en la misma ciudad está a cuarenta milisegundos.

Cuántas idas y vueltas antes del primer byte

Contar idas y vueltas es la forma correcta de razonar sobre esto, porque cada una cuesta la latencia completa del trayecto.

Con TCP y TLS 1.3:

  1. Resolución de nombre, si no está en caché: una ida y vuelta al resolutor.
  2. Apretón de manos de TCP: una ida y vuelta.
  3. Apretón de manos de TLS 1.3: una ida y vuelta.
  4. Petición y primer byte de respuesta: una ida y vuelta.

Total: tres idas y vueltas con el nombre ya resuelto. A 100 ms cada una son 300 ms antes del primer byte de un fichero estático. Desde un nodo a 10 ms, son 30 ms. Diez veces mejor sin haber cambiado nada del contenido.

Con QUIC: el establecimiento de conexión y el criptográfico van juntos, así que son dos idas y vueltas en vez de tres en conexión nueva, y una sola con reanudación de sesión, gracias al modo de cero idas y vueltas. Con una salvedad que conviene conocer: los datos enviados en la primera ida y vuelta no tienen protección contra repetición, así que solo deben usarse para peticiones idempotentes.

Con conexión ya abierta: una sola ida y vuelta. De ahí el valor de preconnect para orígenes que sabes que vas a usar, y de ahí que reducir el número de orígenes distintos sea una optimización real: cada origen nuevo son dos o tres idas y vueltas de establecimiento.

Mídelo en tu sitio, no lo estimes:

function desgloseDeConexion(filtro = '') {
  return performance
    .getEntriesByType('resource')
    .filter((r) => r.name.includes(filtro))
    .map((r) => ({
      recurso: new URL(r.name).pathname.slice(0, 40),
      protocolo: r.nextHopProtocol || 'oculto',
      dns: Math.round(r.domainLookupEnd - r.domainLookupStart),
      tcp: Math.round(r.connectEnd - r.connectStart),
      tls: r.secureConnectionStart
        ? Math.round(r.connectEnd - r.secureConnectionStart)
        : 0,
      espera: Math.round(r.responseStart - r.requestStart),
      descarga: Math.round(r.responseEnd - r.responseStart),
      bytes: r.encodedBodySize,
    }));
}

console.table(desgloseDeConexion());

Un aviso sobre este código: para recursos de otro origen, los campos de tiempo detallados y nextHopProtocol vienen a cero salvo que ese origen envíe la cabecera Timing-Allow-Origin. Si ves ceros en los recursos de tu CDN de imágenes, no es que sean instantáneos: es que no te dejan mirar. Pedir esa cabecera a tus proveedores es de las cosas más rentables que puedes hacer por tu capacidad de diagnóstico.

Los primeros catorce kilobytes

Hay un número mágico que conviene conocer porque explica un salto discontinuo en el comportamiento de las páginas pequeñas.

TCP no empieza a enviar a máxima velocidad: arranca con una ventana de congestión pequeña y la va aumentando a medida que confirma que la red aguanta. El valor inicial estandarizado son diez segmentos. Con un tamaño máximo de segmento de 1.460 bytes, eso son unos 14,6 kilobytes que se pueden enviar en la primera ida y vuelta sin esperar confirmación.

La consecuencia práctica: si tu documento HTML comprimido cabe en esos catorce kilobytes, llega entero en la primera ida y vuelta. Si ocupa quince, la parte que sobra necesita una ida y vuelta más, que a 100 ms de distancia son 100 ms de retraso por un kilobyte. Es el ejemplo más limpio que existe de por qué contar idas y vueltas es más útil que contar bytes.

De aquí sale una técnica concreta y a menudo rentable: meter en esos primeros catorce kilobytes el HTML de la parte visible más el CSS crítico en línea, y dejar todo lo demás para después. Y de aquí sale también la razón de que el streaming del nivel anterior sea tan eficaz: el primer trozo que envías, si es pequeño, viaja en esa primera ventana.

Dos matices honestos. El valor inicial de la ventana lo puede ajustar el servidor y algunos proveedores usan valores mayores. Y con QUIC el mecanismo es equivalente pero los detalles difieren. El orden de magnitud —una decena de kilobytes en la primera ida y vuelta— se mantiene.

Qué acerca un nodo de borde y qué no

Acerca los bytes estáticos. Un fichero cacheado en un nodo cercano se sirve en una ida y vuelta corta. Es el caso ideal y el que justifica el noventa por ciento del valor de una red de distribución.

Acerca el establecimiento de conexión, siempre. Aunque la respuesta tenga que ir al origen, la conexión TLS del usuario termina en el nodo cercano, y del nodo al origen suele haber una conexión ya establecida y reutilizada, por rutas optimizadas. Es decir, incluso una petición que no acierta en caché se beneficia: en vez de tres idas y vueltas largas más el trabajo del origen, tienes tres idas y vueltas cortas más una larga. Esto se suele pasar por alto y es un ahorro considerable.

No acerca los datos. Si la respuesta depende de una consulta a una base de datos que está en otro continente, el nodo de borde no puede hacer nada. Es más: si además mueves ahí el cómputo, puedes empeorarlo, y ese es el asunto de el cómputo en el edge.

No acerca lo que no puede cachear. Una respuesta con Cache-Control: private o con una clave de caché que incluye el identificador de sesión no se cachea nunca, y el nodo se limita a hacer de intermediario. Qué se puede cachear y cómo se decide es la siguiente lección.

El ancho de banda mejora exponencialmente y la latencia no mejora nunca: toda decisión que cambie idas y vueltas por bytes gana con el tiempo

Esta es la observación que hay que llevarse del nivel entero, porque no caduca. Desde que existe la web comercial, el ancho de banda típico de un usuario se ha multiplicado por varios órdenes de magnitud, y va a seguir creciendo. La latencia, en el mismo periodo, ha mejorado modestamente por mejoras de encaminamiento y de protocolo, y no puede mejorar mucho más porque está a un factor pequeño de un límite físico: la velocidad de la luz en vidrio. No hay avance tecnológico posible que reduzca a la mitad el tiempo de Madrid a Sídney, salvo cambiar el medio o la ruta, y las dos cosas son proyectos de infraestructura de miles de millones con ganancias de un dígito. Toma esa asimetría en serio y clasifica cualquier decisión de arquitectura según qué recurso consume. Juntar varios ficheros en uno cambia idas y vueltas por bytes: gana. Poner el CSS crítico en línea, aunque duplique unos kilobytes: gana. Incluir una imagen pequeña como datos en el HTML en vez de pedirla aparte: gana. Comprimir mucho más agresivamente a costa de más CPU en el servidor: neutro o gana. Y al revés: dividir el paquete en veinte trozos que se piden en cascada cambia bytes por idas y vueltas y pierde, aunque el total descargado sea menor. Renderizar en el cliente y luego pedir datos a una API introduce una ida y vuelta más en el camino crítico y pierde. Una cascada de peticiones donde cada una depende de la anterior es el peor patrón posible, porque multiplica el recurso que no mejora. La consecuencia menos evidente y más valiosa es esta: las optimizaciones que ahorran bytes envejecen mal y las que ahorran idas y vueltas envejecen bien. Aquella técnica de 2012 para exprimir cada kilobyte del JavaScript importa menos cada año que pasa; la de reducir el número de peticiones en cascada importa exactamente lo mismo que entonces y seguirá importando en 2040. Cuando tengas que priorizar una lista de mejoras de rendimiento y no sepas por dónde empezar, ordena por cuántas idas y vueltas elimina cada una. Es un criterio que casi nunca se equivoca.

⚔️ Mide tu geografía
  1. Ejecuta el desglose de conexión en tu sitio desde tu ubicación y desde un servicio de pruebas en otro continente. Compara la columna de espera.
  2. Cuenta cuántos orígenes distintos usa tu página. Multiplica por dos idas y vueltas y calcula el coste de establecimiento total.
  3. Mide el tamaño comprimido de tu documento HTML y compáralo con catorce kilobytes.
  4. Comprueba qué recursos de terceros no envían Timing-Allow-Origin y pide la cabecera a esos proveedores.
  5. Localiza la cascada de peticiones más profunda de tu carga y cuenta sus niveles. Cada nivel es una ida y vuelta.