Mabilis na pag-scale ng online storage para sa mahigit 1 bilyong user ng ChatGPT
Paano namin inangkop sa Python ang Habitat, ang aming application storage platform, upang tugunan ang walang kapantay na paglago.
Nina Jon Lee, Chaomin Yu, at Ben Ries, mga Miyembro ng Technical Staff
Umaasa ang bawat produkto ng OpenAI sa mabilis at maaasahang access sa data—nagla-log in man ang isang tao, sinusuri ang mga setting ng Codex, o nagsisimula ng bagong pag-uusap sa ChatGPT. Maaaring mangailangan ang bawat pagkilos na iyon ng maraming magkakahiwalay na paghahanap ng data bago makatugon ang produkto. Kapag mabagal ang mga request na iyon, mabagal din sa pakiramdam ang produkto. Kapag pumalya ang mga request na iyon, ganap na hindi gagana ang produkto.
Ang Habitat ang online storage platform na binuo namin upang mabilis at maaasahang ma-access ng mga produkto ng OpenAI ang kinakailangang impormasyon. Mahigit 70 milyong request bawat segundo na ngayon ang pinangangasiwaan ng Habitat, para sa mga produktong ginagamit linggo-linggo ng mahigit 1 bilyong tao sa halos 40 heograpikong rehiyon. Unang inilunsad ang Habitat upang suportahan ang mga GPT sa DevDay 2023, bilang simpleng Python client-side library na nakakonekta sa iisang database. Ngayon, isa na itong kumplikadong distributed system na naghahatid ng mahigit 500 petabyte ng data.
Figure 01 · Ano ang Habitat?
Online storage platform
Ang Habitat ang online storage platform na binuo namin upang mabilis at maaasahang ma-access ng mga produkto ng OpenAI ang kinakailangang impormasyon.
- Request
- Response
- Mga pagbabago (CDC)
Hindi madaling bumuo at magpatakbo ng infrastructure sa ganitong scale, ngunit hindi rin ito partikular na mahirap. Natatangi ang sitwasyon namin dahil sa walang kapantay na bilis ng pag-scale na kinailangan upang suportahan ang napakalaking paglago ng mga user at demand sa produkto habang sabay na bumubuo ng ganap na maunlad na platform. Madalas bumuo ang mga system engineer para sa 10x na scale at umaasang tatagal ito nang ilang taon habang naghahanda sa susunod na 10x. Sa amin, mahigit 10x ang taunang paglago sa nakalipas na tatlong taon. Dahil dito, ang pagbuo at pagpapatakbo ng Habitat ay naging serye ng mga taktikal na pasya at wastong pagkakasunod-sunod: unawain ang bawat component sa pinakamababang antas upang sulitin ang kasalukuyang stack, habang nilalabanan ang kakulangan sa storage at compute capacity upang magkaroon ng panahon para sa mahahalagang pamumuhunan.
- 70M+
request bawat segundo
- 1B+
tao bawat linggo
- 500 PB+
data
Habang lumalaki ang OpenAI, kinailangang sumabay ng Habitat: una, maging sapat na maaasahan para sa kritikal na product traffic; sunod, maging sapat na mabilis para sa mga global user; at sa huli, mahusay na gumana sa napakalaking scale. Ito ang unang post sa seryeng may dalawang bahagi tungkol sa pag-scale namin ng online storage. Sa post na ito, ibabahagi namin kung paano umunlad ang Habitat, kung bakit ginawa namin itong service mula sa library, at kung paano namin ginawang maaasahang storage platform layer ang isang service na nakasulat sa di-karaniwang serving stack language na Python.
Sa susunod na post, detalyado naming tatalakayin kung paano namin tiniyak ang pagiging maaasahan ng multi-tenancy sa malawakang scale, ang layered strategy namin sa pag-optimize ng read performance, at kung paano namin pinalawak ang pakikipagtulungan sa Azure Cosmos DB upang maaasahang tugunan ang walang kapantay na demand.
Nagsimula ang Habitat sa simpleng ideya: hindi dapat kailangang isipin ng mga product engineer ang pamamahala ng database. Unang inilunsad ang Habitat upang suportahan ang mga GPT sa DevDay 2023 bilang maliit na Python library na nakikipag-ugnayan sa pangunahing server ng ChatGPT. Sinuportahan nito ang maliit na pangkat ng mga operation na lihim na tumutugma sa database application na Azure Cosmos DB.
Trabaho ng library na bigyan ang mga product team ng simpleng paraan upang mag-store at kumuha ng data nang hindi kailangang kabisaduhin ang mga nakapailalim na detalye. Habitat ang nag-asikaso sa kinakailangang trabaho: pagtukoy sa uri ng data, kung saan ito dapat manggaling o pumunta, kung pinapayagan ang request, at iba pa.
Hindi kailangang alalahanin ng mga product engineer ang schema lookup, routing, authorization, encryption, serialization, request shaping, at connection pooling. Hindi rin nila kailangang isipin kung saan nagmumula ang data: Azure Cosmos DB, mga cache, o iba pang uri ng storage.
Figure 02 · Habitat service
Pinasimpleng daloy ng Habitat request
Sa paghihiwalay ng storage logic bilang standalone service, nakapagtatag kami ng iisang sentro ng kontrol para sa mga deployment, observability, at pagpapahusay ng platform.
- Request
- Response
Mahusay gumana ang Python library na ito at mabilis na ginamit ng mga product engineer sa OpenAI ang Habitat, kahit walang sentralisadong pagtulak na iwan ang self-serve Postgres at Azure Cosmos DB.
Habang nagbabago ang mga pangangailangan sa produkto, madali ring nakapagdagdag ang mga product developer sa shared library ng suporta para sa client-side caching, compression, o encryption.
Pagsapit ng kalagitnaan ng 2025, naabot na ng Habitat ang mga limitasyon nito bilang client-side implementation. Habang nagiging mas kumplikado ang Habitat layer at dumarami ang mga service ng OpenAI, naging imposible ang mga backward-compatible na pagbabago sa protocol.
Sa isang pagkakataon, gusto naming bawasan ang lawak ng epekto ng outage sa alinmang rehiyon para sa pinakamahalaga naming dataset sa pamamagitan ng paglilipat sa mga ito sa pangkat ng mga Azure Cosmos DB account na nakakalat sa iba’t ibang rehiyon. Kinailangan sa pagbabagong ito ang dagdag na routing logic sa client na naka-disable sa likod ng feature flag, ang pagtiyak na nailunsad ito sa lahat ng client, at saka ang pag-enable sa feature flag.
Inabot nang ilang araw ang pag-uugnay ng mga deployment sa dose-dosenang service at pakikipagtulungan sa bawat team upang ilunsad ito. Bago ito i-enable, naisip naming magdagdag ng shadowing upang matiyak na tama ang sharding logic. Inabot na naman ng ilang araw ang paglulunsad niyon. Pag-aayos ng bug sa isang bagay na napagtanto naming mali? Ilang araw na naman. Sa wakas, handa na kaming i-enable ang flag, ngunit ibinalik ng isang team ang service nito—dahil sa ibang dahilan—sa dati at may bug na client, na nagdulot ng mismong outage na pinagsikapan naming iwasan.
Nangailangan ang mga pagbabago sa client library ng kumplikadong koordinasyon sa dose-dosenang service—isang prosesong naging mas marupok, hindi mahusay, at madaling pumalya sa operasyon. Upang bawasan ang lawak ng operasyong ito para sa mga susunod na deployment, nagpasya kaming gawing hiwalay na service ang Habitat.
Sa paghihiwalay ng storage logic bilang standalone service, nakapagtatag kami ng iisang sentro ng kontrol para sa mga deployment, observability, at pagpapahusay ng platform. Sa halip na pamahalaan ang magkakahiwalay na update, maipapatupad namin ang mga pagpapahusay sa sentro at agad na mapakikinabangan ng bawat produkto ng OpenAI.
Nagbibigay din sa amin ang sentralisadong service ng iisang chokepoint para sa pinakamatibay na batayang proteksiyon sa seguridad at privacy ng data. Sa Habitat service namin sentralisadong maipapatupad ang mga patakaran sa access control, audit logging, at paglilimita ng access sa mga storage resource gaya ng Azure Cosmos DB. Mahalaga ang papel ng Habitat sa pagprotekta sa data ng user at pagpigil sa di-awtorisadong access mula sa mga external, internal, at agent na actor.
Alam naming kailangan namin ng service, pero ayaw muna naming lumipat mula sa Python, kahit may dagdag itong overhead bilang service. Ang paggamit ng Python para sa service na may mataas na throughput ay nagpataas sa network latency at malaki ang idinagdag na gastos sa pag-scale ng CPU at memory kumpara sa lokal na pagpapatakbo ng library. Batid din naming hindi katanggap-tanggap ang mga inefficiency ng Python sa 100x na scale, kaya halos tiyak na kakailanganin itong muling isulat kalaunan.
Gayunman, itinuring namin itong estratehikong pagpasok sa technical debt. Noon, ang pangunahing layunin namin ay hindi pag-optimize ng gastos o resource, kundi ang alisin ang mga hadlang sa mga product developer at patatagin ang platform. Sa pansamantalang pagtanggap sa mga kompromiso sa performance ng isang Python service, nauna naming natugunan ang mas agarang hamon, naitatag ang mga pangunahing API, at nakabuo ng matatag na infrastructure.
Kalkulado rin ang aming pagtaya na mapapadali ng mabilis na pagsulong ng sarili naming mga coding model ang teknikal na landas sa hinaharap. Tumaya kaming kapag kailangan na ang ganap na paglipat mula sa Python, gagawin itong posible ng Codex at GPT. Sa huli, napatunayang tama ang pustang iyon.
Hindi pinakamainam sa performance ang pagpapatakbo sa Habitat bilang Python service, ngunit kailangan itong piliin. Napapabilis ng Python ang trabaho namin, pero hindi ibig sabihin nito na puwede na kaming magpakasiguro at tumanggap ng lubhang mas mataas na latency. Kapag daan-daang database call ang dulot ng karaniwang request ng user, ang pinakamabagal na database call ang nararamdaman ng user. Nalaman naming ang pangunahing hamon sa pagpapatakbo ng Python service sa ganitong scale ay ang pamamahala sa mga tail latency na ito.
Tinutulungan ng asyncio ang Python na sabay-sabay na magpatakbo ng mga I/O-bound workload, ngunit hindi nito nalalampasan ang Python GIL o naibibigay ang CPU parallelism. Bukod sa I/O-heavy request proxying, maraming CPU-heavy na responsibilidad at background task ang pinangangasiwaan ng Habitat: routing, compression, encryption, checksumming, downstream health checking, request shadowing, at hedging.
Dahil napakaraming CPU-heavy workload at background task sa service namin, madaling mangibabaw sa tail request latency ang pagkaantala sa pag-schedule ng asyncio. Bago kami nag-tune para sa unang paglunsad, nakita namin sa mga trace ng request na may p99 o mas mataas na latency na kahit mabilis tumugon ang downstream storage, madalas maantala ang mga request habang hinihintay na muling i-schedule ang kaukulang coroutine para i-parse ang response.
Figure 03 · Pagsubaybay sa pagkaantala ng asyncio
Hindi CPU parallelism ang concurrency
Pinapayagan ng Python asyncio ang sabay-sabay na pagproseso ng request, ngunit iisang request lang ang tumatakbo sa CPU thread sa bawat sandali. Malaki ang epekto nito sa latency ng request kapag maraming CPU work na kailangang gawin.
Mababang CPU work
Maiikling hakbang ng Python; nagsasabay ang paghihintay sa I/OMataas na CPU work
Pinaghihintay ng mahahabang hakbang ng Python ang mga handa nang responsePara sa mga Python service sa OpenAI, bukod sa karaniwang utilization at saturation metric ng memory, CPU, network, at disk usage, napakahalagang subaybayan kung gaano kaabala ang asyncio loop at mag-tune nang naaayon.
Sa pana-panahong pag-schedule ng mga background task at pagtatala ng agwat ng inaasahan at aktuwal na oras ng pagpapatakbo, nasusukat namin nang empirikal at real time ang pagkaantala sa pag-schedule ng event loop. Sa mataas na utilization at maraming magastos na task, kahit katamtamang dami ng sabay-sabay na request bawat process ay sapat para magdulot ng malaking scheduling jitter—hanggang daan-daang millisecond at, sa ilang pambihirang sitwasyon, ilang segundo.
Kaya nililimitahan namin sa kaunting sabay-sabay na request ang bawat process at sa halip ay lubhang dinaragdagan ang bilang ng mga Python worker process.
Sa unang paglunsad ng service, natukoy namin sa live CPU profiling ang isang ugat ng mataas na asyncio delay—at ng mataas na tail latency: ang pana-panahong pag-parse ng JSON ng aming mga configuration ng feature flag sa Statsig, isang tool para pamahalaan ang feature flag, magpatakbo ng A/B test, at iba pa.
Bilang default, naka-configure ang Statsig na kumuha ng na-refresh na config bawat minuto nang walang jitter, at kasama sa config ang lahat ng production rule sa lahat ng service. Sa ibang bahagi, nagpasya sa arkitektura na magpatakbo ng hanggang 8 Python process bawat pod para mapataas ang CPU usage at mapababa ang latency. Dahil dito, bawat minuto ay may sandaling tumitigil ang lahat ng worker ng bawat pod sa pagproseso ng mga kasalukuyang request at sa halip ay ginagamit ang CPU cycle sa pag-parse ng napakalaking configuration file.
Naging simple ang solusyon nang matukoy sa CPU profiling ang ugat ng problema: mag-deploy ng mas maliit at nakatuong config, pahabain ang refresh interval, at magdagdag ng jitter sa ganitong mga background task.
Upang mapanatiling mababa ang asyncio delay, napakahalaga ring mahusay na balansehin ang load ng mga request sa mga server process; kung hindi ito iti-tune, maaaring salungatin din ito ng connection pooling.
Sa client-side connection pooling, maaaring ilang server connection lang ang itatag ng isang client process na gumagawa ng maraming sabay-sabay na request, kaya sa iilang process lang nito maipapadala ang buong load. Bago namin inayos ang load balancing, malaki ang pagkakaiba-iba ng utilization sa service namin, kung saan ang ilang tail process ay naghahatid ng 5–10x na mas maraming sabay-sabay na request kaysa karaniwan.
Natuklasan namin ito sa isang di-inaasahang insidente kung saan, kahit itinigil na ang client na nag-o-overload sa bahagi ng service, nanatiling mahina ang isang pangkat ng mga process matagal matapos ang pabugso-bugsong traffic. Sa katunayan, napansin naming patuloy na lumala ang mga process na iyon at tumanggap ng parami nang paraming request hanggang sa i-restart namin ang mga ito. Kapag na-overload ang isang pod, may kilos na nagdidirekta ng mas maraming traffic sa overloaded na pod. Isa itong uri ng failure na pamilyar na sa ilan naming kasamahan mula sa dati nilang trabaho: metastable failure(magbubukas sa bagong window).
Hinala naming connection pool ang may sala at sinubukan ito sa paglilimita sa maximum na tagal ng connection reuse; nalimitahan nga nito ang paglala at nakumpirma ang direksiyon ng aming pagsisiyasat. Sa karagdagang pagsisiyasat, nalaman naming LIFO connection reuse ang default ng aiohttp TCPConnector ng Python: pinipili para sa susunod na request ang pinakahuling ibinalik na koneksyon. Karaniwan, makatwiran ang default na ito: sa muling paggamit ng mga bagong koneksyon, maaaring mag-idle timeout ang mga dagdag na koneksyong ginawa para sa pabugso-bugsong traffic, kaya nababawasan ang overhead sa pagpapanatili sa mga ito. Sa sitwasyong ito, nagdulot ito sa amin ng metastable failure. Sa bugso ng mga request, mas huling nagbalik ng koneksyon sa pool ang mga request sa mababagal at overloaded na server, kaya mas madalas silang napili ng mga sumunod na request at unti-unting mas nagkonsentra ang traffic sa mga pod na nahihirapan na. Pinutol ng pag-patch sa connection pool upang gumamit ng FIFO reuse ang feedback loop na ito at nabawasan din ang pagkakaiba-iba ng request sa steady state.
Figure 04A · Client-side connection pooling
Ibinabalik ng LIFO ang bagong trabaho sa mabagal na process
Pagkatapos ng bugso ng mga request, huling ibinabalik ng mas mababagal na server ang mga koneksyon sa pool. Hinihikayat ng LIFO na mas mapunta ang trabaho sa parehong mas mababagal na server.
Umaabot ang unang bugso sa A, B, at sa mas mabagal na process C.
Figure 04B · Client-side connection pooling
Pinuputol ng FIFO ang feedback loop ng muling paggamit ng koneksyon
Nagpapanatili ang FIFO ng mas maraming aktibong koneksyon pagkatapos ng bugso, ngunit patas na binabalanse ang workload sa lahat ng server.
Umaabot ang unang bugso sa A, B, at sa mas mabagal na process C.
Ngayon, pangunahing umaasa kami sa Istio at Envoy para magbigay ng connection pooling at mas mahusay na mga strategy sa pagbabalanse na batid ang load ng server sa buong infrastructure ng OpenAI, at lubusang maiwasan ang problemang ito.
Isang side effect ng pag-tune para sa mababang asyncio delay at pagkakaroon ng napakaraming Python process ay napakadaling lunurin ang mga downstream dependency sa napakaraming koneksyon—na tinatawag na “thundering herd.”
Maaaring magdulot ang karaniwang araw-araw na deployment—kung hindi iti-tune upang bumagal—ng malaking CPU churn mula sa paulit-ulit na pagpapalit ng koneksyon. O maaaring pabagsakin ng connection leak ang network dahil sa pagkapuno ng NAT gateway. Hindi rin bihira ang mga problemang ito sa ibang service, ngunit malaki ang ibinababa ng sampung beses na mas maraming process sa threshold para ma-trigger ang mga ito. Madalas nitong pinupuno ang mga network resource na hindi inaasahan ng mga client na kakailanganin nilang pangasiwaan sa steady state batay lamang sa throughput.
Umaasa rin kami sa Envoy upang i-maximize ang aming connection fan-in. Ginagamit namin ito upang i-upgrade sa HTTP/2 ang mga HTTP/1 connection ng Python at mapakinabangan ang multiplexing, saka i-pool ang mga koneksyong iyon at pahabain ang buhay ng mga ito. Binibigyan din kami ng Envoy ng sentral na lugar upang magpatupad ng mga rate limit at circuit breaker na hindi gaanong magiging epektibo sa bawat standalone na Python process.
Figure 05 · Connection fan-in
Parehong mga request, mas kaunting koneksyon
Tumutulong ang connection pooling at HTTP/2 connection multiplexing na bawasan ang connection load sa mga downstream.
Isang dahilan kung bakit na-scale namin nang ganito kalawak ang Python ay ang limitadong API ng Habitat, na nagpapanatiling mahuhulaan ang gastos ng request. Sa halip na payagan ang mga client na bumuo ng anumang SQL query na maaaring magdulot ng malaking table scan o join sa maraming table, nagbibigay ang Habitat ng simpleng NoSQL API. Ang kawalan ng napakahusay na API ay isang tahasang kompromiso sa disenyo ng Habitat.
Layunin naming mag-optimize para sa simple, mahuhulaan, at pare-pareho ang trabahong mga request. Sa aming karanasan, mas madaling i-scale ang mga sistemang ito at mahirap gamitin nang mali. Mapanganib sa operasyon ang mga request na hindi mahuhulaan ang fanout: pinahihirap ng mga ito ang isolation at load balancing, at nagdudulot ng biglaang pagsipa ng latency na mahirap tugunan sa pag-scale ng service at mga client nito.
Bago kami lumipat sa Habitat at Azure Cosmos DB, karamihan ng online data ng OpenAI ay naka-store sa Postgres. Noon, madaling suriin ang lahat ng pagbabago sa query at schema upang matiyak na maayos ang kilos ng mga ito at gumagana sa naka-index na data bago ilabas sa production. Habang lumalaki ang team at mga produkto, mabilis itong naging imposibleng pamahalaan at madalas na nagdulot ng outage kapag pinabagsak ng isang bagong magastos na query sa hot path ang database.
Ang problema ay kawalan ng balanse sa gastos: mura at madaling sumulat ng SQL query na magastos at mahirap patakbuhin. Sa Habitat, iniiwasan namin ito at ginagawa naming kitang-kita sa client side ang mga magastos na query. Walang unbounded query na makaka-overload sa Habitat, at kailangan ng mga complex join at graph traversal ang dagdag na pagsisikap ng mga product team, na tumutulong upang mas mahusay ang kabuuang disenyo.
Nagbibigay ang Habitat ng NoSQL API na nakabatay sa mga uri ng object at edge na tinutukoy ng client, na hango sa TAO(magbubukas sa bagong window). Paunang tinutukoy ng mga client ang mga object at edge at ang ugnayan ng mga ito, ngunit hindi ang nilalaman ng bawat uri. Kahawig ng graph ang mga nagreresultang ugnayan, ngunit hindi sinusuportahan ng Habitat ang karaniwang graph traversal query maliban sa pag-query ng mga direktang edge ng isang partikular na object.
Hinahati namin ang graph upang magkatabi ang bawat object at mga kaugnay nitong edge sa isang storage-level partition, ngunit hindi namin sinisikap sa database level na pagsamahin ang mga object at ang mga remote object na tinutukoy ng kanilang mga edge. Dahil dito, madaling hatiin ang modelo para sa horizontal scalability, ngunit hindi mahusay ang graph traversal dahil maaaring mangailangan ang bawat paglipat sa pagitan ng mga object ng pagkuha mula sa dalawang ganap na magkaibang Azure Cosmos DB account na naka-store sa magkaibang rehiyon.
Para sa mga client na mas kumplikado ang pangangailangan sa query, nagbibigay kami ng offline na secondary view ng Habitat sa pamamagitan ng Rockset. Gumagamit kami ng change data capture (CDC) upang i-stream ang mga pagbabago mula sa online storage papunta sa mga nakahiwalay na Rockset instance nang halos real time. Responsibilidad ng bawat client team na i-scale ang sarili nilang Rockset instance para sa kanilang mga kumplikadong query.
Nagdudulot ng dagdag na abala sa mga client ang pag-provision ng Rockset, ngunit sa tingin namin ay tama itong kompromiso sa ngayon: gawing default ang mga simpleng query habang nagbibigay ng alternatibo sa nangangailangan ng mga kumplikadong query. Inihihiwalay ng disenyong ito ang aming online storage sa mga analytical at search workload na maraming pagbasa.
Dahil ipinagpaliban namin nang isang taon ang muling pagsulat ng Python, nakapagtuon kami sa mas agaran at makabuluhang mga hamon habang napakabilis ng aming paglago. Dahil humihinog na ang platform, patuloy na bumibilis ang paglago, at pangalawa na ito sa pinakamalaking service ayon sa core count sa OpenAI—at pang-apat sa Envoy footprint—panahon na para lampasan ang Python. Sa pinakamataas nitong antas, tinulungan kami ng Python na maghatid ng mahigit 20 milyong request bawat segundo.
Noong Q2 2026, sa tulong ng 2 engineer, Codex, at GPT‑5.5, naisulat naming muli sa Rust ang buong service. Pinangangasiwaan na ngayon ng bagong Rust service ang 95% ng mga production request namin; ganap naming ihihinto ang Python sa mga susunod na linggo. Ipinapakita ng data namin na 6x na mas mahusay sa CPU at 15x na mas mahusay sa memory ang Rust service kaysa bersyon ng Python, na may mas mababang average at tail latency. Plano naming magbahagi pa ng mga natutuhan sa susunod na blog.
Isang bahagi lamang ng Habitat ang Python—at ngayo’y Rust—service. Sa bahagi II ng seryeng ito tungkol sa mabilis naming pag-scale sa online storage upang maghatid sa mahigit 1 bilyong user ng ChatGPT, tatalakayin namin ang storage layer at kung paano naghahatid ang Habitat ng mahigit 500 petabyte at 70 milyong request bawat segundo.
Kung gusto mong magtrabaho sa mga OLTP system sa frontier scale at interesado ka sa ganitong engineering, tingnan ang bakanteng posisyong ito sa aming team.


