Latencia, throughput y percentiles | Nicolás Garzón
Rendimiento no significa únicamente “responder rápido”. Describe cuánto trabajo completa el sistema, cuánto tarda cada operación, qué recursos consume y cómo se degrada cuando la demanda se acerca a su capacidad.
Un sistema puede tener baja latencia con poca carga y colapsar cuando aumenta la concurrencia. También puede procesar muchas operaciones por segundo, pero ofrecer una experiencia lenta a cada usuario.
Por eso deben separarse varios conceptos:
Latencia: tiempo de una operación.
Throughput: operaciones completadas por unidad de tiempo.
Concurrencia: operaciones activas al mismo tiempo.
Utilización: proporción de capacidad ocupada.
Saturación: trabajo que espera porque un recurso llegó a su límite.
Capacidad: carga máxima sostenible bajo un objetivo de calidad.
Texto
Copiar llegadas
→ cola
→ recursos de ejecución
→ dependencias
→ respuestaEl tiempo total incluye espera y ejecución. Optimizar solo el código puede no cambiar nada si el cuello está en una cola, pool o dependencia externa.
Supón que un endpoint responde en 80 ms durante una prueba manual. En producción, p95 llega a 3 segundos.
La diferencia puede deberse a:
Pool de conexiones agotado.
Locks.
Garbage collection.
Caché fría.
Fan-out a dependencias.
CPU saturada.
Consultas con parámetros diferentes.
Retries.
Cola en el load balancer.
El promedio de 150 ms puede ocultar que una parte importante de usuarios espera varios segundos.
La latencia que percibe un usuario incluye más que el tiempo del servicio.
Texto
Copiar cliente
→ DNS y conexión
→ TLS
→ edge o gateway
→ cola
→ aplicación
→ base de datos
→ proveedor externo
→ serialización
→ red de vueltaCada capa necesita medición propia. Una traza permite atribuir tiempo, pero la métrica de experiencia debe conservar el total.
Texto
Copiar latencia total = espera + ejecuciónSi el código tarda 20 ms pero espera 500 ms por una conexión, optimizar la función no resuelve el problema.
Queue time.
Pool wait.
Lock wait.
CPU time.
I/O wait.
Downstream time.
Throughput mide trabajo completado, no solicitudes recibidas.
Requests por segundo.
Pedidos confirmados por minuto.
Mensajes procesados por segundo.
Filas migradas por hora.
La unidad debe representar valor o recurso relevante.
Un sistema puede aceptar 10.000 solicitudes/s y completar solo 5.000 mientras acumula cola. El throughput sostenible es 5.000, no 10.000.
Concurrencia es trabajo simultáneo.
Aumentarla puede elevar throughput mientras existen recursos libres. Después de cierto punto, produce:
Contention.
Más memoria.
Cambios de contexto.
Pools agotados.
Mayor tail latency.
Retries y timeouts.
No existe un número universal de workers. Debe corresponder a CPU, I/O, dependencias y límites externos.
L: trabajo promedio dentro del sistema.
λ: tasa de llegada o throughput.
W: tiempo promedio en el sistema.
Texto
Copiar 1.000 requests/s × 0,2 s = 200 requests concurrentesSi cada request mantiene una conexión de base, necesitarías capacidad cercana a 200 conexiones solo para esa carga, lo cual puede ser inviable. Esto motiva reducir tiempo, limitar concurrencia o compartir trabajo de forma distinta.
La ley aplica en estado estable. Si la cola crece indefinidamente, el sistema no está estable.
Cuando la utilización se acerca al 100 %, pequeñas variaciones generan grandes colas.
Texto
Copiar capacidad ociosa
→ absorbe variabilidad
capacidad casi llena
→ cualquier pico espera
→ timeout
→ retry
→ más cargaOperar permanentemente al máximo elimina margen para:
Picos.
Mantenimiento.
Failover.
Instancias lentas.
Backfills.
Retries.
La capacidad sostenible debe conservar headroom.
La latencia es una distribución.
La mitad de operaciones es igual o más rápida. Representa experiencia típica.
El 5 % es más lento. Muestra degradación frecuente y es útil para SLO.
Revela colas largas, pausas, locks y dependencias lentas.
Puede estar dominado por eventos raros, errores de medición o requests atascados. Sigue siendo útil para diagnóstico, pero no siempre para objetivos.
Texto
Copiar p50 = 80 ms
p95 = 250 ms
p99 = 2.500 msEl promedio podría ser 120 ms y ocultar un problema severo para 1 de cada 100 solicitudes.
Un request que llama muchas dependencias tiene mayor probabilidad de encontrar una lenta.
Si cada dependencia cumple 99 % bajo un umbral y necesitas 20 respuestas:
Texto
Copiar probabilidad aproximada de que todas cumplan = 0,99^20 ≈ 81,8 %Por eso el fan-out amplifica la cola.
Reducir dependencias críticas.
Paralelizar solo operaciones independientes.
Usar resultados parciales o degradación.
Cachear.
Precomputar.
Aplicar timeouts y presupuestos.
Un objetivo de extremo a extremo debe repartirse.
Texto
Copiar objetivo p95: 400 ms
├── edge y red: 50 ms
├── gateway: 20 ms
├── aplicación: 50 ms
├── base de datos: 100 ms
├── proveedor: 100 ms
└── margen: 80 msEl margen absorbe variabilidad y colas.
Si el timeout del proveedor es 5 segundos, no cabe dentro del presupuesto. La operación necesita un timeout menor, asincronía o cambio de UX.
Un timeout limita cuánto espera un componente. Debe ser:
Menor que el presupuesto superior.
Mayor que la latencia normal más variabilidad razonable.
Diferente por dependencia y operación.
Acompañado de semántica de error.
Un timeout no prueba que el downstream no completó la operación. Para escrituras, puede dejar resultado incierto.
Una prueba de carga puede ocultar saturación si el generador espera una respuesta antes de enviar la siguiente operación.
Cuando el sistema se vuelve lento, también disminuye artificialmente la tasa de envío y no registra solicitudes que deberían haber llegado.
Una prueba correcta mantiene el patrón de llegada esperado o contabiliza retrasos desde el tiempo programado, no solo desde el envío real.
Un número fijo de usuarios espera respuesta antes de repetir.
Apropiado para ciertos clientes interactivos.
Las llegadas ocurren a una tasa independiente de la respuesta.
Representa webhooks, tráfico agregado, eventos o picos donde nuevos requests continúan llegando.
Ambos modelos producen comportamientos diferentes bajo saturación.
Serialización, cifrado, compresión, regex, cálculos y garbage collection.
Objetos grandes, cachés, buffers, colas y fugas.
Queries, fsync, archivos, logs y swapping.
Distancia, payload, handshake, retransmisión y ancho de banda.
Scans, índices, locks, conexiones, sorts y transacciones.
Rate limits, latencia variable, errores y ventanas de mantenimiento.
Locks, recursos globales, filas calientes y estructuras compartidas.
El cuello limita throughput. Aumentar otros recursos no ayuda.
Texto
Copiar 20 instancias de aplicación
→ base soporta 2.000 writes/s
→ capacidad total sigue cerca de 2.000 writes/sEscalar horizontalmente la aplicación puede incluso empeorar al abrir más conexiones y competir por locks.
Al aumentar concurrencia, dos fuerzas limitan escala:
Contention por recursos compartidos.
Coherencia o coordinación entre participantes.
El objetivo no es memorizar una fórmula, sino reconocer que duplicar workers rara vez duplica throughput indefinidamente.
Backpressure evita aceptar trabajo más rápido de lo que puede procesarse.
Cola acotada.
Límite de concurrencia.
Rate limiting.
Rechazo temprano.
Pausa de consumidores.
Ventanas de crédito.
Respuestas 429 o 503 con retry policy.
Sin backpressure, la cola se mueve a memoria, conexiones o timeouts y el sistema falla de forma menos controlada.
Cuando no puede procesarse todo, se rechaza trabajo para preservar lo importante.
Desactivar recomendaciones.
Rechazar reportes pesados.
Limitar tenants ruidosos.
Mantener pagos y pedidos mientras se degrada analítica.
La prioridad debe definirse antes del incidente.
Agrupar operaciones reduce overhead por llamada y mejora throughput.
Texto
Copiar 100 inserts individuales
→ 100 round trips
1 batch de 100
→ 1 o pocos round trips
Mayor latencia para el primer elemento.
Memoria.
Errores parciales.
Tamaño máximo.
Necesidad de flush por tiempo o cantidad.
Operaciones independientes pueden ejecutarse en paralelo.
Texto
Copiar secuencial: 40 + 60 + 90 = 190 ms
paralelo: aproximadamente max(40, 60, 90) = 90 ms + overheadPero aumenta carga simultánea. Si todos los requests hacen fan-out paralelo, una dependencia puede saturarse.
Reduce trabajo repetido y latencia, pero introduce:
Staleness.
Invalidación.
Stampede.
Memoria.
Complejidad de claves.
Debe diseñarse según semántica, no como parche genérico.
Se envía una segunda solicitud si la primera supera cierto umbral.
Puede reducir tail latency en lecturas idempotentes, pero aumenta carga. Bajo saturación puede empeorar el incidente.
Necesita límite, cancelación y selección cuidadosa.
Texto
Copiar p95 < 300 ms
1.000 requests/s
catálogo público por tenant
Gateway valida límites.
Aplicación consulta productos.
Base filtra por tenant, categoría y estado.
Se serializan 100 elementos.
120 ms esperando conexión.
80 ms query.
30 ms serialización.
20 ms red.
La mayor mejora puede ser limitar pool y optimizar concurrencia, no solo añadir índice.
Índice compuesto reduce query a 20 ms.
Paginación reduce payload.
Caché de categoría frecuente evita consultas.
CDN sirve catálogo público con TTL breve.
Cada cambio debe medir p50, p95, hit ratio, staleness y carga de origen.
No todo debe optimizarse igual.
El flujo de confirmación puede priorizar integridad sobre latencia mínima.
Texto
Copiar validación
→ reserva atómica
→ guardar pedido y outbox
→ commit
→ respuesta confirmedEnviar correo y generar analítica ocurre después. Sacar efectos secundarios de la ruta crítica reduce latencia sin comprometer la transacción.
Objetivo.
Patrón de llegada.
Distribución de endpoints.
Datos y tenants representativos.
Warm-up.
Duración suficiente.
Fallos y dependencias.
Criterio de saturación.
Percentiles.
Error rate.
Recursos.
Recuperación después de la carga.
No concluyas a partir de una prueba corta con caché caliente y un único tipo de request.
La capacidad no es el punto antes del crash. Es la carga que cumple SLO con margen.
Texto
Copiar máximo observado: 8.000 requests/s
capacidad sostenible con p95 y headroom: 5.500 requests/sPlanifica failover: si pierdes una zona, las restantes deben absorber tráfico sin superar su capacidad sostenible.
Utilization.
Saturation.
Errors.
Pool wait.
Queue depth.
Lock wait.
GC pause.
Cache hit/miss.
Replica lag.
Dependency latency.
Payload size.
Correlaciona recursos con flujo de negocio, no solo con host.
El origen recibe un pico. Usa warm-up, stale-while-revalidate o límites.
Timeouts disparan reintentos que elevan carga. Aplica budgets, jitter y circuit breaker.
Un cliente consume pools compartidos. Añade cuotas, particiones o prioridades.
La query es rápida, pero serialización y red dominan. Pagina, comprime o reduce campos.
La mitad de capacidad desaparece. Verifica headroom y autoscaling real, no solo nominal.
Backfill o reporte satura I/O. Throttle y separa pools.
Oculta tail latency. Usa distribuciones.
Los cuellos aparecen con concurrencia y datos reales.
Convierte fallos rápidos en colas largas y consume recursos.
Más aplicaciones no resuelven base, proveedor o lock global.
Crear instancias tarda y las dependencias pueden no escalar.
La cola infinita solo pospone el fallo y aumenta latencia.
Reduce tiempo local mientras satura downstream.
Confirmar impacto y percentiles.
Separar error, cola y ejecución.
Revisar saturación de recursos.
Identificar dependencia dominante con trazas.
Comparar cambio reciente y distribución por tenant/endpoint.
Aplicar mitigación: shed, límite, rollback o degradación.
Verificar recuperación y cola acumulada.
Corregir capacidad o diseño con evidencia.
SLO incumplido.
Costo significativo.
Capacidad cercana al límite.
Flujo crítico bloqueado.
Evidencia de cuello.
No sacrifiques claridad por microoptimizaciones sin impacto.
Latencia, throughput y concurrencia no son equivalentes.
La espera forma parte del tiempo total.
Los percentiles muestran la distribución que el promedio oculta.
Cerca de saturación, la latencia crece de forma no lineal.
Cada request necesita presupuesto de latencia.
Backpressure y load shedding preservan estabilidad.
La capacidad debe medirse con SLO y headroom.
Optimiza el cuello demostrado.
¿Por qué más conexiones de base pueden reducir throughput?
¿Qué revela p99 que puede ocultar p50?
¿Cómo puede el batching mejorar throughput y empeorar latencia?
¿Qué diferencia existe entre cola y ejecución?
¿Por qué autoscaling de aplicación no resuelve cualquier saturación?
Ver respuestas orientativas
Porque aumentan contention, memoria y carga sobre un recurso finito.
Pausas, locks, dependencias lentas y saturación que afectan la cola.
Amortiza overhead, pero espera a acumular elementos antes de procesar.
La cola es tiempo esperando recurso; ejecución es tiempo haciendo trabajo.
Porque el cuello puede estar en base, proveedor, red o coordinación compartida.
Caching y CDN profundiza en cómo reutilizar resultados para reducir latencia y carga sin perder control sobre frescura, autorización e invalidación.