Overslaan naar hoofdinhoud
OpenAI

23 oktober 2026

Engineering

Online opslag snel opschalen voor meer dan 1 miljard ChatGPT‑gebruikers (deel II)

Hoe we Azure Cosmos DB in ons applicatieopslagplatform Habitat optimaliseerden om ongekende groei op te vangen.

Door Jon Lee, Hrachya Hakobyan en Chaomin Yu, leden van de technische staf

Bezig met laden...

Alle OpenAI-producten hebben snelle, betrouwbare toegang tot gegevens nodig. Ons opslagplatform Habitat voorziet daarin. Het moet binnen milliseconden reageren voor meer dan 1 miljard gebruikers in 40 geografische regio's. Onze infrastructuur stond voor een uitzonderlijke uitdaging: explosieve groei en nieuwe toepassingen ondersteunen en tegelijk de betrouwbaarheid, prestaties en ontwikkelsnelheid blijven verbeteren. Daarvoor moesten we het ontwerp en beheer van ons online opslagplatform herzien. We wogen voortdurend keuzes af volgens een vast patroon: eerst betrouwbaar genoeg worden voor bedrijfskritiek productverkeer, dan snel genoeg voor gebruikers wereldwijd en ten slotte soepel kunnen opereren op enorme schaal.

Deze tweedelige serie beschrijft hoe we Habitat hebben ontwikkeld van een eenvoudige clientbibliotheek en database tot een wereldwijd gedistribueerd opslagplatform dat meer dan 500 petabyte aan gegevens beschikbaar stelt. Deel I ging over de ontwikkeling van Habitat van een Python-client tot een service. Ook bespraken we de technieken waarmee we een op Python gebaseerde service veel verder konden opschalen dan velen voor praktisch haalbaar zouden houden.

In dit artikel, deel II, laten we zien hoe we de onderliggende opslagcomponent hebben opgeschaald: Azure Cosmos DB. In nauwe samenwerking met het Azure-team kwamen we tot een werkbare multi-tenancyaanpak met gezamenlijk beheerde containers, die uitstekende leesprestaties levert op enorme, wereldwijde schaal.

Figuur 01 · Wat is Habitat?

Onlineopslagplatform

Habitat is het onlineopslagplatform dat we hebben gebouwd zodat OpenAI-producten snel en betrouwbaar toegang hebben tot de benodigde informatie.

  • Verzoek
  • Antwoord
  • Wijzigingen (CDC)

Clients

Onlineopslagplatform

Opslagbronnen

  • ChatGPT
  • API
  • Codex
  • Interne services
  • En meer

Habitat

  • CachingCaches
  • ACL-beleidAutorisatie
  • Plaatsing en gegevensresidentieGegevensresidentie
  • VersleutelingGegevensbeveiliging
  • IsolatieMultitenancy
  • SnelheidsbegrenzingRequest shaping
  • RouteringSchema opzoeken · Gegevensresidentie
  • Azure Cosmos DBOnlineopslag
  • NanobaseOnlineopslag
  • ValkeyCaches
  • BlobopslagOpslagbronnen
CDC-servicesChange Data Capture
  • Databricks
  • Rockset
  • Kafka
  • En meer

Multi-tenancy betrouwbaar maken op grote schaal

Naarmate bedrijven groeien, stappen infrastructuurteams vaak over van single-tenantsystemen naar multi-tenantsystemen. Bij single-tenancy onderhoudt elk team voor een productonderdeel zijn eigen systeem. Dat beperkt de impact van storingen, maakt verantwoordelijkheden duidelijk en isoleert workloads. Naarmate teams en productonderdelen groeien, wordt dit duur in gebruik. Single-tenancy maakt elk productteam verantwoordelijk voor capaciteitsplanning en leidt vaak tot aanzienlijke overcapaciteit.

Bij multi-tenancy ligt de regie juist bij een centraal databaseteam, met meer kennis en ervaring in het toewijzen van resources. Maar multi-tenancy brengt eigen problemen met zich mee, zoals hinderlijke buren: één tenant gebruikt een ongebruikelijk groot deel van de resources, ten koste van de andere tenants.

