Passer au contenu principal
OpenAI

23 octobre 2026

Ingénierie

Adapter le stockage en ligne à plus d’un milliard d’utilisateurs de ChatGPT (partie II)

Comment nous avons optimisé Azure Cosmos DB dans Habitat, notre plateforme de stockage applicatif, pour gérer une croissance sans précédent.

Par Jon Lee, Hrachya Hakobyan et Chaomin Yu, membres de l’équipe technique

Chargement...

Tous les produits OpenAI ont besoin d’un accès rapide et fiable aux données, assuré par notre plateforme de stockage, Habitat. Elle doit répondre en quelques millisecondes à plus d’un milliard d’utilisateurs répartis dans 40 régions géographiques. Notre infrastructure faisait face à un défi exceptionnel : soutenir une croissance explosive et de nouveaux cas d’usage tout en continuant d’améliorer la fiabilité, les performances et la rapidité du développement produit. Pour relever ce défi, il a fallu repenser la conception et l’exploitation de notre plateforme de stockage en ligne. Nous avons constamment évalué les compromis selon la même logique : devenir d’abord assez fiables pour le trafic produit critique, puis assez rapides pour les utilisateurs du monde entier, et enfin capables d’opérer efficacement à très grande échelle.

Cette série en deux parties explique comment nous avons fait évoluer Habitat, d’une simple bibliothèque cliente associée à une base de données vers une plateforme de stockage distribuée mondialement, donnant accès à plus de 500 pétaoctets de données. La partie I portait sur l’évolution d’Habitat, d’un client Python vers un service. Elle présentait aussi les techniques qui nous ont permis de pousser un service Python bien au-delà de ce que beaucoup jugeraient réaliste.

Dans cet article, la partie II, nous expliquons comment nous avons fait évoluer le composant de stockage sous-jacent : Azure Cosmos DB. Grâce à une étroite collaboration avec l’équipe Azure, nous avons abouti à une approche multilocataire viable fondée sur des conteneurs cogérés, offrant d’excellentes performances en lecture à très grande échelle dans le monde entier.

Figure 01 · Qu’est-ce qu’Habitat ?

Plateforme de stockage en ligne

Habitat est la plateforme de stockage en ligne que nous avons créée pour permettre aux produits OpenAI d’accéder rapidement et fiablement aux informations nécessaires.

  • Requête
  • Réponse
  • Modifications (CDC)

Clients

Plateforme de stockage en ligne

Ressources de stockage

  • ChatGPT
  • API
  • Codex
  • Services internes
  • Et plus encore

Habitat

  • Mise en cacheCaches
  • Politiques ACLAutorisation
  • Placement et résidence des donnéesRésidence des données
  • ChiffrementSécurité des données
  • IsolationMutualisation
  • Limitation du débitMise en forme des requêtes
  • RoutageRecherche de schéma · Résidence des données
  • Azure Cosmos DBStockage en ligne
  • NanobaseStockage en ligne
  • ValkeyCaches
  • Stockage d’objets blobRessources de stockage
Services CDCCapture des données modifiées
  • Databricks
  • Rockset
  • Kafka
  • Et plus encore

Fiabiliser l’architecture multilocataire à grande échelle

À mesure que les entreprises grandissent, les équipes infrastructure passent souvent de systèmes monolocataires à des systèmes multilocataires. L’architecture monolocataire, où chaque équipe responsable d’une composante produit gère son propre système, réduit la portée des incidents, clarifie les responsabilités et facilite l’isolation des charges de travail. À mesure que les équipes et les composantes produit se multiplient, son exploitation devient coûteuse. L’architecture monolocataire rend chaque équipe produit responsable de la planification de la capacité et entraîne souvent un surprovisionnement important.

À l’inverse, l’architecture multilocataire confie le contrôle à une équipe centralisée de bases de données, plus expérimentée et mieux armée pour provisionner les ressources. Mais elle crée ses propres problèmes, notamment celui des voisins bruyants : un locataire consomme une part inhabituellement élevée des ressources au détriment des autres.

