Detrás de cada viaje de Uber, cada pedido de comida y cada operación logística, existe una infraestructura de datos masiva y sofisticada. No se trata de una única base de datos simple, sino de un ecosistema complejo diseñado para manejar petabytes de datos y decenas de millones de solicitudes por segundo, garantizando baja latencia, alta disponibilidad y escalabilidad.

La espina dorsal de esta infraestructura es una flota gigantesca de MySQL. Uber opera más de 2,300 clústeres independientes de MySQL, una escala que presenta desafíos operativos enormes. Gestionar una flota de este tamaño, asegurando cero tiempo de inactividad y sin pérdida de datos, requiere un plano de control altamente avanzado.
El plano de control de MySQL en Uber es un sistema basado en estados que orquesta la provisión, mantenimiento y desmantelamiento de clústeres y nodos. Su componente central es el gestor de tecnología, que interactúa con Odin, la plataforma interna de Uber para gestionar tecnologías con estado. Este gestor publica el 'estado objetivo' o deseado del clúster (configuraciones, número de nodos, roles, ajustes de servidor, etc.) a Odin, asegurando que el estado real del clúster converja siempre hacia el deseado. Además, facilita cambios de estado a través de flujos de trabajo tolerantes a fallos, impulsados por Cadence.
- Operaciones Críticas en la Gestión de MySQL
- Docstore: Una Capa Adicional para Escalar Escrituras y Lecturas
- CacheFront: La Solución de Caching Integrado
- Otras Características Avanzadas de CacheFront
- Más Allá de MySQL y Docstore
- Evolución Arquitectónica: Monolito a Microservicios a DOMA
- ¿Por Qué Tantos Sistemas de Datos?
- Preguntas Frecuentes
Operaciones Críticas en la Gestión de MySQL
La complejidad de operar MySQL a esta escala se manifiesta en la automatización de operaciones críticas:
- Failover Primario: En una configuración de primario único y múltiples réplicas, mantener el nodo primario saludable es vital para la alta disponibilidad de escritura. Uber automatiza el proceso de cambio de nodo primario. Existen dos tipos: 'graceful' (elegante) para mantenimiento planificado, donde se transfiere la carga de escritura suavemente, y 'emergency' (emergencia) cuando el primario actual no está disponible, asumiendo que es inalcanzable. Este proceso es fundamental para cumplir con los acuerdos de nivel de servicio (SLA) de 99.99% de disponibilidad.
- Reemplazo de Nodo: Mover un nodo MySQL (y sus datos) de un host a otro sin afectar a los usuarios es una operación compleja. El flujo de trabajo de reemplazo gestiona la adición de un nuevo nodo (encontrando un host con recursos idénticos, sincronizando datos) y la eliminación elegante del nodo antiguo, asegurando que las dependencias (como la replicación) se manejen correctamente y que el rendimiento no se degrade.
- Cambios de Esquema: La automatización de cambios de esquema se realiza a través de un flujo de trabajo de auto-servicio. Utiliza herramientas como MySQL's instant alter o Percona pt-online-schema-change para realizar actualizaciones seguras y sin bloqueo en el nodo primario. El flujo de trabajo selecciona la estrategia adecuada según el tipo de cambio y el tamaño de los datos, e incluso permite una 'ejecución en seco' en una réplica aislada para verificar la compatibilidad antes de aplicarlo a todo el clúster. Este proceso está integrado con las tuberías CI/CD de Uber, alineando el código desplegado con el esquema de la base de datos.
El plano de datos de un nodo MySQL en Uber no es solo el proceso mysqld. Corre dentro de contenedores Docker y está acompañado por otros contenedores auxiliares: un contenedor trabajador (alinea el estado real con el objetivo), un contenedor de métricas (recopila señales de rendimiento), un probador de salud (monitorea el proceso MySQL) y un contenedor efímero de respaldo.
El plano de descubrimiento o enrutamiento simplifica la interacción del cliente, proporcionando una IP virtual única a la que los servicios se conectan. Un proxy inverso actúa como balanceador de carga, dirigiendo las escrituras al primario y balanceando las lecturas entre las réplicas, priorizando las de la misma región geográfica. Este plano utiliza un almacén de topología basado en etcd para mantener configuraciones actualizadas y propagar cambios.
Docstore: Una Capa Adicional para Escalar Escrituras y Lecturas
Aunque MySQL es robusto, las aplicaciones modernas exigen latencias muy bajas y un rendimiento extremadamente alto, especialmente para las lecturas. Aquí es donde entra Docstore. Docstore es una base de datos distribuida interna de Uber, construida *sobre* MySQL. Almacena decenas de petabytes de datos y atiende decenas de millones de peticiones por segundo. Fue diseñado para manejar cargas de trabajo pesadas, respaldado por SSDs NVMe.
Sin embargo, incluso Docstore basado en disco enfrentaba desafíos con casos de uso que requerían un rendimiento de lectura *mucho* mayor. La optimización del modelo de datos tiene límites, la escalabilidad vertical es costosa y limitada, y la escalabilidad horizontal (división de shards) es compleja y no resuelve problemas de 'hot keys' (claves calientes) o 'hot partitions' (particiones calientes). Además, el desequilibrio entre lecturas y escrituras (muchas más lecturas) sobrecargaba los nodos MySQL subyacentes, impactando las latencias.
CacheFront: La Solución de Caching Integrado
Para superar estos desafíos y reducir la carga sobre el motor de almacenamiento, Uber desarrolló CacheFront, una solución de caching integrado para Docstore, utilizando Redis como capa de cache distribuida. El objetivo era minimizar la necesidad de escalar vertical u horizontalmente el almacenamiento, mejorar las latencias P50 y P99, estabilizar los picos de latencia y reemplazar las soluciones de caching personalizadas que los equipos individuales tenían que construir y mantener.

