OpenAIPublicación de la fuente

Escalado rápido del almacenamiento en línea para servir a más de 1 mil millones de usuarios de ChatGPT (Parte II)

Todos los productos de OpenAI requieren un acceso rápido y confiable a los datos, proporcionado por nuestra plataforma de almacenamiento, Habitat. Tiene que responder en milisegundos a más de 1 mil millones de usuarios en 40 regiones geográficas.

Todos los productos de OpenAI requieren un acceso rápido y confiable a los datos, proporcionado por nuestra plataforma de almacenamiento, Habitat. Tiene que responder en milisegundos a más de 1 mil millones de usuarios en 40 regiones geográficas. Nuestra infraestructura enfrentó un desafío extraordinario: soportar un crecimiento explosivo y nuevos casos de uso mientras continuábamos mejorando la confiabilidad, el rendimiento y la velocidad de desarrollo de producto. Resolver ese desafío requirió repensar cómo se diseñaba y operaba nuestra plataforma de almacenamiento en línea. Evaluamos constantemente los compromisos, siguiendo el patrón de: primero volverse lo suficientemente confiable para el tráfico de productos de misión crítica, luego lo suficientemente rápido para los usuarios globales y, finalmente, operar con destreza a escala masiva.

Esta serie en dos partes explica cómo desarrollamos Habitat desde una simple biblioteca cliente y base de datos hasta una plataforma de almacenamiento distribuida globalmente que sirve más de 500 petabytes de datos. La Parte I se centró en la evolución de Habitat, de un cliente Python a un servicio. También cubrió las técnicas que nos permitieron llevar un servicio basado en Python mucho más allá de lo que muchos considerarían práctico.

En esta publicación, la Parte II, recorremos cómo escalamos el componente de almacenamiento subyacente: Azure Cosmos DB. Mediante una estrecha colaboración con el equipo de Azure, llegamos a un enfoque viable de multi-tenancy de contenedores cogestionados, con un excelente rendimiento de lectura a escala masiva y global.

Figura 01 · ¿Qué es Habitat?

Plataforma de almacenamiento en línea

Habitat es la plataforma de almacenamiento en línea que construimos para que los productos de OpenAI puedan acceder de manera rápida y confiable a la información necesaria.

  • Solicitud
  • Respuesta
  • Cambios (CDC)

Clientes

Plataforma de almacenamiento en línea

Recursos de almacenamiento

  • ChatGPT
  • API
  • Codex
  • Servicios internos
  • Y más

Habitat

  • Almacenamiento en cachéCachés
  • Políticas ACLEautorización
  • Ubicación y residencia de datosResidencia de datos
  • CifradoSeguridad de los datos
  • AislamientoMulti-tenancy
  • Limitación de tasaModelado de solicitudes
  • EnrutamientoBúsqueda de esquema · Residencia de datos
  • Azure Cosmos DBAlmacenamiento en línea
  • NanobaseAlmacenamiento en línea
  • ValkeyCaches
  • Blob storageRecursos de almacenamiento
CDC ServicesCaptura de datos modificados
  • Databricks
  • Rockset
  • Kafka
  • Y más

Haciendo confiable el multi-arrendamiento a gran escala

A medida que las empresas escalan, los equipos de infraestructura a menudo evolucionan de operar sistemas de inquilino único a sistemas multi-arrendatario. El inquilino único, donde cada equipo de superficie de producto mantiene su propio sistema, reduce el radio de impacto y proporciona límites de propiedad fáciles y aislamiento de cargas de trabajo. A medida que crecen los equipos y las superficies de producto, esto se vuelve costoso de operar. El inquilino único hace que cada equipo de producto sea responsable de la planificación de capacidad y a menudo resulta en un aprovisionamiento excesivo significativo.

Por el contrario, el multi-arrendamiento asigna el control a un equipo centralizado de bases de datos, con mejor conocimiento y experiencia para aprovisionar recursos. Pero el multi-arrendamiento crea sus propios problemas, como los problemas de vecinos ruidosos, donde un inquilino consume una parte inusualmente grande de los recursos en detrimento de los demás inquilinos.