Voor Habitat moesten we al deze afwegingen maken om een betrouwbaar en efficiënt opslagsysteem op grote schaal te ontwerpen. Vandaag is Habitat een multi-tenantdatabaselaag voor veel OpenAI-producten. Maar we hebben een cirkel doorlopen: van één multi-tenant Azure Cosmos DB-container naar afzonderlijke single-tenantcontainers als onderliggende opslag, en daarna weer terug naar een multi-tenantcontainer als standaard. We staan nog maar aan het begin van multi-tenancy in Habitat. We ondersteunen veel toepassingen, maar hebben investeringen op dit gebied kunnen uitstellen door waar mogelijk de ingebouwde basisfuncties van Azure Cosmos DB te benutten.

Een korte inleiding tot Azure Cosmos DB-containers

Voordat we ons traject met Azure Cosmos DB bespreken, eerst wat basisinformatie:

  • Een Azure Cosmos DB-account definieert een verzameling containers en een replicatiebeleid

  • Elke container wordt ingericht voor een bepaalde doorvoer, uitgedrukt in request units per seconde (RU/s)

  • Gegevens binnen elke container worden op de gebruikelijke manier verdeeld over shards op basis van een opgegeven logische partitiesleutel, met gedocumenteerde limieten voor opslag en doorvoer per logische partitiesleutel

  • Azure Cosmos DB verdeelt logische partitiesleutels over een kleiner aantal onderliggende fysieke partities. Die worden opgesplitst zodra de opslag een drempel overschrijdt of de container meer fysieke partities nodig heeft om de ingerichte doorvoer te leveren

Fase I: Vertrouwen op de basisfuncties van Azure Cosmos DB

Aanvankelijk lieten we alle clientbelasting door en vertrouwden we op de opgegeven limiet van 10K RU/s per logische partitiesleutel om tegendruk te bieden. In het begin gebruikten we bovendien maar één standaardcontainer voor Azure Cosmos DB per account. Dit werkte redelijk goed, maar bleek om een paar redenen problematisch:

Limieten voor logische partitiesleutels

Door vroege API-keuzes lieten we clients rechtstreeks de logische partitiesleutel kiezen. Daardoor gebruiken verschillende producttoepassingen vaak dezelfde veelgebruikte partitiesleutels, zoals user_id of workspace_id. Omdat deze toepassingen de Azure Cosmos DB-limieten voor dezelfde logische partitiesleutels deelden, beperkte het ontwerp de totale doorvoer per gebruiker.

Voordat we overstapten op Habitat en Azure Cosmos DB, liepen we bij het opschalen van Postgres vaak tegen hetzelfde probleem aan: een stroom verzoeken van één zeer actieve organisatie of veelgebruikte sleutel — één tenant met een onevenredig hoge belasting — kon de hele database platleggen. We hebben samen veel werk gestoken in het cachen van die sleutels en het inbouwen van leases bij cachemissers, zodat de daaruit voortkomende belasting de onderliggende database niet overbelast.

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—

Hinderlijke buren

De gedocumenteerde limieten voor gegevensomvang en doorvoer gelden voor logische partitiesleutels, maar worden in werkelijkheid afgedwongen op de fysieke partitie. In de praktijk betekent dit dat logische partities geen 10.000 RU/s kunnen halen. Ze delen de limieten van de fysieke partitie namelijk met alle andere logische partitiesleutels die zich op diezelfde fysieke partitie bevinden.

Hierdoor konden hinderlijke buren veel ongerelateerde logische partitiesleutels beïnvloeden: workloads voor nichefuncties verstoorden zo essentiële aanmeld- en registratieprocessen.

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—

Zwakke partities

Ook de doorvoerlimiet van een fysieke partitie varieert, afhankelijk van de totale doorvoer die aan de Azure Cosmos DB-container is toegewezen. De ingerichte doorvoer van de container wordt ongeveer gelijk verdeeld over de fysieke partities van die container.

Als het gegevensvolume groeit, worden fysieke partities gesplitst. Het totale aantal partities neemt dan toe, terwijl de totale ingerichte doorvoer gelijk blijft. Hierdoor daalt de effectieve doorvoerlimiet per partitie naarmate de gegevensomvang groeit.

Voor onze meest opslagintensieve, blobachtige toepassingen ontstaat zo een probleem: alleen al de groei van de opslag verlaagt de doorvoercapaciteit voor actieve workloads, zelfs als het aantal verzoeken en het gebruik stabiel blijven.

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

Fase II: Workloadisolatie en single-tenancy uitproberen