Pour Habitat, nous avons dû peser tous ces compromis afin de concevoir un système de stockage fiable et efficace à grande échelle. Aujourd’hui, Habitat constitue une couche de base de données multilocataire pour de nombreux produits OpenAI. Mais notre parcours a fait une boucle : d’un seul conteneur Azure Cosmos DB multilocataire, nous sommes passés à des conteneurs de stockage monolocataires, avant de revenir à un conteneur multilocataire par défaut. L’architecture multilocataire d’Habitat en est encore à ses débuts : nous prenons en charge de nombreux cas d’usage, mais avons pu différer les investissements dans ce domaine en exploitant autant que possible les primitives intégrées d’Azure Cosmos DB.

Présentation simplifiée des conteneurs Azure Cosmos DB

Avant de retracer notre parcours avec Azure Cosmos DB, voici quelques notions de base :

  • Un compte Azure Cosmos DB définit un ensemble de conteneurs et une politique de réplication

  • Chaque conteneur est provisionné pour un débit donné, exprimé en unités de requête par seconde (RU/s)

  • Les données de chaque conteneur sont stockées selon un partitionnement classique par clé de partition logique spécifiée, avec des limites documentées de stockage et de débit par clé

  • Azure Cosmos DB répartit les clés de partition logique sur un nombre réduit de partitions physiques sous-jacentes. Il scinde celles-ci lorsque le stockage dépasse un seuil ou que le conteneur a besoin de davantage de partitions physiques pour soutenir le débit provisionné

Phase I : s’appuyer sur les primitives d’Azure Cosmos DB

À l’origine, nous laissions passer toute la charge des clients, en comptant sur la limite annoncée de 10 k RU/s par clé de partition logique pour exercer une contre-pression. Au départ, nous n’utilisions aussi qu’un seul conteneur Azure Cosmos DB par défaut dans chaque compte. Cela fonctionnait assez bien, mais s’est révélé problématique pour plusieurs raisons :

Limites des clés de partition logique

En raison de choix d’API initiaux, nous avions directement exposé aux clients la sélection de la clé de partition logique. Nous rencontrons donc fréquemment des collisions entre différents cas d’usage produit sur des clés de partition courantes, telles que user_id ou workspace_id. Ces cas d’usage partageant les limites d’Azure Cosmos DB sur les mêmes clés de partition logique, cette conception plafonnait le débit global pour un utilisateur donné.

Avant notre migration vers Habitat et Azure Cosmos DB, nous rencontrions souvent ce problème en faisant évoluer Postgres : un grand nombre de requêtes issues d’une organisation ou d’une clé très sollicitée — un locataire générant une charge disproportionnée — pouvait faire tomber toute la base de données. Un effort collectif important a été consacré à la mise en cache de ces clés et à l’ajout de baux lors des défauts de cache, afin que la charge qui en résulte ne submerge pas la base de données sous-jacente.

Figure 02a · Logical partition key limits

Different clients, the same partition key

Cosmos DB containerPhysical partitionPK: user-id-28104CapacityMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedMemory / dreaming : capacity usedConversationsSuccess rateResponses returned in this animation loop—AuthSuccess rateResponses returned in this animation loop—Memory / dreamingSuccess rateResponses returned in this animation loop—

Voisins bruyants

Bien que les limites documentées de volume de données et de débit s’appliquent aux clés de partition logique, c’est au niveau de la partition physique qu’elles sont réellement imposées. En pratique, les partitions logiques ne peuvent donc pas atteindre 10 000 RU/s. Elles partagent les limites de la partition physique avec toutes les autres clés de partition logique qui y sont colocalisées.

Des voisins bruyants pouvaient ainsi affecter de nombreuses clés de partition logique sans lien entre elles : des traitements portant sur les données de fonctionnalités de niche perturbaient les parcours essentiels de connexion et d’inscription.

Figure 02b · Noisy neighbors

Different users, the same physical partition

Cosmos DB containerPhysical partitionPKs: user-id-28104, user-id-10384Conversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversations user-id-28104: capacity usedConversationsuser-id-28104Success rateResponses returned in this animation loop—Conversationsuser-id-10384Success rateResponses returned in this animation loop—

Partitions sous-dotées

La limite de débit d’une partition physique varie également selon le débit total alloué au conteneur Azure Cosmos DB. Le débit provisionné du conteneur est réparti à peu près équitablement entre ses partitions physiques.

À mesure que le volume de données augmente, les partitions physiques se scindent : leur nombre total croît, mais le débit total provisionné reste inchangé. La limite de débit effective par partition diminue donc à mesure que le volume de données augmente.