En Habitat, tuvimos que sopesar todos estos compromisos para diseñar un sistema de almacenamiento confiable y eficiente a gran escala. Hoy, Habitat es una capa de base de datos multi-arrendatario para muchos productos de OpenAI, pero pasamos por un viaje circular desde el uso de un contenedor multi-arrendatario de Azure Cosmos DB hasta aprovisionar contenedores de respaldo de inquilino único para luego volver a un contenedor multi-arrendatario por defecto. Todavía estamos muy al principio de nuestra historia de multi-arrendamiento en Habitat: admitimos un gran conjunto de casos de uso, pero hemos podido diferir la inversión en esta área aprovechando las primitivas integradas de Azure Cosmos DB siempre que sea posible.

Una introducción simplificada a los contenedores de Azure Cosmos DB

Antes de repasar nuestro viaje con Azure Cosmos DB, algo de contexto básico:

  • Una cuenta de Azure Cosmos DB define un conjunto de contenedores y una política de replicación

  • Cada contenedor se aprovisiona con una cierta cantidad de rendimiento en unidades de solicitud por segundo (RU/s)

  • Los datos dentro de cada contenedor se almacenan de la manera típica de fragmentación por clave de partición lógica especificada, con límites documentados de almacenamiento y rendimiento por clave de partición lógica

  • Azure Cosmos DB maneja la fragmentación de las claves de partición lógica en un número menor de particiones físicas de respaldo, dividiéndolas en múltiples particiones físicas cuando el almacenamiento supera un umbral o cuando el contenedor requiere más particiones físicas para sostener el rendimiento aprovisionado

Fase I: Confiar en las primitivas de Azure Cosmos DB

Originalmente permitíamos pasar cualquier carga de cliente, confiando en el límite establecido de 10K RU/s por clave de partición lógica para proporcionar contrapresión. Cuando comenzamos, también usábamos solo un contenedor predeterminado de Azure Cosmos DB en cada cuenta. Esto funcionó lo suficientemente bien, pero resultó problemático por algunas razones:

Límites de clave de partición lógica

Debido a decisiones tempranas de la API, expusimos directamente la selección de la clave de partición lógica a los clientes. Como resultado, tenemos colisiones frecuentes en claves de partición de uso común, como user_id o workspace_id, entre diferentes casos de uso de producto. Debido a que estos casos de uso compartían los límites de Azure Cosmos DB en las mismas claves de partición lógica, el diseño restringía el rendimiento general para un usuario determinado.

Un problema común que enfrentábamos al escalar Postgres antes de mudarnos a Habitat y Azure Cosmos DB era la posibilidad de que muchas solicitudes de una organización muy activa o una clave muy activa—un inquilino que genera una carga desproporcionadamente alta—derribaran toda la base de datos. Se dedicó un esfuerzo colectivo significativo a almacenar en caché esas claves y construir arrendamientos en los fallos de caché para que la carga resultante de fallos de caché no pisoteara la base de datos subyacente.

Figura 02a · Límites de clave de partición lógica

Clientes diferentes, la misma clave de partición

Vecinos ruidosos

Si bien los límites documentados de tamaño de datos y rendimiento se aplican a las claves de partición lógica, los límites en realidad se aplican en la partición física. En la práctica, esto significa que las particiones lógicas no pueden alcanzar 10,000 RU/s. En cambio, comparten los límites de la partición física con todas las demás claves de partición lógica colocadas en esa partición física.

Esto permitía que los vecinos ruidosos afectaran a muchas claves de partición lógica no relacionadas, con cargas de trabajo que operaban sobre datos de características de producto de nicho que interrumpían los flujos principales de inicio de sesión y registro.

Figura 02b · Vecinos ruidosos

Usuarios diferentes, la misma partición física

Particiones débiles