Afzonderlijke containers helpen deze problemen met partitiesleutellimieten en hinderlijke buren deels op te lossen. Elke afzonderlijke container kan eigen, onafhankelijke fysieke partities krijgen. Alleen workloads binnen die container kunnen elkaar dan nog hinderen of overlappende partitiesleutels gebruiken. Daar staat tegenover dat het inrichten van nieuwe containers overhead met zich meebrengt: elke container vereist een eigen capaciteitsplanning. Daarom willen we alleen containers aanmaken wanneer een service of toepassing daar logisch om vraagt.

We gingen afzonderlijke Azure Cosmos DB-containers gebruiken voor de meest kritieke nieuwe toepassingen die sterke isolatie vereisten. Daarnaast gebruikten we een script om zwakke partities te beheren door de totale ingerichte doorvoer per container af te stemmen op het aantal fysieke partities. Daarmee vermeden we de meeste problemen waarmee we te maken hadden.

Maar omdat we met een standaardcontainer waren begonnen, zaten veel bestaande kritieke toepassingen daar helaas aan vast zolang er geen gegevensmigratie plaatsvond. Om kritieke services te beschermen die nog afhankelijk waren van gegevens in de gedeelde standaardcontainer, adviseerden we teams vaak om voor nieuwe services of grote productfuncties aparte containers aan te maken. Naarmate we opschaalden, nam de druk op de standaardcontainer toe, net als het aantal productie-incidenten. We gingen containers inrichten voor elke nieuwe service of grote productfunctie, puur om de standaardcontainer tegen extra belasting te beschermen.

Dit voorkwam veel platformbrede storingen en beperkte de impact tot uitval of verminderde prestaties van afzonderlijke functies of services. Uiteindelijk werd de overhead van het inrichten van nieuwe containers echter een probleem:

Geen stabiele totale groei

In de oude gedeelde standaardcontainer zou een nieuwe toepassing die van 0 naar 1 miljoen QPS groeide het totale gebruik waarschijnlijk nauwelijks beïnvloeden. In een geïsoleerde container kon diezelfde groei van 0 naar 1 miljoen QPS echter een belasting opleveren die 1.000 keer hoger lag dan de uitgangswaarde, die alleen op intern testgebruik was gebaseerd.

Met afzonderlijke containers moesten teams er nu aan denken om vóór een lancering de verwachte doorvoercapaciteit in te richten. Productteams zetten hun functies vaak in productie zonder vooraf op te schalen. Op de lanceringsdag zaten we dan in crisisoverleg en probeerden we op het laatste moment containers op te schalen.

Het mengen van workloads is een belangrijk voordeel van multi-tenantsystemen dat we met deze containerstrategie opgeven voor betere isolatie.

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

Capaciteitsplanning

Gaandeweg vereiste ook het bewaken van het gebruik van afzonderlijke containers diepgaande productkennis: wanneer zou het verkeer verschuiven of groeien?

We kunnen een eenvoudig control-plane-script leveren dat de ingerichte doorvoer per container opschaalt op basis van groeitrends. Maar zonder stabiele totale groei moest vrijwel elk productteam bij OpenAI zich met capaciteitsplanning bezighouden om correct op te schalen.

Organisatorisch was dit niet schaalbaar: het verschilde sterk per serviceteam hoeveel aandacht het besteedde aan de capaciteitsinrichting van Azure Cosmos DB.

Fase III: Multi-tenancy als standaard, met de mogelijkheid om gegevens te verplaatsen

Naarmate de organisatie groeide, werden die operationele problemen steeds moeilijker beheersbaar. Doordat er geen centraal team was dat de planning deed, planden veel teams slecht. Daarom keerden we uiteindelijk terug naar een multi-tenantoplossing. Samen met het Azure-team ontwikkelden we oplossingen voor onze oorspronkelijke multi-tenancyproblemen, op basis van een gedeeld ontwerp:

Veelgebruikte sleutels begrenzen

Door de meest gebruikte sleutels als eerste te begrenzen, voorkomen we dat hinderlijke buren alle beschikbare doorvoer van een fysieke partitie verbruiken. Zo beperken we het effect waarbij één veelgebruikte sleutel het hele platform kan raken.

Quality of Service (QoS)

