Rask skalering av nettlagring for over én milliard ChatGPT‑brukere
Slik tilpasset vi applikasjonslagringsplattformen Habitat i Python for å håndtere enestående vekst.
Av Jon Lee, Chaomin Yu og Ben Ries, medlemmer av den tekniske staben
Alle OpenAI-produkter er avhengige av rask og pålitelig tilgang til data, enten noen logger på, sjekker Codex-innstillingene sine eller starter en ny samtale i ChatGPT. Hver av disse handlingene kan kreve mange separate dataoppslag før produktet kan svare. Hvis forespørslene er trege, føles produktet tregt. Hvis forespørslene mislykkes, slutter produktet helt å fungere.
Habitat er nettlagringsplattformen vi bygget for at OpenAI-produkter raskt og pålitelig skal få tilgang til informasjonen de trenger. Habitat håndterer nå over 70 millioner forespørsler i sekundet og støtter produkter som brukes av over én milliard mennesker hver uke, i nesten 40 geografiske regioner. Habitat ble først lansert for å støtte GPT‑er under DevDay 2023, som et enkelt Python-bibliotek på klientsiden koblet til én database. I dag er det et komplekst distribuert system som betjener mer enn 500 petabyte med data.
Figur 01 · Hva er Habitat?
Nettlagringsplattform
Habitat er nettlagringsplattformen vi bygget for at OpenAI-produkter raskt og pålitelig skal få tilgang til informasjonen de trenger.
- Forespørsel
- Svar
- Endringer (CDC)
Å bygge og drifte infrastruktur i denne skalaen er ingen enkel oppgave, men heller ikke spesielt utfordrende. Det som gjorde situasjonen vår unik, var den enestående hastigheten vi måtte skalere med for å møte den enorme veksten i brukere og produktetterspørsel, samtidig som vi bygget ut en moden plattform. Systemutviklere bygger ofte for ti ganger så stor skala og håper at det holder i noen år mens de forbereder den neste tidoblingen. I vårt tilfelle har vi vokst mer enn ti ganger fra år til år de siste tre årene. Derfor har byggingen og driften av Habitat bestått av en rekke taktiske beslutninger i nøye rekkefølge: Vi har måttet forstå hver komponent på laveste nivå for å hente mest mulig ut av den eksisterende teknologistakken, samtidig som vi har håndtert knapphet på lagrings- og beregningskapasitet for å kjøpe oss tid til grunnleggende investeringer.
- 70 mill.+
forespørsler per sekund
- 1 mrd.+
mennesker hver uke
- 500 PB+
data
Etter hvert som OpenAI vokste, måtte Habitat vokse i takt: først ved å bli pålitelig nok for virksomhetskritisk produkttrafikk, deretter raskt nok for globale brukere og til slutt i stand til å operere smidig i enorm skala. Dette innlegget er det første i en serie på to deler om hvordan vi skalerte nettlagringen. Her forteller vi hvordan Habitat utviklet seg, hvorfor vi gjorde det om fra et bibliotek til en tjeneste, og hvordan vi strakk en tjeneste skrevet i et uvanlig språk for serverstakken – Python – til å bli et pålitelig plattformlag for lagring.
I et senere innlegg går vi nærmere inn på hvordan vi gjorde flerleietakerløsningen pålitelig i stor skala, den lagdelte strategien vår for å optimalisere leseytelsen og hvordan vi skalerte samarbeidet med Azure Cosmos DB for å håndtere enestående etterspørsel pålitelig.
Habitat begynte med en enkel idé: Produktutviklere skal ikke måtte tenke på databaseadministrasjon. Habitat ble først lansert for å støtte GPT‑er under DevDay 2023, som et lite Python-bibliotek som samhandlet med hovedserveren til ChatGPT. Det støttet et lite sett med operasjoner som i bakgrunnen ble koblet til databaseapplikasjonen Azure Cosmos DB.
Bibliotekets oppgave var å gi produktteamene en enkel måte å lagre og hente data på, uten at de måtte beherske de underliggende detaljene. Habitat tok seg av det nødvendige arbeidet: å finne ut hvilken type data det gjaldt, hvor de skulle hentes fra eller sendes, om forespørselen var tillatt, og så videre.
Produktutviklerne slapp å forholde seg til skjemaoppslag, ruting, autorisasjon, kryptering, serialisering, utforming av forespørsler og tilkoblingssamlinger. De trengte ikke engang å tenke på hvor dataene kom fra: Azure Cosmos DB, hurtigbuffere eller andre typer lagring.
Figur 02 · Habitat-tjenesten
Forenklet forespørselsflyt i Habitat
Ved å skille ut lagringslogikken i en frittstående tjeneste fikk vi ett sentralt kontrollpunkt for utrulling, observerbarhet og plattformforbedringer.
- Forespørsel
- Svar
Python-biblioteket fungerte godt, og Habitat ble raskt tatt i bruk av produktutviklere hos OpenAI, selv uten noen samordnet sentral satsing på å gå bort fra selvbetjent Postgres og Azure Cosmos DB.
Etter hvert som produktbehovene utviklet seg, var det også enkelt for produktutviklerne å legge til støtte for funksjoner som hurtigbufring på klientsiden, komprimering eller kryptering i det delte biblioteket.
I midten av 2025 hadde Habitat nådd grensene for en implementering på klientsiden. Etter hvert som Habitat-laget ble mer komplekst og OpenAI fikk flere tjenester, ble bakoverkompatible protokollendringer urealistiske.
I ett tilfelle ønsket vi å begrense konsekvensene av et driftsavbrudd i én region for de mest kritiske datasettene våre ved å migrere dem til et sett med regionalt distribuerte Azure Cosmos DB-kontoer. Endringen krevde at vi la inn ekstra rutingslogikk i klienten bak et deaktivert funksjonsflagg, sørget for utrulling til alle klienter og deretter aktiverte funksjonsflagget.
Det tok flere dager å koordinere utrullinger på tvers av dusinvis av tjenester og samarbeide med hvert team. Før vi aktiverte dette, innså vi at vi ønsket å innføre skygging for å sikre at logikken for partisjonering var riktig. Det tok ytterligere et par dager å rulle ut. En feilretting for noe vi oppdaget var galt? Enda et par dager. Til slutt var vi klare til å aktivere flagget. Da rullet et av teamene av andre årsaker tjenesten sin tilbake til en tidligere klient med feil, noe som utløste nettopp driftsavbruddet vi hadde jobbet så hardt for å unngå.
Endringer i klientbiblioteket krevde komplisert koordinering mellom dusinvis av tjenester – en prosess som ble stadig mer skjør, ineffektiv og utsatt for driftsfeil. For å redusere denne driftsmessige spredningen ved fremtidige utrullinger bestemte vi oss for å gjøre Habitat til en egen tjeneste.
Ved å skille ut lagringslogikken i en frittstående tjeneste fikk vi ett sentralt kontrollpunkt for utrulling, observerbarhet og plattformforbedringer. I stedet for å administrere fragmenterte oppdateringer kunne vi innføre forbedringer sentralt, slik at alle OpenAI-produkter fikk nytte av dem umiddelbart.
En sentralisert tjeneste gir oss også ett kontrollpunkt der vi kan tilby de sterkeste grunnmekanismene for datasikkerhet og personvern. I Habitat-tjenesten kan vi håndheve retningslinjer for tilgangskontroll sentralt, utføre revisjonslogging og begrense tilgangen til underliggende lagringsressurser som Azure Cosmos DB. Habitat spiller en avgjørende rolle i å beskytte brukerdata og hindre uautorisert tilgang fra eksterne, interne og agentbaserte aktører.
Vi visste at vi trengte en tjeneste, men ønsket ikke å gå bort fra Python helt ennå, selv med den ekstra belastningen Python medførte som tjeneste. Bruk av Python til en tjeneste med høy gjennomstrømming økte nettverksforsinkelsen og ga betydelige skaleringskostnader for CPU og minne sammenlignet med lokal kjøring av biblioteket. Vi innså også at ineffektiviteten i Python ikke ville være akseptabel ved 100 ganger så stor skala, og at en omskriving derfor nesten helt sikkert ville bli nødvendig.
Likevel så vi på dette som en strategisk pådratt teknisk gjeld. Hovedmålet vårt var da ikke å optimalisere kostnader eller ressurser, men å fjerne hindringer for produktutviklerne og gjøre plattformen stabil. Ved å godta ytelseskompromissene ved en Python-tjeneste på kort sikt kunne vi prioritere mer presserende utfordringer, etablere kjerne-API-ene våre og bygge ut en robust infrastruktur.
Vi tok også en kalkulert sjanse på at den raske utviklingen av våre egne kodemodeller ville gjøre den tekniske veien enklere fremover. Vi satset på at Codex og GPT ville gjøre migreringen gjennomførbar når tiden kom for å gå helt bort fra Python. Det viste seg etter hvert at vi hadde rett.
Å kjøre Habitat som en Python-tjeneste ville være mindre enn optimalt ytelsesmessig, men var et nødvendig valg. Python lar oss jobbe raskt, men det betyr ikke at vi kunne kaste all forsiktighet over bord og godta vesentlig høyere forsinkelser. Når en gjennomsnittlig brukerforespørsel fører til hundrevis av databasekall, er det det tregeste databasekallet brukeren merker. Vi har erfart at den største utfordringen ved å kjøre en Python-tjeneste i denne skalaen er å håndtere haleforsinkelsene.
Asyncio hjelper Python med å kjøre I/O-bundne arbeidsbelastninger samtidig, men omgår ikke Pythons GIL og gir ikke CPU-parallellitet. I tillegg til I/O-tung videresending av forespørsler håndterer Habitat mange CPU-krevende oppgaver og bakgrunnsoppgaver: ruting, komprimering, kryptering, kontrollsummer, tilstandskontroll av nedstrømstjenester, skygging og sikring av forespørsler.
Med så mange CPU-krevende arbeidsbelastninger og bakgrunnsoppgaver i tjenesten kan planleggingsforsinkelsen i asyncio lett dominere haleforsinkelsen for forespørsler. Før vi finjusterte den første tjenestelanseringen, viste sporinger av forespørsler med p99-forsinkelse eller høyere at nedstrømslagringen svarte raskt, men at forespørslene ofte stoppet opp mens de ventet på at den ansvarlige korutinen skulle planlegges på nytt for å tolke svaret.
Figur 03 · Måling av asyncio-forsinkelsen
Samtidighet er ikke CPU-parallellitet
Python asyncio tillater samtidig behandling av forespørsler, men bare én forespørsel kjøres på CPU-tråden om gangen. Dette påvirker forespørselsforsinkelsen kraftig når mye CPU-arbeid må utføres.
Lite CPU-arbeid
Korte Python-trinn; I/O-venting overlapperMye CPU-arbeid
Lange Python-trinn lar klare svar venteFor Python-tjenester hos OpenAI er det avgjørende å overvåke asyncio-løkken og hvor belastet den er, og deretter finjustere deretter, i tillegg til å måle vanlige utnyttelses- og metningsverdier for minne, CPU, nettverk og disk.
Ved å regelmessig planlegge bakgrunnsoppgaver og registrere forskjellen mellom forventet og faktisk kjøretid kan vi måle planleggingsforsinkelsen i hendelsesløkken empirisk og i sanntid. Ved høy utnyttelse og mange kostbare oppgaver er selv et moderat antall samtidige forespørsler per prosess nok til å skape betydelig variasjon i planleggingen – opptil hundrevis av millisekunder og i enkelte grensetilfeller flere sekunder.
Derfor lar vi hver prosess bare betjene et lite antall samtidige forespørsler og skalerer i stedet kraftig ut antallet Python-arbeidsprosesser.
Under den første tjenestelanseringen avdekket CPU-profilering i produksjon én årsak til høy asyncio-forsinkelse, og dermed høye haleforsinkelser: regelmessig JSON-tolking av konfigurasjonene for funksjonsflagg via Statsig (et verktøy for administrasjon av funksjonsflagg, A/B-testing med mer).
Som standard var Statsig konfigurert til å hente oppdaterte konfigurasjoner hvert minutt uten tidsvariasjon, og konfigurasjonen omfattet alle produksjonsregler for samtlige tjenester. Et annet sted var det tatt en arkitekturbeslutning om å kjøre opptil åtte Python-prosesser per pod for å øke CPU-utnyttelsen og redusere forsinkelsene. Til sammen betydde dette at alle arbeidsprosessene i hver pod på et tidspunkt hvert minutt stoppet behandlingen av pågående forespørsler og i stedet brukte CPU-sykluser på å tolke en enorm konfigurasjonsfil.
Løsningen var enkel da CPU-profileringen hadde avdekket årsaken: distribuere en mindre og mer målrettet konfigurasjon, forlenge oppdateringsintervallet og legge inn litt tidsvariasjon i slike bakgrunnsoppgaver.
For å holde asyncio-forsinkelsen lav er det også avgjørende å fordele forespørslene godt mellom serverprosessene. Uten finjustering kan tilkoblingssamlinger motvirke dette.
Med tilkoblingssamlinger på klientsiden kan én klientprosess som sender mange samtidige forespørsler, opprette bare noen få servertilkoblinger og dermed sende hele belastningen til bare noen få prosesser. Før vi justerte lastbalanseringen, varierte utnyttelsen i tjenesten kraftig. Enkelte prosesser i halen betjente fem til ti ganger så mange samtidige forespørsler som gjennomsnittet.
Vi oppdaget dette ved en tilfeldighet da noen prosesser fortsatt hadde redusert ytelse lenge etter trafikktoppen, til tross for at vi hadde stoppet klienten som overbelastet deler av tjenesten. Vi så faktisk at disse prosessene ble stadig dårligere og mottok flere og flere forespørsler helt til vi startet dem på nytt. Når en pod først ble overbelastet, førte en bestemt mekanisme til at enda mer trafikk ble låst til den. Dette var en type feil noen av kollegene våre kjente godt fra tidligere arbeid: metastabil feil(åpnes i et nytt vindu).
Vi mistenkte at tilkoblingssamlingen var årsaken, og testet dette ved å begrense maksimal varighet for gjenbruk av tilkoblinger. Det begrenset faktisk forverringen og bekreftet at undersøkelsen gikk i riktig retning. Videre undersøkelser viste at Pythons aiohttp TCPConnector som standard gjenbruker tilkoblinger etter LIFO-prinsippet: Tilkoblingen som sist ble returnert, velges for neste forespørsel. Dette er vanligvis et fornuftig standardvalg: Gjenbruk av nylige tilkoblinger gjør at ekstratilkoblinger som ble opprettet for å håndtere trafikktopper, kan bli inaktive og utløpe, noe som reduserer kostnaden ved å opprettholde dem. I vårt tilfelle skapte det en metastabil feil. Under en trafikktopp returnerte forespørsler til tregere, overbelastede servere tilkoblingene til samlingen senere. Dermed ble disse oftere valgt av påfølgende forespørsler, slik at stadig mer trafikk samlet seg på podene som allerede slet. Ved å endre tilkoblingssamlingen til FIFO-gjenbruk brøt vi denne tilbakekoblingssløyfen og reduserte samtidig variasjonen i forespørsler ved stabil drift.
Figur 04A · Tilkoblingssamling på klientsiden
LIFO sender nytt arbeid tilbake til den trege prosessen
Etter en trafikktopp returnerer tregere servere tilkoblingene til samlingen sist. LIFO oppmuntrer til at mer arbeid konsentrerers om de samme trege serverne.
En innledende trafikktopp når A, B og den tregere prosessen C.
Figur 04B · Tilkoblingssamling på klientsiden
FIFO bryter tilbakekoblingssløyfen for gjenbruk av tilkoblinger
FIFO beholder flere aktive tilkoblinger etter en trafikktopp, men fordeler arbeidsbelastningen jevnt mellom alle serverne.
En innledende trafikktopp når A, B og den tregere prosessen C.
I dag er vi hovedsakelig avhengige av Istio og Envoy for tilkoblingssamlinger og bedre balanseringsstrategier som tar hensyn til serverbelastning i hele OpenAI-infrastrukturen, slik at vi unngår problemet fullstendig.
En bivirkning av finjustering for lav asyncio-forsinkelse og det store antallet Python-prosesser er at det blir svært enkelt å overvelde nedstrømsavhengigheter med enorme mengder tilkoblinger – et fenomen kjent som en «tordnende flokk».
En vanlig daglig utrulling kan, hvis den ikke er innstilt til å gå sakte, skape betydelig CPU-belastning når tilkoblinger stadig opprettes og avsluttes. En tilkoblingslekkasje kan også slå ut nettverket ved å mette NAT-gatewayen. Dette er ikke uvanlige problemer for andre tjenester heller, men terskelen for å utløse dem blir betydelig lavere når man har en størrelsesorden flere prosesser. Det metter ofte nettverksrelaterte ressurser som klientene, basert på gjennomstrømmingen alene, ikke forventer å måtte håndtere ved stabil drift.
Vi bruker også Envoy for å samle flest mulig tilkoblinger. Vi bruker Envoy til å oppgradere Pythons HTTP/1-tilkoblinger til HTTP/2 for å dra nytte av multipleksing, og deretter samle tilkoblingene og forlenge levetiden deres. Envoy gir oss også ett sentralt sted for å implementere hastighetsgrenser og effektbrytere som ville vært mindre effektive i hver frittstående Python-prosess.
Figur 05 · Samling av tilkoblinger
De samme forespørslene, færre tilkoblinger
Tilkoblingssamlinger og multipleksing av HTTP/2-tilkoblinger reduserer tilkoblingsbelastningen på nedstrømstjenester.
Én grunn til at vi kunne skalere Python så langt, var Habitats begrensede API, som gjør kostnaden per forespørsel forutsigbar. I stedet for å la klientene lage vilkårlige SQL-spørringer som kan føre til store tabellskanninger eller sammenføyninger på tvers av mange tabeller, tilbyr Habitat et enkelt NoSQL-API. Mangelen på et kraftig API er et bevisst kompromiss i utformingen av Habitat.
Vi forsøker å optimalisere for enkle og forutsigbare forespørsler med konstant arbeidsmengde. Vår erfaring er at slike systemer er vesentlig enklere å skalere og vanskelige å bruke feil. Forespørsler med uforutsigbar spredning er driftsmessig farlige: De kompliserer isolering og lastbalansering og skaper brå økninger i forsinkelsen som er vanskelige å skalere for både tjenesten og klientene.
Før vi gikk over til Habitat og Azure Cosmos DB, ble det meste av OpenAIs nettdata lagret i Postgres. På den tiden var det enkelt å gjennomgå alle spørrings- og skjemaendringer for å sikre at de oppførte seg som de skulle og brukte indekserte data før produksjonssetting. Etter hvert som teamet og produktene vokste, ble dette raskt uhåndterlig og førte ofte til driftsavbrudd når én ny, kostbar spørring i en mye brukt kodebane slo ut databasen.
Problemet er en ubalanse i kostnad: Det er billig og enkelt å skrive SQL-spørringer som er kostbare og vanskelige å kjøre. I Habitat unngår vi dette og gjør kostbare spørringer svært tydelige på klientsiden. Det finnes ingen ubegrensede spørringer som kan overbelaste Habitat. Komplekse sammenføyninger og graftraversering krever at produktteamene gjør noe av tungarbeidet, noe som bidrar til mer effektive løsninger samlet sett.
Habitat tilbyr et NoSQL-API bygget rundt klientdefinerte objekt- og kanttyper, inspirert av TAO(åpnes i et nytt vindu). Klientene forhåndsdefinerer objekter og kanter og hvordan de er knyttet til hverandre, men ikke innholdet i hver type. Relasjonene som oppstår, ligner en graf, men Habitat støtter ikke vanlige spørringer for graftraversering utover direkte kanter fra et bestemt objekt.
Vi partisjonerer grafen slik at hvert objekt og tilhørende kanter ligger sammen i en partisjon på lagringsnivå, men gjør ingen samordnet innsats på databasenivå for å plassere objekter sammen med de eksterne objektene kantene peker til. Resultatet er at modellen enkelt kan partisjoneres for horisontal skalerbarhet. Graftraversering er imidlertid ineffektivt fordi hvert hopp mellom objekter kan kreve henting fra to helt forskjellige Azure Cosmos DB-kontoer lagret i ulike regioner.
For klienter med mer komplekse spørringsbehov tilbyr vi en frakoblet sekundærvisning av Habitat gjennom Rockset. Vi bruker endringsdatafangst (CDC) til å strømme endringer fra nettlagringen til isolerte Rockset-forekomster nesten i sanntid. Hvert klientteam er ansvarlig for å skalere sin egen Rockset-forekomst etter behovene for komplekse spørringer.
Klargjøringen av Rockset gjør det litt mer tungvint for klientene, men vi mener dette er riktig kompromiss nå: enkle spørringer er standarden, mens de som trenger komplekse spørringer, får en alternativ løsning. Denne utformingen isolerer nettlagringen vår fra lesetunge analyse- og søkearbeidsbelastninger.
Ved å utsette omskrivingen av Python i ett år kunne vi konsentrere oss om mer presserende og betydningsfulle utfordringer under den kraftige veksten. Da plattformen var blitt mer moden og veksten fortsatte å tilta, og tjenesten var blitt den nest største hos OpenAI målt i antall kjerner (og den fjerde største målt i Envoy-omfang), var tiden endelig inne for å gå videre fra Python. På det meste hjalp Python oss med å håndtere over 20 millioner forespørsler i sekundet.
I andre kvartal 2026 klarte vi å skrive om hele tjenesten i Rust med bare to utviklere, Codex og GPT‑5.5. Den nye Rust-tjenesten håndterer nå 95 prosent av produksjonsforespørslene våre. I løpet av de kommende ukene avvikler vi Python fullstendig. Dataene våre viser at Rust-tjenesten er seks ganger mer CPU-effektiv og 15 ganger mer minneeffektiv enn Python-versjonen, med betydelig lavere gjennomsnitts- og haleforsinkelser. Vi planlegger å dele flere erfaringer i et senere blogginnlegg.
Python-tjenesten – og nå Rust-tjenesten – er bare én side av Habitat. I del to av denne serien om hvordan vi raskt skalerte nettlagringen for å betjene over én milliard ChatGPT‑brukere, skal vi se på lagringslaget og hvordan Habitat håndterer mer enn 500 petabyte og over 70 millioner forespørsler i sekundet.
Hvis du vil jobbe med OLTP-systemer i banebrytende skala og er interessert i denne typen utvikling, kan du se den ledige stillingen i teamet vårt.