El límite de rendimiento de una partición física dada también es variable, dependiente del rendimiento total asignado al contenedor de Azure Cosmos DB. El rendimiento aprovisionado del contenedor se distribuye de manera aproximadamente uniforme entre las particiones físicas de ese contenedor.

A medida que crece el volumen de datos, las particiones físicas se dividen, aumentando el recuento total de particiones mientras el rendimiento total aprovisionado permanece sin cambios. El resultado es que el límite de rendimiento efectivo por partición se reduce a medida que crece el tamaño de los datos.

Para nuestros casos de uso con mayor demanda de almacenamiento, de tipo blob, esto crea un modo de fallo en el que el mero crecimiento del almacenamiento reduce la capacidad de rendimiento para las cargas de trabajo activas, incluso cuando las tasas de solicitudes y el uso se mantienen estables.

Figura 02C · Particiones débiles

El límite cae por debajo de la demanda

Una partición se divide cuando alcanza su límite de almacenamiento. Cada partición hija recibe la mitad de la capacidad de rendimiento.

Antes de la división: 10K RU/s de capacidad

Después de la división: 5K RU/s de capacidad × 2 particiones

Fase II: Probar el aislamiento de la carga de trabajo y la inquilinato único

Los contenedores separados ayudan a resolver parcialmente estos límites de clave de partición y los vecinos ruidosos. Al usar contenedores separados, a cada uno se le puede asignar sus propias particiones físicas independientes y solo las cargas de trabajo variables sobre ese contenedor mismo podrían ser vecinos ruidosos o solaparse en el espacio de claves de partición. Como desventaja, existe una sobrecarga no nula al aprovisionar nuevos contenedores—cada contenedor requiere una planificación de capacidad individualizada—así que queremos crear contenedores solo en un límite de servicio o caso de uso que tenga sentido.

Comenzamos a usar contenedores separados de Azure Cosmos DB para los casos de uso nuevos más críticos que requerían un aislamiento fuerte. Combinado con un script para gestionar particiones débiles sincronizando el rendimiento total aprovisionado para cada contenedor con su número de particiones físicas, evitamos en su mayoría todos los problemas que estábamos enfrentando.

Sin embargo, dado que empezamos con un contenedor predeterminado, muchos casos de uso críticos heredados quedaron desafortunadamente atrapados allí sin una migración de datos. Para proteger los servicios críticos que aún dependían de los datos en el contenedor predeterminado compartido, a menudo aconsejábamos a los equipos crear contenedores separados para nuevos servicios o funcionalidades importantes de producto. A medida que escalábamos, la presión sobre el contenedor predeterminado creció y los incidentes de producción también crecieron. Comenzamos a aprovisionar contenedores para cualquier nuevo servicio o funcionalidad grande de producto solo para proteger el contenedor predeterminado de más carga.

Esto nos salvó de muchas interrupciones en todo el sitio, limitando el radio de impacto a interrupciones de degradación de funcionalidades o servicios. Sin embargo, la sobrecarga de aprovisionar nuevos contenedores finalmente nos alcanzó:

Falta de crecimiento agregado estable

En el antiguo contenedor predeterminado compartido, cualquier caso de uso nuevo en particular que pasara de 0 QPS a 1 millón de QPS era poco probable que cambiara significativamente el uso agregado total. Sin embargo, en un contenedor aislado, un nuevo caso de uso que pasara de 0 a 1 millón de QPS podría representar 1,000 veces más carga que la línea base atribuida solo a la ingesta interna (dogfooding).

Con contenedores dedicados, los equipos ahora necesitaban recordar preaprovisionar los contenedores al nivel esperado de rendimiento para sus lanzamientos. Los equipos de producto a menudo enviaban sus funcionalidades a producción y olvidaban preescalar, y nos sentábamos en salas SEV el día del lanzamiento intentando escalar los contenedores a último momento.

Este es un beneficio central de mezcla de cargas de trabajo de los sistemas multiinquilino que perdemos a favor de un mejor aislamiento con esta estrategia de contenedores.

Figura 03 · Falta de crecimiento agregado estable