QoS met prioriteitsniveaus voor verzoeken voorkomt op vergelijkbare wijze dat offline workloads, zoals bulk-inserts of gegevensextracties, alle doorvoer van een fysieke partitie gebruiken. Door verzoeken voor deze workloads een lagere prioriteit te geven, worden ze als eerste begrensd. Zo voorkomen we dat interactieve verzoeken met hogere prioriteit voor eindgebruikers worden begrensd.

Serverloze modus

Azure Cosmos DB had al een serverloze modus die ons probleem met zwakke partities in de modus met vooraf ingerichte capaciteit had kunnen oplossen. Er was echter een groot nadeel: die schaalde alleen op basis van opslaggebruik en beperkte het RU-gebruik tot 5K RU/s per fysieke partitie. Dat zou ons probleem met zwakke partities oplossen, maar opschalen van RU-intensieve toepassingen onmogelijk maken.

Het Azure Cosmos DB-team bouwde voor ons een verbeterde serverloze modus waarmee elke fysieke partitie tot 10K RU/s kon opschalen. Naast splitsingen op basis van opslaggebruik werden splitsingen op basis van RU-gebruik ingevoerd. Daardoor hoefden we containers niet meer handmatig te bewaken en op te schalen.

Dankzij deze wijzigingen konden we weer één gedeelde container gebruiken. Dat heeft de capaciteitsplanning voor productteams, zowel vooraf als doorlopend, aanzienlijk vereenvoudigd, met behoud van isolatie tussen workloads. In de maanden daarna hebben we geen incidenten meer gehad door capaciteitsinrichting of hinderlijke buren, ondanks de steeds snellere productontwikkeling.

Betere betrouwbaarheid door gezamenlijk beheer

Wanneer bedrijven de schaal van OpenAI bereiken, worden beheerde services minder volledig "beheerd". Veel workloads worden uitzonderingsgevallen binnen de infrastructuur van de cloudprovider. Toen OpenAI een van de grootste gebruikers van Azure Cosmos DB werd, vroeg succesvol beheer om een andere aanpak: gedeelde tests en dashboards, rechtstreeks contact tussen engineers en gezamenlijke verantwoordelijkheid voor storingen die alleen op onze schaal optreden. Ons grootste Azure Cosmos DB-account slaat nu tientallen petabytes aan gegevens op en verwerkt meer dan 20 miljoen QPS. Voor zover wij weten, zijn we het enige bedrijf dat Azure Cosmos DB op deze schaal heeft ingezet.

Eind 2024 maakte een regionale storing duidelijk waarom deze samenwerking nodig was. Een stroomstoring trof toen de primaire Azure-regio van een van onze grootste Azure Cosmos DB-accounts. Bij de daaropvolgende failover bleek dat onze grootste accounts meerdere uren nodig hadden om over te schakelen naar een secundaire regio. Noch ons team, noch het Azure Cosmos DB-team had dit op onze schaal getest.

Ongeveer een maand later veroorzaakten we nog een ernstige storing toen we die accounts terugschakelden naar de oorspronkelijke regio. Een plotselinge golf verbindingen naar de oorspronkelijke regio overbelastte daar de Azure Cosmos DB-gateway. Door een eigenaardigheid in de failoverafhandeling van de Azure Cosmos DB-client in gatewaymodus maakten alle clients onmiddellijk verbinding met de oorspronkelijke regio en stuurden er verzoeken naartoe, terwijl slechts een deel van de fysieke partities was teruggezet.

Bij elke storing doorliepen zowel OpenAI als Azure hun incidentbeheerprocessen. Daarbij werden meerdere onderliggende oorzaken gevonden en oplossingen doorgevoerd. Maar deze storingen waren symptomen van een groter, structureel probleem in de manier waarop ons team en het Azure Cosmos DB-team werkten en testten. Aanvankelijk konden we dankzij beheerde services snel vooruit en ons richten op bedrijfsdoelen. Op grote schaal nemen beheerde services minder werk uit handen en is intensieve samenwerking met de provider nodig op elk niveau, van ontwerp tot dagelijks beheer.