Pour nos cas d’usage les plus gourmands en stockage, de type blob, cela crée un mode de défaillance où la seule croissance du stockage réduit la capacité de débit des charges actives, même si les taux de requêtes et l’utilisation restent stables.

Figure 02C · Weak partitions

The limit falls below demand

A partition splits when it reaches its storage limit. Each child receives half the throughput capacity.

Before split: 10K RU/s capacity

After split: 5K RU/s capacity × 2 partitions

RU/s05K6K10K200200429

Phase II : tester l’isolation des charges de travail et l’architecture monolocataire

Des conteneurs distincts permettent de résoudre partiellement ces problèmes de limites des clés de partition et de voisins bruyants. Chaque conteneur peut alors disposer de ses propres partitions physiques indépendantes. Seules les charges de travail qu’il héberge peuvent devenir des voisins bruyants ou se chevaucher dans l’espace des clés de partition. En contrepartie, provisionner de nouveaux conteneurs a un coût opérationnel : chacun exige une planification de capacité spécifique. Nous souhaitons donc n’en créer qu’à des frontières pertinentes entre services ou cas d’usage.

Nous avons commencé à utiliser des conteneurs Azure Cosmos DB distincts pour les nouveaux cas d’usage les plus critiques nécessitant une forte isolation. En y ajoutant un script qui gérait les partitions sous-dotées en alignant le débit total provisionné de chaque conteneur sur son nombre de partitions physiques, nous avons largement évité les problèmes rencontrés.

Mais comme nous avions démarré avec un conteneur par défaut, de nombreux cas d’usage critiques historiques y restaient malheureusement bloqués, faute de migration des données. Pour protéger les services critiques dépendant encore des données du conteneur partagé par défaut, nous conseillions souvent aux équipes de créer des conteneurs distincts pour les nouveaux services ou les fonctionnalités produit majeures. Avec notre croissance, la pression sur le conteneur par défaut augmentait, tout comme les incidents en production. Nous avons commencé à provisionner des conteneurs pour chaque nouveau service ou fonctionnalité majeure, simplement pour éviter d’ajouter de la charge au conteneur par défaut.

Cela nous a épargné de nombreuses pannes à l’échelle du site, en limitant leur portée à la dégradation d’une fonctionnalité ou d’un service. Cependant, la charge opérationnelle liée au provisionnement de nouveaux conteneurs a fini par nous rattraper :

Absence de croissance agrégée stable

Dans l’ancien conteneur partagé par défaut, un nouveau cas d’usage passant de 0 à 1 million de requêtes par seconde (QPS) avait peu de chances de modifier sensiblement l’utilisation totale agrégée. Dans un conteneur isolé, en revanche, le même passage de 0 à 1 million de QPS pouvait représenter une charge 1 000 fois supérieure au niveau de référence issu des seuls tests d’usage internes.

Avec des conteneurs dédiés, les équipes devaient désormais penser à provisionner à l’avance le débit attendu pour leurs lancements. Les équipes produit déployaient souvent leurs fonctionnalités en production sans penser à augmenter la capacité en amont. Le jour du lancement, nous nous retrouvions en cellule de crise à tenter de redimensionner les conteneurs à la dernière minute.

Cette stratégie de conteneurs nous fait perdre un avantage essentiel des systèmes multilocataires — le mélange des charges de travail — au profit d’une meilleure isolation.

Figure 03 · Lack of stable aggregate growth

The same workload, different headroom

1K RU/s during load testing → 1M RU/s at launch

Shared container

100M RU/s capacity · 80% utilized

Load test

1K20M=

0.005%

of headroom

Launch

1M20M=

5%

of headroom

New dedicated container

10K RU/s capacity · no other workloads

Load test

1K10K=

10%

of headroom

Launch

1M10K=

10,000%

of headroom

Planification de la capacité

Au fil du temps, surveiller l’utilisation des conteneurs dédiés a aussi exigé une connaissance fine des produits pour anticiper les variations ou la croissance du trafic.

Nous pouvons fournir un script simple du plan de contrôle pour augmenter le débit provisionné de chaque conteneur selon les tendances de croissance. Mais sans croissance agrégée stable, les dimensionner correctement impliquait de faire participer presque toutes les équipes produit d’OpenAI à la planification de la capacité.

Cette approche ne pouvait pas suivre la croissance de l’organisation : le soin apporté au provisionnement d’Azure Cosmos DB variait fortement d’une équipe responsable de service à l’autre.