La misma carga de trabajo, diferente margen

1K RU/s durante las pruebas de carga → 1M RU/s en el lanzamiento

Contenedor compartido

Capacidad de 100M RU/s · 80% utilizada

Prueba de carga

1K20M=

0.005%

de margen

Lanzamiento

1M20M=

5%

de margen

Nuevo contenedor dedicado

Capacidad de 10K RU/s · sin otras cargas de trabajo

Prueba de carga

1K10K=

10%

de margen

Lanzamiento

1M10K=

10,000%

de margen

Planificación de capacidad

Con el tiempo, monitorear el uso de contenedores dedicados también requería un conocimiento profundo del producto para saber cuándo el tráfico cambiaría o crecería.

Podíamos ofrecer un script básico de plano de control para escalar el rendimiento aprovisionado de cada contenedor según las tendencias de crecimiento, pero sin un crecimiento agregado estable, escalarlos correctamente hacía que prácticamente todos los equipos de producto de OpenAI tuvieran que participar en la planificación de capacidad.

Esto no escalaba a nivel organizativo, con una gran varianza en cuánto cuidado le dedicaba cada equipo propietario a su aprovisionamiento de Azure Cosmos DB.

Fase III: Usar multi-tenancy por defecto, con capacidad de movimiento de datos

A medida que la organización creció, esos problemas operativos se volvieron difíciles de escalar. La ausencia de un equipo central único que hiciera la planificación resultó en que muchos equipos planificaran mal. Como resultado, terminamos volviendo a una solución multi-tenant y trabajamos estrechamente con el equipo de Azure para desarrollar soluciones a nuestros problemas originales de multi-tenancy con un diseño de tenencia compartida:

Limitación de claves calientes

Limitar primero las claves más calientes evita que los vecinos ruidosos consuman todo el rendimiento disponible de una partición física dada. Esto reduce el efecto de vecino ruidoso, donde una sola clave caliente puede tener un radio de impacto en todo el sitio.

Calidad de servicio (QoS)

La QoS por niveles de solicitud evita de manera similar que las cargas de trabajo sin conexión, como las inserciones masivas o las extracciones de datos, utilicen todo el rendimiento de una partición física dada. Al asignar a las solicitudes de estas cargas de trabajo una prioridad más baja, se limitan primero, evitando la limitación de las solicitudes interactivas de mayor prioridad que sirven a los usuarios finales.

Modo serverless

Azure Cosmos DB ya tenía un modo serverless que habría resuelto nuestro problema de particiones débiles con el modo aprovisionado. Sin embargo, había un inconveniente importante: escalaba solo según el uso de almacenamiento y limitaba el uso de RU a 5K RU/s por partición física. Esto resolvería nuestro problema de particiones débiles, pero nos impediría escalar casos de uso intensivos en RU.

Un nuevo modo serverless mejorado que el equipo de Azure Cosmos DB construyó para nosotros permitía que cada partición física escalara hasta 10K RU/s e introdujo divisiones basadas en el uso de RU además de las divisiones basadas en el uso de almacenamiento, lo que nos permitió dejar de monitorear y escalar contenedores manualmente.

Con estos cambios, hemos podido volver a usar un contenedor compartido, lo que ha simplificado significativamente la necesidad de realizar cualquier planificación de capacidad inicial o continua por parte de los equipos de producto, al tiempo que preserva el aislamiento entre cargas de trabajo. No hemos tenido ningún incidente de aprovisionamiento ni de vecino ruidoso en los meses posteriores, a pesar del ritmo acelerado de desarrollo de producto.

Mejor confiabilidad como servicios coadministrados