Vandaag bewaken de engineeringteams van Habitat en Azure samen elke laag van Habitat, van onze servicelagen tot de fysieke opslaglagen van Azure Cosmos DB. We beheren en testen wijzigingen op een Azure Cosmos DB-account dat even groot is als onze productieomgeving, maar daar geen deel van uitmaakt. We testen en verbeteren SDK's samen en bepalen best practices voor het opschalen en dimensioneren van onze Azure Cosmos DB-accounts. Onze engineers hebben via Teams rechtstreeks contact met elkaar. We kunnen elkaar zelfs direct oproepen bij incidenten, zonder de verschillende supportniveaus te doorlopen.

Het afgelopen jaar hebben we intensief samengewerkt om het control plane en de gateway van Azure Cosmos DB schaalbaarder te maken. We hebben bescherming tegen overbelasting en caching van diverse Azure Cosmos DB-metadata aan de gateway toegevoegd om de metadatapartitie te beschermen. Ook hebben we de belasting vanuit onze Python-processen voor habitat-service verminderd door connection pooling en meer hergebruik van verbindingen, workloads waar mogelijk bij elkaar geplaatst en kritieke workloads via aparte VPC's geïsoleerd van offline workloads.

Deze intensieve technische samenwerking was het afgelopen jaar cruciaal voor de stabiliteit van onze Azure Cosmos DB-omgeving. Elk systeem dat groot of bedrijfskritiek genoeg is, vereist dit soort teamwerk: grenzen tussen verantwoordelijkheden doorbreken en over organisatiegrenzen heen samenwerken.

Prestaties op wereldwijde schaal verbeteren

Zoals vermeld in deel I is onze kernfilosofie: zorg dat het werkt, maak het snel, maak het goedkoop. Eerst betrouwbaarheid, dan prestaties, dan efficiëntie. Habitat was kritieke infrastructuur voor OpenAI geworden, dus betrouwbaarheid had de hoogste prioriteit. Toen het systeem in 2025 stabieler werd en OpenAI wereldwijd uitbreidde, werd latentie het volgende knelpunt voor gebruikers en productteams.

Reken- en opslagcapaciteit bevonden zich vaak in verschillende regio's, waardoor verzoeken tussen regio's onvermijdelijk waren.

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

De geografische locaties van reken- en opslagcapaciteit dienen uitsluitend ter illustratie.

De latentie varieerde sterk, afhankelijk van waar de gegevens waren opgeslagen en waar het verzoek werd afgehandeld. Om Habitat-verzoeken snel af te handelen, gebruikten productontwikkelaars extra client-side caching en gebundelde verzoeken, beperkten ze lees- en schrijfbewerkingen in de database en haalden ze werk waar mogelijk uit het kritieke pad. Dit leidde tot interessante productontwerpen die beter bestand waren tegen databaseproblemen, maar maakte producten ook complexer en vertraagde de doorontwikkeling. Daarmee schoot Habitat zijn doel voorbij: snelle productontwikkeling mogelijk maken zonder kennis van de database te vereisen.

Dit is in 2026 een belangrijk aandachtspunt voor ons. We hebben een gelaagde strategie ontwikkeld om leesbewerkingen te versnellen. Die vormen meer dan 90% van alle Habitat-verzoeken:

Gegevens dicht bij gebruikers opslaan als de capaciteit het toelaat

We hebben diverse Azure Cosmos DB-accounts in Azure-regio's wereldwijd voor gebruikers met eisen aan gegevensresidentie. Ook voor gebruikers zonder harde eisen aan gegevensresidentie verbetert opslag dicht bij de gebruiker de ervaring dankzij een lagere latentie.

In de praktijk kunnen we dit buiten toepassingen voor gegevensresidentie niet breed realiseren, omdat de fysieke cloudcapaciteit de plaatsingsmogelijkheden beperkt. Onze datasets zijn zo groot dat veel regio's niet de enorme opslagcapaciteit kunnen bieden die nodig is voor hun evenredige aandeel in het gebruikersverkeer.

In regio's met beperkte datacentercapaciteit, stroom of koeling staan we soms voor een directe keuze: capaciteit reserveren voor lokale opslag en lagere Habitat-latentie, of die capaciteit gebruiken voor extra rekenkracht om verzoeken af te handelen en opslagverzoeken naar verder weg gelegen regio's sturen.

Plaatsingsbeslissingen zijn daardoor vaak een productafweging tussen A) optimale latentie voor verschillende producten en gebruikersgroepen en B) de beschikbare opslag- en rekencapaciteit.

Alleen de kleinste en meest latentiegevoelige datasets breed repliceren

