La búsqueda de eficiencia en sistemas distribuidos, especialmente en cargas de trabajo de inferencia de IA, ha empujado los requisitos de latencia de milisegundos a microsegundos. Este cambio fundamental obliga a los arquitectos a reevaluar decisiones de diseño arraigadas, como la introducción de proxies, que, si bien resuelven problemas de escalabilidad y gestión de conexiones, pueden introducir sobrecargas de latencia y CPU, y puntos únicos de fallo. La historia de la NASA y el transbordador espacial sirve como analogía para ilustrar cómo los requisitos iniciales no cuestionados pueden llevar a arquitecturas complejas y costosas, mientras que una reevaluación rigurosa puede simplificar el diseño y mejorar drásticamente la eficiencia. En el contexto de sistemas de caching como Redis y Valkey, esto se traduce en una necesidad de pasar de arquitecturas proxied a modelos de acceso directo con clientes inteligentes para alcanzar la eficiencia deseada.

El problema fundamental de la computación que se aborda es cómo diseñar sistemas distribuidos de baja latencia y alto rendimiento que sean también rentables y resilientes. La explosión de la demanda de inferencia de modelos de Machine Learning, que requieren el acceso a cientos de 'features' en tiempo real con presupuestos de latencia muy ajustados (ej. 100ms para una predicción completa), ha hecho que las latencias de milisegundos en los componentes subyacentes ya no sean suficientes. Esto impulsa la necesidad de optimizar cada microsegundo en la cadena de procesamiento de datos, desde la red hasta la lógica de la aplicación y el kernel del sistema operativo.

Arquitectura del Sistema

La arquitectura de caching distribuido ha evolucionado desde nodos Redis/Valkey individuales hasta setups con sharding. Inicialmente, la escalabilidad se abordó mediante arquitecturas 'proxied' o 'gateway', donde un proxy (ej. Envoy) se interponía entre la aplicación cliente y múltiples nodos de caching. Este proxy era responsable de sharding (usando esquemas de hashing simples o integrándose con Redis Cluster), multiplexación de conexiones y abstracción de la topología del cluster para el cliente. La multiplexación de conexiones es crítica en escenarios de alta escala (ej. 100,000 pods cliente) para evitar sobrecargar los nodos de caching con un número excesivo de conexiones TCP.

Sin embargo, la introducción de un proxy añade dos saltos de red adicionales y una capa de procesamiento de CPU. Cada solicitud debe pasar por el proxy, que la reenvía al nodo de caching apropiado, y luego la respuesta sigue el camino inverso. Este doble I/O en el proxy consume una cantidad significativa de CPU (aproximadamente 45% en modo usuario y 45% en modo kernel para el manejo de la pila TCP/IP), convirtiéndose en un cuello de botella en términos de rendimiento y costo. Además, en una arquitectura proxied, un nodo de caching lento o fallido puede causar un 'head-of-line blocking' a nivel del pool de conexiones del cliente, llevando a una indisponibilidad total del sistema, incluso si la mayoría de los shards están saludables.

La alternativa propuesta es una arquitectura de 'acceso directo' con un 'smart client'. En este modelo, el cliente es consciente de la topología del cluster (dónde reside cada shard) y se conecta directamente a los nodos de caching. Esto elimina la capa de proxy, reduciendo los saltos de red y la sobrecarga de CPU. El cliente mantiene pools de conexiones separados para cada shard, implementando un patrón de 'bulkhead' que aísla los fallos: si un shard se ralentiza, solo las solicitudes a ese shard se ven afectadas, mientras que las solicitudes a otros shards continúan funcionando normalmente. Esta arquitectura mejora la latencia (eliminando los saltos del proxy), reduce el costo (menos instancias de proxy) y aumenta la resiliencia.

Flujo de Solicitud con Arquitectura Proxied

  1. 1 Cliente Envía solicitud GET/SET
  2. 2 Proxy (Envoy) Recibe solicitud, determina shard destino
  3. 3 Proxy (Envoy) Reenvía solicitud al nodo Valkey
  4. 4 Nodo Valkey Procesa solicitud y genera respuesta
  5. 5 Proxy (Envoy) Recibe respuesta del nodo Valkey
  6. 6 Proxy (Envoy) Reenvía respuesta al cliente
  7. 7 Cliente Recibe respuesta

Flujo de Solicitud con Arquitectura de Acceso Directo (Smart Client)

  1. 1 Smart Client Aprende topología del cluster Valkey
  2. 2 Smart Client Determina shard destino para la solicitud
  3. 3 Smart Client Envía solicitud GET/SET directamente al nodo Valkey
  4. 4 Nodo Valkey Procesa solicitud y genera respuesta
  5. 5 Smart Client Recibe respuesta
CapaTecnologíaJustificación
cache Redis Sistema de caching en memoria, base para la evolución de la arquitectura. vs Memcached
cache Valkey Fork de Redis, utilizado como sistema de caching en memoria para las pruebas de rendimiento y resiliencia. vs Redis
networking Envoy Proxy Proxy de capa 7 utilizado para sharding, multiplexación de conexiones y abstracción de la topología del cluster. vs HAProxy, Nginx, Twemproxy
compute EC2 (AWS) Infraestructura de máquinas virtuales para desplegar los componentes del sistema (clientes, proxies, servidores Valkey). vs GCP Compute Engine, Azure Virtual Machines Instancias Graviton de octava generación, 8-core, misma Availability Zone.

Trade-offs

Ganancias
  • ▲▲ Latencia P99
  • Costo por QPS
  • Resiliencia (aislamiento de fallos)
Costes
  • Complejidad del cliente
  • Gestión de conexiones (para el servidor)
local delay_ms = 5000
redis.call('DEBUG', 'SLEEP', delay_ms / 1000)
return 'OK'
Script Lua para simular lentitud en un nodo Valkey, forzando un retardo de 5 segundos en el procesamiento de comandos.

Fundamentos Teóricos

El problema de la latencia en sistemas distribuidos y la necesidad de optimizar cada microsegundo se relaciona con los principios fundamentales de la computación distribuida y la teoría de colas. El efecto de la 'tail latency' (latencia p99 o superior) en sistemas con fan-out paralelo o dependencias secuenciales es un concepto bien estudiado, donde el rendimiento del sistema se ve limitado por el componente más lento. Esto fue popularizado por trabajos como 'The Tail at Scale' de Jeff Dean y Luiz Barroso (2013), que describen cómo las latencias de cola se amplifican en sistemas con muchas dependencias, haciendo que incluso eventos raros de alta latencia se vuelvan comunes a escala de datacenter.

La decisión de adoptar un 'smart client' y eliminar una capa de proxy para reducir la latencia y mejorar la resiliencia se alinea con el principio de 'End-to-End Argument in System Design' de Saltzer, Reed y Clark (1984). Este argumento sugiere que ciertas funciones deben implementarse en las capas más altas de una aplicación (o en el cliente) si requieren conocimiento de la semántica de la aplicación, en lugar de ser implementadas en capas intermedias. En este caso, el conocimiento de la topología del cluster y la lógica de enrutamiento se mueven al cliente, permitiendo una optimización más directa y una mejor gestión de fallos que una capa de proxy genérica no puede proporcionar de manera tan eficiente. El patrón 'bulkhead' para el aislamiento de fallos es una aplicación práctica de principios de ingeniería de resiliencia, análogo a la compartimentación en la construcción naval para contener daños.