Cuando las empresas crecen hasta la escala de OpenAI, los servicios administrados se vuelven menos «administrados». Muchas cargas de trabajo se convierten en casos atípicos en la infraestructura del proveedor de la nube. A medida que OpenAI se convirtió en uno de los mayores usuarios de Azure Cosmos DB, operarlo con éxito requirió un modelo diferente: pruebas compartidas, paneles compartidos, canales directos de ingeniería y propiedad conjunta de los modos de fallo que solo aparecen a nuestra escala. Hoy, nuestra cuenta más grande de Azure Cosmos DB almacena 10s de petabytes de datos y sirve más de 20M QPS. Hasta donde sabemos, somos la única empresa que ha desplegado Azure Cosmos DB a esta escala.

A finales de 2024, una interrupción regional dejó claro por qué era necesaria esta colaboración. En ese momento, un corte de energía afectó a la región principal de Azure de una de nuestras cuentas más grandes de Azure Cosmos DB. En el ejercicio de conmutación por error resultante, nos dimos cuenta de que nuestras cuentas más grandes tardarían varias horas en conmutarse a una región secundaria, algo que ni nuestro equipo ni el equipo de Azure Cosmos DB habían probado a nuestra escala.

Alrededor de un mes después, mientras devolvíamos esas cuentas a la región original, provocamos otra interrupción grave. Una estampida de conexiones hacia la región original saturó la gateway de Azure Cosmos DB de esa región. Una peculiaridad en cómo el cliente de Azure Cosmos DB en modo gateway manejaba las conmutaciones por error hacía que todos los clientes establecieran conexiones y enviaran solicitudes inmediatamente a la región original, a pesar de que solo un subconjunto de particiones físicas había vuelto a esa región.

En cada interrupción, tanto OpenAI como Azure ejecutaron sus procesos de gestión de incidentes, identificando varias causas raíz y desplegando correcciones. Pero estas interrupciones eran síntomas de un problema sistémico mayor entre la forma en que nuestro equipo y el equipo de Azure Cosmos DB operaban y probaban. Al principio, aprovechar los servicios administrados nos permitía movernos rápido y centrarnos en los objetivos de negocio. A escala, los servicios administrados se vuelven menos administrados y requieren integraciones profundas con el proveedor del servicio en todos los niveles, desde el diseño hasta las operaciones.

Hoy, los equipos de ingeniería de Habitat y Azure monitorean conjuntamente cada capa de Habitat, desde nuestras capas de servicio hasta las capas de almacenamiento físico de Azure Cosmos DB. Operamos y probamos cambios contra una cuenta de Azure Cosmos DB de tamaño de producción pero no de producción. Probamos e iteramos juntos en los SDK y determinamos las mejores prácticas para escalar y dimensionar nuestras cuentas de Azure Cosmos DB. Tenemos acceso directo de ingeniería entre nosotros a través de Teams e incluso hemos expuesto formas de avisarnos directamente sin pasar por los niveles de soporte.

Una cantidad sustancial de trabajo conjunto se ha realizado durante el último año para mejorar la escalabilidad del plano de control y la gateway de Azure Cosmos DB, añadiendo protección contra cargas y caché de diversos metadatos de Azure Cosmos DB en su gateway para proteger la partición de metadatos de Azure Cosmos DB, reduciendo la presión de nuestra flota de procesos Python de habitat-service mediante pooling de conexiones y una mayor reutilización de conexiones, colocando cargas de trabajo donde sea posible y aislando las cargas de trabajo críticas de las cargas de trabajo sin conexión mediante diferentes VPC.

Este nivel de coingeniería ha sido crítico para la estabilidad de nuestro Azure Cosmos DB en el último año. Cualquier sistema lo suficientemente grande o crítico exige este tipo de trabajo en equipo: derribar los muros de propiedad y operar a través de los límites organizativos.

Mejorando el rendimiento a escala global

Como se mencionó en la Parte I, nuestra filosofía central es: haz que funcione, hazlo rápido, hazlo barato. Primero la fiabilidad, luego el rendimiento, luego la eficiencia. Habitat se había convertido en infraestructura crítica para OpenAI, por lo que la primera prioridad era hacerlo fiable. A medida que el sistema se estabilizó en 2025 y OpenAI se expandió globalmente, la latencia se convirtió en la siguiente restricción para los usuarios y los equipos de producto.