Phase III : adopter une architecture multilocataire par défaut, avec déplacement des données

À mesure que l’organisation grandissait, ces problèmes opérationnels devenaient difficiles à gérer à grande échelle. Faute d’une équipe centrale unique chargée de la planification, de nombreuses équipes planifiaient mal. Nous sommes donc revenus vers une solution multilocataire, en travaillant étroitement avec l’équipe Azure pour corriger les problèmes initiaux au moyen d’une conception partagée :

Limitation du débit des clés très sollicitées

Limiter d’abord les clés les plus sollicitées empêche les voisins bruyants de consommer tout le débit disponible d’une partition physique. Cela réduit l’effet de voisin bruyant, où une seule clé très sollicitée peut affecter tout le site.

Qualité de service (QoS)

De même, la QoS par niveaux de requêtes empêche les traitements hors ligne, comme les insertions en masse ou les extractions de données, d’utiliser tout le débit d’une partition physique. En attribuant une priorité inférieure aux requêtes de ces traitements, on les limite en premier, ce qui évite de limiter les requêtes interactives plus prioritaires destinées aux utilisateurs finaux.

Mode serverless

Azure Cosmos DB disposait déjà d’un mode serverless qui aurait résolu notre problème de partitions sous-dotées en mode provisionné. Il présentait toutefois un inconvénient majeur : il évoluait uniquement selon l’utilisation du stockage et limitait la consommation de RU à 5 k RU/s par partition physique. Cela aurait résolu notre problème de partitions sous-dotées, mais nous aurait empêchés de faire évoluer les cas d’usage gourmands en RU.

L’équipe Azure Cosmos DB a créé pour nous un mode serverless amélioré, permettant à chaque partition physique d’atteindre 10 k RU/s et ajoutant des scissions fondées sur la consommation de RU à celles fondées sur le stockage. Nous avons ainsi pu cesser de surveiller et de redimensionner les conteneurs manuellement.

Ces changements nous ont permis de revenir à un conteneur partagé unique. Ils ont considérablement simplifié la planification de capacité, initiale comme continue, pour les équipes produit, tout en préservant l’isolation entre charges de travail. Depuis, nous n’avons connu aucun incident de provisionnement ou de voisin bruyant, malgré l’accélération du développement produit.

Une meilleure fiabilité grâce aux services cogérés

Lorsque les entreprises atteignent l’échelle d’OpenAI, les services gérés deviennent moins « gérés ». De nombreuses charges de travail sortent de la norme dans l’infrastructure du fournisseur cloud. OpenAI étant devenu l’un des plus grands utilisateurs d’Azure Cosmos DB, sa bonne exploitation a exigé un autre mode de fonctionnement : tests et tableaux de bord partagés, canaux directs entre ingénieurs et responsabilité commune des modes de défaillance qui n’apparaissent qu’à notre échelle. Aujourd’hui, notre plus grand compte Azure Cosmos DB stocke des dizaines de pétaoctets de données et traite plus de 20 millions de requêtes par seconde. À notre connaissance, nous sommes la seule entreprise à avoir déployé Azure Cosmos DB à cette échelle.

Fin 2024, une panne régionale a mis en évidence la nécessité de cette collaboration. Une coupure de courant avait frappé la région Azure principale de l’un de nos plus grands comptes Azure Cosmos DB. Lors du basculement qui a suivi, nous avons constaté que nos plus grands comptes mettraient plusieurs heures à basculer vers une région secondaire, ce que ni notre équipe ni celle d’Azure Cosmos DB n’avaient testé à notre échelle.

Environ un mois plus tard, en rebasculant ces comptes vers leur région d’origine, nous avons déclenché une autre panne grave. Un afflux massif de connexions vers la région d’origine a submergé sa passerelle Azure Cosmos DB. Une particularité de la gestion des basculements par le client Azure Cosmos DB en mode passerelle poussait tous les clients à se connecter immédiatement à la région d’origine et à lui envoyer des requêtes, alors que seule une partie des partitions physiques y était revenue.