CacheFront opera en la capa del motor de consultas de Docstore, desacoplando el caché del almacenamiento basado en disco y permitiendo que ambos escalen independientemente. Utiliza una estrategia de 'cache aside'. Cuando llega una solicitud de lectura:
- El motor de consultas intenta obtener los datos de Redis.
- Si están en el caché, se devuelven rápidamente.
- Si no están (cache miss), se recuperan del motor de almacenamiento (MySQL subyacente).
- Los datos recuperados se devuelven al usuario y, *asincrónicamente*, se escriben en Redis para futuras solicitudes (populating the cache).
Una de las mayores complejidades del caching es la invalidación. Sin una invalidación explícita, las entradas del caché expirarían según su TTL (por defecto, 5 minutos), lo cual no es aceptable para muchos usuarios que esperan que los cambios se reflejen rápidamente. Reducir el TTL impactaría negativamente la tasa de aciertos del caché.
Para resolver esto, CacheFront aprovecha el servicio de captura de datos cambiados (CDC) de Docstore, llamado Flux. Flux rastrea los eventos del binlog de MySQL y los publica a los consumidores. Un nuevo consumidor de Flux fue desarrollado para suscribirse a estos eventos y, basándose en ellos, invalidar o actualizar las entradas correspondientes en Redis. Esto permite que el caché sea consistente con la base de datos en cuestión de segundos, en lugar de minutos. Además, el uso de binlogs asegura que solo los datos de transacciones confirmadas se reflejen en el caché.
Para evitar escribir datos antiguos en el caché debido a escrituras simultáneas (una desde la ruta de lectura tras un 'miss' y otra desde la ruta de escritura/invalidación), CacheFront implementa deduplicación de escrituras basada en la marca de tiempo de la fila, utilizando scripts Lua atómicos en Redis.
Aunque Flux proporciona consistencia eventual, algunos casos de uso requieren una consistencia más fuerte (como leer las propias escrituras). Para estos escenarios, Uber añadió una API dedicada que permite a los usuarios invalidar explícitamente las filas cacheadas después de que las escrituras correspondientes hayan completado. Esto proporciona garantías de consistencia más fuertes para escrituras puntuales.
Otras Características Avanzadas de CacheFront
- Compare Cache: Un modo especial para verificar la consistencia entre el caché y la base de datos en tiempo real, registrando y emitiendo métricas sobre cualquier discrepancia.
- Cache Warming (Calentamiento): Para asegurar la alta disponibilidad entre regiones geográficas activas-activas, CacheFront replica las *claves* de Redis a la región remota. En lugar de actualizar directamente el caché remoto, se emiten solicitudes de lectura para esas claves. Si hay un 'cache miss' en la región remota, la solicitud va a la base de datos (que ya está replicada entre regiones), se recupera el dato y se escribe en el caché local de esa región. Esto mantiene el mismo conjunto de trabajo cacheado en ambas regiones sin replicar los valores de datos directamente y potencialmente inconsistentes.
- Negative Caching: Para lecturas frecuentes de filas inexistentes, CacheFront cachea el resultado negativo con un flag especial. En futuras lecturas, si se encuentra el flag, se evita consultar la base de datos, mejorando el rendimiento para consultas de datos no presentes.
- Sharding de Redis: Para manejar clientes muy grandes, una única instancia de Docstore puede mapear a múltiples clústeres de Redis. Estos clústeres de Redis se dividen por la clave de partición de Docstore (que puede ser diferente del esquema de sharding de la base de datos subyacente). Esto evita que un solo clúster de Redis caído sobrecargue un único shard de la base de datos, distribuyendo la carga entre todos los shards de la base de datos.
- Circuit Breakers y Adaptive Timeouts: Mecanismos para manejar fallos de nodos de Redis y optimizar los tiempos de espera de las solicitudes de caché, mejorando la latencia y la resiliencia.
Los resultados de CacheFront han sido significativos. Las latencias de solicitud son mucho mejores (P75 con una reducción del 75%, P99.9 con una reducción del 67%). Ha permitido a Uber manejar casos de uso a gran escala (más de 6M RPS con una tasa de aciertos del 99%) que de otro modo requerirían una capacidad de base de datos mucho mayor y más costosa. Actualmente, CacheFront soporta más de 40M solicitudes por segundo en producción.
Más Allá de MySQL y Docstore
El ecosistema de datos de Uber incluye otros sistemas especializados:
- Elasticsearch: Utilizado para búsqueda y posiblemente para almacenar y procesar logs (parte de la suite ELK mencionada en un contexto genérico).
- Cassandra: Mencionado como parte de la plataforma de Machine Learning (Michelangelo).
- Riak y DynamoDB: Mencionados en el contexto de Ringpop para sistemas distribuidos cooperativos en tiempo real, aunque su rol exacto como almacenes primarios no está detallado.
- Plataforma de Datos y ML: Uber utiliza Apache Kafka para streaming de datos (captura de cambios vía Storagetapper). Los datos se ingieren en un data warehouse basado en Apache Hive y HDFS. La plataforma de ML, Michelangelo, utiliza una mezcla de sistemas open-source (HDFS, Samza, Spark, TensorFlow, XGBoost) y componentes internos.
Evolución Arquitectónica: Monolito a Microservicios a DOMA
La infraestructura de datos de Uber ha evolucionado en paralelo con su arquitectura de software. Comenzó con una arquitectura monolítica, utilizando una única base de datos y servidores de aplicación. A medida que creció, esto se volvió un cuello de botella para la velocidad de desarrollo y el riesgo de despliegue. Esto llevó a la adopción de una arquitectura de Microservicios alrededor de 2014, donde la funcionalidad se divide en servicios más pequeños e independientes.
Posteriormente, evolucionaron hacia una Arquitectura de Sistemas Orientada a Dominios (DOMA - Domain-Oriented System Architecture). Bajo DOMA, los microservicios se organizan en colecciones lógicas llamadas dominios, que a su vez se clasifican en capas. Cada dominio es independiente y se comunica a través de Gateways API, lo que mejora la organización y la gestionabilidad a escala.
Esta evolución arquitectónica influye directamente en la estrategia de datos. Con microservicios, es común que diferentes servicios utilicen las bases de datos o almacenes de datos más adecuados para sus necesidades específicas, lo que explica la diversidad de tecnologías de datos en Uber (políglota persistencia).