La capacidad de cómputo y almacenamiento a menudo se encontraba en regiones diferentes, lo que hacía inevitables las solicitudes entre regiones.

Figura 04 · Mejorando el rendimiento a escala global

Tráfico global

La capacidad de cómputo y almacenamiento a menudo se encontraba en regiones diferentes, lo que hacía inevitables las solicitudes entre regiones.

CómputoAlmacenamientoRutas ilustrativas · Los viajes más largos toman más tiempo

Las ubicaciones geográficas del cómputo y el almacenamiento son solo con fines ilustrativos.

La latencia variaba enormemente dependiendo de dónde se almacenaban los datos y dónde se atendía la solicitud. Para que las solicitudes a Habitat fueran rápidas, los desarrolladores de producto recurrían a almacenamiento en caché adicional del lado del cliente, agrupación de solicitudes, minimización de lecturas y escrituras en la base de datos, y a mover trabajo fuera de la ruta crítica siempre que era posible. Si bien esto dio lugar a algunos diseños de producto interesantes que eran más resistentes a problemas de la base de datos, también hizo los productos más complejos y ralentizó la iteración de producto: un fracaso del objetivo de Habitat de fomentar un desarrollo rápido de producto y no necesitar comprender la base de datos.

Esto ha sido un gran enfoque para nosotros en 2026, y hemos desarrollado una estrategia por capas para optimizar el rendimiento de lectura, que representa más del 90% de las solicitudes de Habitat:

Almacenar datos cerca de los usuarios cuando la capacidad lo permite

Tenemos varias cuentas de Azure Cosmos DB en diferentes regiones de Azure alrededor del mundo para usuarios con requisitos de residencia de datos. Incluso para usuarios sin requisitos estrictos de residencia de datos, colocar los datos cerca de los usuarios también mejora su experiencia mediante una menor latencia.

En la práctica, no podemos lograr esto de manera generalizada fuera de los casos de uso de residencia de datos porque la ubicación está limitada por la capacidad física de la nube. Debido al tamaño de nuestros conjuntos de datos, muchas regiones no pueden acomodar la enorme huella de almacenamiento requerida para su parte proporcional del tráfico de usuarios.

En regiones con capacidad limitada de centro de datos, energía o refrigeración, a veces enfrentamos un compromiso directo: reservar capacidad para almacenamiento colocado en la misma ubicación y una menor latencia de Habitat, o usar esa capacidad para cómputo de servicio adicional y enrutar las solicitudes de almacenamiento más lejos.

Como resultado, las decisiones de ubicación suelen ser un compromiso de producto entre: A) optimizar la latencia para diferentes productos y subconjuntos de usuarios, y B) la capacidad bruta de almacenamiento y cómputo.

Replicar ampliamente solo los conjuntos de datos más pequeños y más sensibles a la latencia

Para las cargas de trabajo más críticas en latencia, como los metadatos de autenticación que se necesitan en cada solicitud, reducimos el RTT entre el cómputo y Habitat mediante cuentas de Azure Cosmos DB altamente replicadas con muchas regiones secundarias. Algunas cuentas se replican en las 40 regiones de Azure donde atendemos tráfico; otras se replican en al menos una región por continente.

Hemos tenido que construir una capa transparente de movimiento de datos y enrutamiento en Habitat antes de lo deseado para poder mover conjuntos de datos entre cuentas con diferentes topologías de replicación.

Sin embargo, este enfoque también está limitado en última instancia por la capacidad y, por lo tanto, se limita a unos pocos conjuntos de datos seleccionados a mano.

Confiar en el almacenamiento en caché integrado para todo lo demás

Las cargas de trabajo de Habitat son abrumadoramente de lectura intensiva, con aplicaciones que obtienen constantemente configuraciones, estado y otras propiedades; una cantidad desproporcionada del tráfico se atribuye a un conjunto de trabajo relativamente pequeño de tipos accedidos con frecuencia. Esto hace que el sistema sea particularmente adecuado para el almacenamiento en caché distribuido. Si bien el almacenamiento en caché mejora el rendimiento en infraestructura de una sola región, las mejoras se multiplican al trabajar entre regiones, donde puede usarse para "ocultar" la latencia entre regiones.