À chaque panne, OpenAI et Azure ont appliqué leurs procédures de gestion des incidents, identifié plusieurs causes racines et déployé des correctifs. Mais ces pannes révélaient un problème systémique plus large dans les pratiques d’exploitation et de test de notre équipe et de celle d’Azure Cosmos DB. Au départ, les services gérés nous avaient permis d’avancer vite et de nous concentrer sur nos objectifs métier. À grande échelle, ils deviennent moins gérés et nécessitent une intégration étroite avec le fournisseur à tous les niveaux, de la conception à l’exploitation.

Aujourd’hui, les équipes d’ingénierie Habitat et Azure surveillent ensemble chaque couche d’Habitat, de nos services jusqu’aux couches de stockage physique d’Azure Cosmos DB. Nous exploitons un compte Azure Cosmos DB hors production, mais dimensionné comme en production, et y testons les changements. Nous testons et améliorons ensemble les SDK, et définissons les bonnes pratiques pour faire évoluer et dimensionner nos comptes Azure Cosmos DB. Nos équipes d’ingénierie communiquent directement via Teams, et nous avons même mis en place des moyens de nous alerter mutuellement en astreinte sans passer par les différents niveaux d’assistance.

Au cours de l’année écoulée, un important travail conjoint a permis d’améliorer l’évolutivité du plan de contrôle et de la passerelle d’Azure Cosmos DB : ajout de protections contre la surcharge et mise en cache de diverses métadonnées Azure Cosmos DB dans la passerelle pour protéger leur partition, réduction de la pression exercée par notre parc de processus Python habitat-service grâce au regroupement et à une réutilisation accrue des connexions, colocalisation des charges de travail lorsque possible et isolation des charges critiques des traitements hors ligne dans des VPC distincts.

Ce niveau de co-ingénierie a été essentiel à la stabilité de notre infrastructure Azure Cosmos DB au cours de l’année écoulée. Tout système suffisamment vaste ou critique exige ce type de travail d’équipe : décloisonner les responsabilités et collaborer au-delà des frontières organisationnelles.

Améliorer les performances à l’échelle mondiale

Comme indiqué dans la partie I, notre philosophie est simple : faire fonctionner, accélérer, puis réduire les coûts. La fiabilité d’abord, puis les performances, puis l’efficacité. Habitat était devenu une infrastructure critique pour OpenAI : notre priorité était donc de le rendre fiable. À mesure que le système se stabilisait en 2025 et qu’OpenAI se développait à l’international, la latence est devenue la contrainte suivante pour les utilisateurs et les équipes produit.

Les capacités de calcul et de stockage se trouvaient souvent dans des régions différentes, rendant les requêtes interrégionales inévitables.

Figure 04 · Improving performance at a global scale

Global traffic

Compute and storage capacity were often located in different regions, making cross-region requests unavoidable.

ComputeStorageIllustrative routes · Longer journeys take more time

Les emplacements géographiques du calcul et du stockage sont présentés à titre illustratif uniquement.

La latence variait fortement selon le lieu de stockage des données et celui du traitement de la requête. Pour rendre les requêtes Habitat performantes, les développeurs produit ajoutaient des caches côté client, regroupaient les requêtes, minimisaient les lectures et écritures en base et déplaçaient autant que possible les traitements hors du chemin critique. Cela a abouti à des conceptions de produits intéressantes, plus résilientes aux problèmes de base de données, mais a aussi accru leur complexité et ralenti les itérations. Habitat manquait ainsi son objectif : favoriser un développement produit rapide sans nécessiter de comprendre la base de données.

C’est un axe majeur de notre travail en 2026. Nous avons élaboré une stratégie à plusieurs niveaux pour optimiser les performances en lecture, les lectures représentant plus de 90 % des requêtes Habitat :

Stocker les données près des utilisateurs lorsque la capacité le permet

Nous disposons de plusieurs comptes Azure Cosmos DB dans différentes régions Azure du monde pour les utilisateurs soumis à des exigences de résidence des données. Même sans exigences strictes de résidence des données, stocker les données près des utilisateurs améliore leur expérience en réduisant la latence.

En pratique, nous ne pouvons pas généraliser cette approche au-delà des cas liés à la résidence des données, car le placement est contraint par la capacité physique du cloud. Vu la taille de nos jeux de données, de nombreuses régions ne peuvent pas accueillir le volume de stockage massif nécessaire à leur part du trafic utilisateur.

Dans les régions où la capacité des centres de données, l’alimentation électrique ou le refroidissement sont limités, un arbitrage direct s’impose parfois : réserver de la capacité au stockage colocalisé pour réduire la latence d’Habitat, ou l’affecter à davantage de calcul pour traiter les requêtes et acheminer les demandes de stockage plus loin.