Voor workloads waarbij latentie het meest kritiek is, zoals authenticatiemetadata die bij elk verzoek nodig zijn, verlagen we de RTT tussen de rekeninfrastructuur en Habitat met Azure Cosmos DB-accounts die naar veel secundaire regio's repliceren. Sommige accounts repliceren naar alle 40 Azure-regio's waar we verkeer afhandelen; andere naar ten minste één regio per continent.

We hebben eerder dan gewenst een transparante laag voor gegevensverplaatsing en routering in Habitat moeten bouwen, zodat we datasets kunnen verplaatsen tussen accounts met verschillende replicatietopologieën.

Maar ook deze aanpak wordt uiteindelijk beperkt door capaciteit en blijft daarom voorbehouden aan enkele zorgvuldig geselecteerde datasets.

Geïntegreerde caching gebruiken voor de rest

Habitat-workloads bestaan overwegend uit leesbewerkingen: applicaties halen voortdurend instellingen, status en andere eigenschappen op. Een onevenredig groot deel van het verkeer komt voort uit een relatief kleine werkset van veelgebruikte typen. Dit maakt het systeem bijzonder geschikt voor gedistribueerde caching. Caching verbetert de prestaties al binnen één regio, maar de winst is nog groter bij meerdere regio's. Daar kan caching de latentie tussen regio's "verbergen".

We hebben een gedistribueerde lookaside-cachelaag in Habitat geïntegreerd. Die bewaart kopieën van recent opgevraagde objecten en relaties op Valkey-servers in onze infrastructuur, dicht bij de plek waar gebruikersverzoeken worden verwerkt. Zulke caches gebruiken doorgaans een TTL die een afweging maakt tussen de hitratio en de mate van veroudering. Korte TTL's beperken veroudering, maar verminderen de voordelen van caching: items verlopen snel en moeten vaker opnieuw worden opgehaald. Langere TTL's verhogen de hitratio, maar leveren langer verouderde gegevens. Dat leidt tot een slechte gebruikerservaring en onvoorspelbaar productgedrag.

Een andere aanpak is om cache-items expliciet ongeldig te maken wanneer de applicatie schrijfbewerkingen uitvoert op dezelfde onderliggende gegevens. Dit houdt gecachete gegevens veel actueler, maar is lastig correct te implementeren. Bovendien blijven er randgevallen, zoals gedeeltelijke fouten, waarbij de cache verouderde gegevens houdt. Implementaties in meerdere regio's versterken deze problemen: netwerken tussen regio's zijn minder betrouwbaar en er ontstaan racecondities tussen de cache en de replicatie van de onderliggende opslag. Aanvullende TTL's begrenzen hoelang gegevens maximaal verouderd blijven, maar brengen nog steeds dezelfde hierboven beschreven afweging met zich mee.

We hebben een geavanceerdere aanpak voor invalidatie gekozen, in navolging van systemen zoals TAO van Meta. De geïntegreerde cache van Habitat gebruikt change data capture (CDC) via de change feed van Azure Cosmos DB om invalidaties binnen seconden wereldwijd door te geven. Zo halen we hoge hitratio's en houden we gegevens actueel. Een service in onze infrastructuur verwerkt deze change feed en maakt items in lokale caches ongeldig wanneer de onderliggende gegevens worden bijgewerkt. Bij de volgende leesbewerking levert dat een cachemisser op, waarna de cache wordt gevuld met de nieuwste versie van de gegevens.

Proxy-overhead verminderen met Rust

We hebben de latentie ook aanzienlijk verlaagd door overhead in de Habitat-service zelf weg te nemen. Daarvoor hebben we de code herschreven in Rust, dat beter presteert dan de oorspronkelijke Python-code.

Samen hebben deze wijzigingen onze totale wereldwijde p50-leeslatentie verlaagd van ongeveer 120 ms naar ongeveer 10 ms: een verbetering met een factor 12 sinds we ons eerder dit jaar op prestaties zijn gaan richten.

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

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

Caching heeft de mediane latentie sterk verlaagd, maar de traagste verzoeken moeten nog steeds niet-gecachete gegevens uit de onderliggende opslag halen, vaak uit verafgelegen regio's. Naarmate meer capaciteit beschikbaar komt en we opslag efficiënter maken, willen we een fundamentelere uitdaging aanpakken: gegevens vanaf het begin dichter bij de plek opslaan waar ze worden opgevraagd.