Hemos integrado una capa de almacenamiento en caché distribuido lookaside en Habitat. Almacena una copia de los objetos y aristas accedidos recientemente en servidores Valkey ubicados en nuestra infraestructura cerca de donde se procesan las solicitudes de los usuarios. Normalmente, este tipo de cachés usan un TTL que compensa entre la tasa de aciertos y la obsolescencia. Los TTL cortos reducen la obsolescencia pero amortiguan el impacto positivo del almacenamiento en caché, porque los elementos expiran de la caché rápidamente y deben recuperarse con más frecuencia. Los TTL más largos mejoran las tasas de aciertos, pero sirven datos obsoletos durante períodos prolongados, lo que lleva a malas experiencias de usuario y a un comportamiento impredecible del producto.

Otro enfoque es ejecutar operaciones explícitas de invalidación cuando la aplicación realiza operaciones de escritura sobre los mismos datos subyacentes. Esto mejora drásticamente la frescura de los datos en caché, pero puede ser difícil de lograr correctamente. También sigue estando sujeto a varios casos límite, como fallos parciales, que dejan la caché obsoleta. Los despliegues multirregión agravan estos problemas, con redes entre regiones menos fiables y la caché compitiendo con la replicación del almacenamiento subyacente. Complementar esto con TTL acota la obsolescencia máxima, pero sigue sufriendo el mismo compromiso de TTL subyacente discutido anteriormente.

Hemos adoptado un enfoque más avanzado para la invalidación, siguiendo los pasos de sistemas como TAO de Meta. La caché integrada de Habitat se basa en la captura de datos de cambio (CDC) a través del change feed de Azure Cosmos DB para propagar invalidaciones globalmente en cuestión de segundos, logrando altas tasas de aciertos mientras mantiene baja la obsolescencia. Un servicio en nuestra infraestructura consume este change feed y ejecuta invalidaciones en las cachés locales cuando los datos subyacentes se actualizan. Esto provoca un fallo de caché la próxima vez que se leen los datos, y la caché se llena con la última versión de los datos.

Reducir la sobrecarga del proxy con Rust

También hemos reducido significativamente la latencia al eliminar la sobrecarga en el propio servicio de Habitat mediante la reescritura del código en Rust, que es más eficiente que el Python original.

En conjunto, estos cambios han reducido nuestro p50 global de lecturas de aproximadamente 120 ms a aproximadamente 10 ms, una mejora de 12x desde que comenzamos a centrarnos en el rendimiento a principios de este año.

Figura 05 · Mejorando el rendimiento a escala global

Latencia p50 para lecturas

Tres cambios de diseño principales mejoraron la latencia de lectura

aproximadamente 120 ms → aproximadamente 10 ms

Mejora de 12x

  1. datos críticos replicados en geos cercanos
  2. caché dentro de la región lanzada
  3. reescritura en Rust lanzada

Si bien el almacenamiento en caché ha reducido drásticamente la latencia mediana, las solicitudes más lentas todavía requieren recuperar datos no almacenados en caché del almacenamiento subyacente, a menudo a través de regiones distantes. A medida que entra en línea más capacidad y mejoramos la eficiencia del almacenamiento, planeamos abordar un desafío más fundamental: colocar los datos más cerca de donde se accederá a ellos desde el principio.

Escalando el Change Data Capture