Les décisions de placement relèvent donc souvent d’un arbitrage produit entre A) l’optimisation de la latence pour différents produits et groupes d’utilisateurs, et B) la capacité brute de stockage et de calcul.

Répliquer largement uniquement les jeux de données les plus petits et les plus sensibles à la latence

Pour les charges les plus sensibles à la latence, comme les métadonnées d’authentification nécessaires à chaque requête, nous réduisons le temps aller-retour (RTT) entre le calcul et Habitat grâce à des comptes Azure Cosmos DB fortement répliqués dans de nombreuses régions secondaires. Certains comptes sont répliqués dans les 40 régions Azure où nous traitons du trafic ; d’autres, dans au moins une région par continent.

Nous avons dû intégrer à Habitat, plus tôt que prévu, une couche transparente de déplacement et de routage des données pour transférer les jeux de données entre comptes ayant des topologies de réplication différentes.

Cette approche reste toutefois contrainte par la capacité et se limite donc à quelques jeux de données soigneusement sélectionnés.

S’appuyer sur le cache intégré pour tout le reste

Les charges d’Habitat sont très majoritairement des lectures : les applications récupèrent sans cesse paramètres, états et autres propriétés. Une part disproportionnée du trafic provient d’un ensemble de travail assez restreint de types fréquemment consultés. Le système se prête donc particulièrement bien à la mise en cache distribuée. Si le cache améliore les performances d’une infrastructure monorégionale, ses bénéfices s’amplifient dans un contexte multirégional, où il peut « masquer » la latence entre régions.

Nous avons intégré à Habitat une couche de cache distribué de type lookaside. Elle conserve une copie des objets et des arêtes récemment consultés dans des serveurs Valkey placés dans notre infrastructure, près du lieu de traitement des requêtes utilisateur. Ces caches utilisent généralement une durée de vie (TTL) qui arbitre entre taux de succès et obsolescence des données. Des TTL courts réduisent l’obsolescence, mais atténuent les bénéfices du cache : les éléments expirent vite et doivent être récupérés plus souvent. Des TTL plus longs améliorent le taux de succès, mais servent des données obsolètes plus longtemps, dégradant l’expérience utilisateur et rendant le comportement des produits imprévisible.

Une autre approche consiste à exécuter des invalidations explicites lorsque l’application écrit dans les mêmes données sous-jacentes. Cela améliore nettement la fraîcheur des données en cache, mais peut être difficile à mettre en œuvre correctement. Cette approche reste aussi exposée à des cas limites, comme les défaillances partielles, qui laissent le cache obsolète. Les déploiements multirégionaux amplifient ces problèmes : les réseaux interrégionaux sont moins fiables et le cache entre en concurrence avec la réplication du stockage sous-jacent. Ajouter des TTL borne la durée maximale d’obsolescence, mais conserve le compromis inhérent aux TTL évoqué plus haut.

Nous avons adopté une approche d’invalidation plus avancée, dans la lignée de systèmes comme TAO de Meta. Le cache intégré d’Habitat utilise la capture des modifications de données (CDC) via le flux de modifications d’Azure Cosmos DB pour propager les invalidations mondialement en quelques secondes, alliant taux de succès élevé et faible obsolescence. Un service de notre infrastructure consomme ce flux et invalide les caches locaux lorsque les données sous-jacentes sont mises à jour. La lecture suivante provoque un défaut de cache, puis le cache est rempli avec la dernière version des données.

Réduire le surcoût du proxy avec Rust

Nous avons aussi fortement réduit la latence en supprimant des surcoûts dans le service Habitat lui-même, grâce à une réécriture en Rust, plus performant que le code Python d’origine.

Ensemble, ces changements ont fait passer notre latence p50 globale en lecture, à l’échelle mondiale, d’environ 120 ms à environ 10 ms : une amélioration d’un facteur 12 depuis nos premiers efforts sur les performances au début de l’année.

Figure 05 · Improving performance at a global scale

p50 latency for reads

Three major design changes improved read latency

roughly 120 ms → roughly 10 ms

12x improvement

Milliseconds020406080100120140160Temps123
  1. critical data replicated into nearby geos
  2. in-region caching launched
  3. rust rewrite launched