Change data capture opschalen

Betrouwbare, schaalbare CDC — het doorgeven van databasewijzigingen aan downstreamsystemen — is niet alleen cruciaal voor de cachingstrategie van Habitat. Miljoenen vastgelegde wijzigingen per seconde, uit duizenden containers en miljoenen containerpartities, stromen door meer dan honderd Kafka-topics. Ze voeden ook secundaire indexen met uiteindelijke consistentie, pipelines voor gegevensverplaatsing, offline analyses en andere realtime productfuncties. Door de wereldwijde groei van onze onderliggende infrastructuur is het steeds complexer geworden om rijwijzigingen te volgen. Wil een client een callback registreren die wordt uitgevoerd zodra rijen van een bepaald type veranderen, dan moet die eerst onder meer bepalen welke Cosmos-accounts en -containers de gegevens bevatten en welke CDC-service in de betreffende regio's naar die containers luistert. Ook moeten de CDC-workers, Kafka en de consumer passend worden geschaald. Ons CDC-platform neemt al die complexiteit weg voor productontwikkelaars. Het biedt een eenvoudige interface waarmee clients een functie registreren die bij gewijzigde rijen moet worden aangeroepen. Wij regelen de technische verbindingen en het opschalen.

Een intern control plane zorgt er continu voor dat wijzigingen uit alle vereiste containers worden vastgelegd, kiest uit welke Cosmos-regio's wordt gelezen en verdeelt het werk efficiënt over duizenden workers in meerdere geografische regio's. Door replicaregio's te gebruiken en leesbewerkingen op de feed een lagere prioriteit te geven, beschermen we latentiegevoelig Habitat-verkeer tegen vastleggingsworkloads op de achtergrond. In zo'n grote omgeving zijn er voortdurend crashes van workers, containerproblemen, fouten in de lease-opslag, ongeldige configuraties en storingen bij bestemmingen. We hebben de levenscyclus en leaseafhandeling van CDC-workers robuuster gemaakt, fouten tussen streams geïsoleerd en waarborgen ingebouwd voor configuratiewijzigingen en uitrol. We gebruiken dead-letter-wachtrijen om te voorkomen dat permanente afleverfouten de rest van de wachtrij blokkeren. We vangen regionale storingen op door readers over te schakelen naar andere Cosmos-regio's. Op onze schaal moesten we zelfs de CDC-SDK van Azure aanpassen om checkpointing efficiënter te maken: we bundelen checkpoints in het geheugen en schrijven ze alleen periodiek weg.

Hoewel Habitat Azure Cosmos DB intern op complexe wijze gebruikt, is het doel altijd geweest om infrastructuurdetails voor productontwikkelaars af te schermen en zo productontwikkeling te versnellen. Voor ons CDC-platform geldt hetzelfde.

Vooruitblik

Een klein team kon een snel groeiend opslagplatform ondersteunen door de opslag-API bewust beperkt te houden, de Python-service verder op te schalen en de dringendste technische uitdagingen voorrang te geven. We richtten ons eerst op betrouwbaarheid voor bedrijfskritiek productverkeer, vervolgens op leesprestaties voor gebruikers wereldwijd en ten slotte op operationele efficiëntie op grote schaal. Deze aanpak maakte snelle groei en nieuwe toepassingen mogelijk, terwijl betrouwbaarheid, prestaties en ontwikkelsnelheid verbeterden.

Om Habitat en gespreksopslag op te schalen voor de volgende miljard gebruikers, moeten we de uitdagingen van gegevensreplicatie over onze infrastructuur op een nog grotere schaal aanpakken. Daarom bouwen we nu al zelf een online opslagsysteem op exabyteschaal, geoptimaliseerd voor omvangrijke Habitat-gegevenstypen. Dit systeem is nog in ontwikkeling en combineert de RocksDB Cloud-kern van Rockset met replicatie op basis van Raft. Het implementeert hetzelfde documentmodel als Azure Cosmos DB, maar gebruikt ontkoppelde opslag en fysieke replicatie om minder flashcapaciteit nodig te hebben, in ruil voor een lagere piek-QPS.

Wil je werken aan dit soort data-infrastructuur op grensverleggende schaal? Bekijk onze vacatures⁠.

Auteurs

OpenAI