Un CDC confiable y escalable—la propagación de cambios de bases de datos a sistemas posteriores—es un componente crítico en algo más que la estrategia de caché de Habitat. Millones de cambios capturados por segundo, a través de miles de contenedores y millones de particiones de contenedores, fluyen por más de un centenar de temas de Kafka para también alimentar índices secundarios eventualmente consistentes, canalizaciones de movimiento de datos, análisis fuera de línea y otras funciones de productos en tiempo real. A medida que nuestra infraestructura de soporte ha crecido a nivel global, se ha vuelto cada vez más complejo escuchar los cambios en las filas. Si un cliente quiere registrar una devolución de llamada que se ejecute cada vez que se cambien las filas de su tipo, debe, entre otras cosas, determinar primero qué cuentas y contenedores de Cosmos contienen sus datos, qué despliegue del servicio de CDC se está ejecutando en las regiones respectivas escuchando esos contenedores, y escalar adecuadamente el conjunto de trabajadores del servicio de CDC, Kafka y su consumidor. Nuestra plataforma de CDC tiene como objetivo abstraer todo esto de los desarrolladores de productos y proporcionar en su lugar una superficie simple donde los clientes registran una función que desean que se llame en sus filas modificadas, y nosotros nos encargamos de toda la plomería y el escalado.

Un plano de control interno garantiza continuamente que todos los contenedores requeridos estén siendo capturados, selecciona desde qué regiones de Cosmos leer y distribuye eficientemente el trabajo entre miles de trabajadores en múltiples regiones geográficas. El uso de regiones de réplica y lecturas de feed de menor prioridad protege el tráfico de Habitat sensible a la latencia de las cargas de trabajo de captura en segundo plano. Fallos de trabajadores, problemas de contenedores, errores del almacén de arrendamientos, configuraciones no válidas y fallos de destino ocurren continuamente en una flota de este tamaño. Endurecimos el ciclo de vida de los trabajadores de CDC y el manejo de arrendamientos, aislamos los fallos entre flujos, y construimos salvaguardas para los cambios y despliegues de configuración. Utilizamos colas de mensajes muertos para evitar el bloqueo de cabecera de línea por fallos de entrega permanentes. Toleramos interrupciones regionales cambiando los lectores a regiones de Cosmos alternativas. A nuestra escala, incluso hemos tenido que hacer cambios en el SDK de CDC de Azure para hacer su implementación de checkpointing más eficiente agrupando checkpoints en memoria y solo vaciándolos periódicamente.

Si bien el uso interno de Azure Cosmos DB por parte de Habitat es complejo, su propuesta de valor siempre ha sido abstraer los detalles de la infraestructura de los desarrolladores de productos para mejorar la velocidad de desarrollo del producto, y nuestra plataforma de CDC no es diferente.

Mirando hacia adelante

Un equipo pequeño pudo soportar una plataforma de almacenamiento en rápido crecimiento manteniendo la API de almacenamiento deliberadamente estrecha, continuando escalando el servicio de Python, y priorizando los desafíos de ingeniería más urgentes. Nos centramos primero en la confiabilidad para el tráfico de productos críticos para la misión, luego en el rendimiento de lectura para usuarios globales, y finalmente en la eficiencia operativa a escala. Este enfoque permitió un crecimiento rápido y nuevos casos de uso mientras mejoraba la confiabilidad, el rendimiento y la velocidad de desarrollo del producto.

Para escalar Habitat y el almacenamiento de conversaciones para los próximos mil millones de usuarios, debemos abordar la dificultad de replicar nuestros datos a través de nuestra infraestructura, a una escala aún mayor. Para prevenirlo, hemos estado construyendo un sistema de almacenamiento en línea personalizado y a escala de exabytes, optimizado para los tipos de datos voluminosos de Habitat. Este sistema en desarrollo combina el núcleo de RocksDB Cloud de Rockset con replicación basada en Raft. Implementa el mismo modelo de documentos que Azure Cosmos DB, pero utiliza almacenamiento desagregado y replicación física para reducir la cantidad de capacidad flash necesaria, a cambio de un qps pico más bajo.

Si estás interesado en trabajar en este tipo de esfuerzos de infraestructura de datos a escala fronteriza, consulta nuestras vacantes abiertas⁠.

Fuente original

OpenAI

Notas sobre el contenido

La publicación original y los derechos pertenecen a la fuente.

Traducción automática · Consulte el original