Si le cache a fortement réduit la latence médiane, les requêtes les plus lentes doivent encore récupérer des données non mises en cache dans le stockage sous-jacent, souvent dans des régions éloignées. À mesure que de nouvelles capacités sont disponibles et que nous optimisons le stockage, nous prévoyons de traiter un défi plus fondamental : placer d’emblée les données plus près de leur lieu d’accès.

Passage à l’échelle de la CDC

Une CDC fiable et évolutive — qui propage les modifications de la base vers les systèmes en aval — est essentielle bien au-delà de la stratégie de cache d’Habitat. Des millions de modifications capturées par seconde, sur des milliers de conteneurs et des millions de partitions, transitent par plus de cent topics Kafka. Elles alimentent aussi des index secondaires à cohérence éventuelle, des pipelines de déplacement de données, des analyses hors ligne et d’autres fonctionnalités produit en temps réel. Avec l’expansion mondiale de notre infrastructure sous-jacente, l’écoute des modifications de lignes est devenue toujours plus complexe. Pour enregistrer une fonction de rappel à exécuter dès que des lignes de son type sont modifiées, un client doit notamment identifier les comptes et conteneurs Cosmos qui hébergent ses données, les déploiements du service CDC qui écoutent ces conteneurs dans chaque région, puis dimensionner correctement le parc de workers CDC, Kafka et son consommateur. Notre plateforme CDC vise à masquer cette complexité aux développeurs produit. Elle propose une interface simple où les clients enregistrent une fonction à appeler sur les lignes modifiées ; nous gérons toute l’infrastructure et sa mise à l’échelle.

Un plan de contrôle interne vérifie en continu la capture de tous les conteneurs requis, choisit les régions Cosmos à lire et répartit efficacement le travail entre des milliers de workers dans plusieurs régions géographiques. L’utilisation de régions répliquées et de lectures de flux moins prioritaires protège le trafic Habitat sensible à la latence des tâches de capture en arrière-plan. Dans un parc aussi vaste, plantages de workers, problèmes de conteneurs, erreurs du stockage des baux, configurations invalides et défaillances des destinations surviennent en permanence. Nous avons renforcé le cycle de vie des workers CDC et la gestion des baux, isolé les défaillances entre flux et ajouté des garde-fous pour les changements de configuration et les déploiements. Nous utilisons des files de lettres mortes pour éviter qu’un échec de livraison permanent ne bloque la tête de file. Nous tolérons les pannes régionales en basculant les lecteurs vers d’autres régions Cosmos. À notre échelle, nous avons même dû modifier le SDK CDC d’Azure pour rendre ses points de contrôle plus efficaces, en les regroupant en mémoire et en ne les persistant que périodiquement.

Malgré la complexité de son usage interne d’Azure Cosmos DB, Habitat a toujours eu pour vocation de masquer les détails d’infrastructure aux développeurs pour accélérer le développement produit. Notre plateforme CDC suit le même principe.

Perspectives

Une petite équipe a pu soutenir une plateforme de stockage en forte croissance en gardant une API de stockage volontairement restreinte, en continuant à faire évoluer le service Python et en privilégiant les défis techniques les plus urgents. Nous avons privilégié d’abord la fiabilité du trafic produit critique, puis les performances en lecture pour les utilisateurs du monde entier, et enfin l’efficacité opérationnelle à grande échelle. Cette approche a permis une croissance rapide et de nouveaux cas d’usage, tout en améliorant la fiabilité, les performances et la rapidité du développement produit.

Pour adapter Habitat et le stockage des conversations au prochain milliard d’utilisateurs, nous devons surmonter la difficulté de répliquer nos données dans toute notre infrastructure, à une échelle encore plus grande. Pour l’anticiper, nous développons en interne un système de stockage en ligne sur mesure à l’échelle de l’exaoctet, optimisé pour les types de données volumineux d’Habitat. Ce système en développement combine le cœur RocksDB Cloud de Rockset avec une réplication fondée sur Raft. Il implémente le même modèle documentaire qu’Azure Cosmos DB, mais utilise un stockage désagrégé et une réplication physique pour réduire la capacité flash nécessaire, au prix d’un débit de pointe en requêtes par seconde plus faible.

Si vous souhaitez travailler sur ce type d’infrastructure de données à une échelle sans précédent, consultez nos offres d’emploi⁠.

Auteur

OpenAI