¿Por Qué Tantos Sistemas de Datos?
La razón principal detrás de la compleja infraestructura de datos de Uber es la necesidad de satisfacer requisitos muy diversos y exigentes a una escala masiva. Ningún sistema de base de datos único puede proporcionar simultáneamente la durabilidad y consistencia de una base de datos relacional para transacciones críticas, la baja latencia de un caché en memoria para lecturas frecuentes, la escalabilidad horizontal de un almacén de documentos distribuido y las capacidades analíticas de un data warehouse. Al utilizar una combinación de sistemas, cada uno optimizado para un propósito específico (MySQL para la base transaccional, Docstore/CacheFront/Redis para escalabilidad de lectura/escritura y baja latencia, Kafka para streaming, Hive/HDFS para analítica, Elasticsearch para búsqueda, etc.), Uber puede construir una plataforma robusta, escalable y de alto rendimiento.
| Sistema | Tipo Principal | Uso Principal en Uber | Características Clave |
|---|---|---|---|
| MySQL | Relacional | Base de datos transaccional, espina dorsal de la infraestructura | Alta disponibilidad (gestión compleja del plano de control), replicación, transacciones ACID (base para Docstore) |
| Docstore | Distribuido (sobre MySQL) | Base de datos para alto rendimiento y escala (lecturas/escrituras) | Construido in-house, distribuido, utiliza MySQL subyacente, resuelve desafíos de escala del disco |
| Redis | Clave-Valor (en memoria) | Capa de caching para baja latencia | Utilizado por CacheFront, rápido, soporta estructuras de datos variadas, alta concurrencia |
| Elasticsearch | Documental (Search Engine) | Búsqueda, posiblemente logs y analítica | Indexación rápida, consultas complejas, escalabilidad horizontal |
| Cassandra | Columna amplia distribuida | Parte de la plataforma de Machine Learning | Alta escalabilidad, disponibilidad, rendimiento de escritura |
| Apache Kafka | Streaming de eventos | Captura y procesamiento de cambios de datos (CDC), comunicación entre servicios | Alta throughput, tolerancia a fallos, procesamiento en tiempo real |
| Apache Hive / HDFS | Data Warehouse / File System Distribuido | Data Lake, analítica, procesamiento de big data | Almacenamiento masivo, consultas SQL sobre datos estructurados/semiestructurados |
Preguntas Frecuentes
P: ¿Uber utiliza solo MySQL?
R: No. Aunque MySQL es la base de su infraestructura transaccional principal, Uber utiliza un amplio abanico de tecnologías de datos, incluyendo Docstore (construido sobre MySQL), Redis para caching, Elasticsearch para búsqueda, Cassandra para ML, y sistemas como Kafka, Hive y HDFS para procesamiento de datos y analítica.
P: ¿Cómo maneja Uber las enormes cargas de lectura?
R: Principalmente a través de CacheFront, una capa de caching integrado que utiliza Redis. Las solicitudes de lectura se atienden primero desde el caché en memoria, que es mucho más rápido que acceder al disco. Un sistema sofisticado de invalidación basado en la captura de cambios de datos (CDC) mantiene el caché actualizado.
P: ¿Qué es Docstore?
R: Docstore es una base de datos distribuida interna de Uber construida sobre MySQL. Está diseñada para manejar cargas de trabajo muy altas y grandes volúmenes de datos que exceden las capacidades de escalar solo MySQL.
P: ¿Cómo asegura Uber la consistencia entre el caché (Redis) y la base de datos (MySQL)?
R: Utilizan un sistema de invalidación basado en Change Data Capture (CDC) que rastrea los cambios en MySQL binlogs y actualiza o invalida las entradas correspondientes en Redis casi en tiempo real. También tienen mecanismos para manejar escrituras simultáneas y ofrecer consistencia más fuerte para casos de uso específicos.
P: ¿Por qué Uber pasó de una arquitectura monolítica a microservicios y DOMA?
R: Para mejorar la velocidad de desarrollo, la escalabilidad, la resiliencia y la capacidad de gestionar la complejidad de su plataforma a medida que crecía. Cada arquitectura sucesiva (Microservicios, DOMA) ofreció mejor aislamiento y organización para manejar un sistema masivo con múltiples equipos trabajando en paralelo.
La infraestructura de datos de Uber es un testimonio de cómo la ingeniería a gran escala resuelve problemas de rendimiento, escalabilidad y disponibilidad en un entorno de alta demanda. La combinación de bases de datos relacionales, almacenes NoSQL, sistemas de caching distribuido, plataformas de streaming y data lakes, todo gestionado por sofisticados planos de control y arquitecturas de microservicios/dominios, es clave para su operación global.
Si quieres conocer otros artículos parecidos a La Infraestructura de Datos de Uber al Descubierto puedes visitar la categoría Bases de datos.

Aprende mas sobre MySQL