Brzo skaliranje online pohrane za više od milijardu korisnika ChatGPT‑ja
Kako smo platformu za pohranu aplikacija Habitat, napisanu u Pythonu, prilagodili nezabilježenom rastu.
Autori: Jon Lee, Chaomin Yu i Ben Ries, članovi tehničkog osoblja
Svaki OpenAI-jev proizvod ovisi o brzom i pouzdanom pristupu podacima, bilo da se netko prijavljuje, provjerava postavke Codexa ili započinje novi razgovor u ChatGPT‑ju. Svaka od tih radnji može zahtijevati mnogo zasebnih dohvata podataka prije nego što proizvod odgovori. Ako su ti zahtjevi spori, proizvod djeluje sporo. Ako ti zahtjevi ne uspiju, proizvod potpuno prestaje raditi.
Habitat je platforma za online pohranu koju smo izgradili kako bi OpenAI-jevi proizvodi brzo i pouzdano pristupali potrebnim informacijama. Habitat sada obrađuje više od 70 milijuna zahtjeva u sekundi i podržava proizvode koje svaki tjedan upotrebljava više od milijardu ljudi u gotovo 40 geografskih regija. Habitat je prvi put pokrenut za podršku GPT‑ovima na događaju DevDay 2023. kao jednostavna Python biblioteka na strani klijenta povezana s jednom bazom podataka. Danas je to složen distribuirani sustav koji poslužuje više od 500 petabajta podataka.
Slika 01 · Što je Habitat?
Platforma za online pohranu
Habitat je platforma za online pohranu koju smo izgradili kako bi OpenAI-jevi proizvodi brzo i pouzdano pristupali potrebnim informacijama.
- Zahtjev
- Odgovor
- Promjene (CDC)
Izgradnja i rad infrastrukture u ovom opsegu nije jednostavan pothvat, ali nije ni osobito zahtjevan. Našu je situaciju činila jedinstvenom nezabilježena brzina skaliranja potrebna da bismo podržali golem rast broja korisnika i potražnje za proizvodima, istodobno gradeći zrelu platformu. Sistemski inženjeri često grade za deset puta veći opseg i nadaju se da će izdržati nekoliko godina dok se pripremaju za sljedeće deseterostruko povećanje. U našem slučaju posljednje tri godine rastemo više od deset puta na godišnjoj razini. Zbog toga se izgradnja i rad Habitata svode na niz taktičkih odluka i njihov pravilan redoslijed: razumijevanje svake komponente na najnižoj razini radi maksimalnog iskorištavanja postojećeg tehnološkog sklopa te istodobno prevladavanje manjka kapaciteta pohrane i računalnih resursa kako bismo dobili vrijeme za temeljna ulaganja.
- 70 mil.+
zahtjeva u sekundi
- 1 mlrd.+
ljudi tjedno
- 500 PB+
podataka
Kako je OpenAI rastao, s njim je morao rasti i Habitat: prvo je morao postati dovoljno pouzdan za promet ključan za rad proizvoda, zatim dovoljno brz za korisnike diljem svijeta i naposljetku sposoban učinkovito raditi u golemom opsegu. Ovo je prva objava u dvodijelnoj seriji o skaliranju online pohrane. Objasnit ćemo kako se Habitat razvijao, zašto smo ga iz biblioteke pretvorili u uslugu i kako smo uslugu napisanu u Pythonu, neuobičajenom jeziku za servisni sloj, razvili u pouzdan platformski sloj za pohranu.
U budućoj ćemo objavi detaljno opisati kako smo osigurali pouzdanost višekorisničke arhitekture u velikom opsegu, slojevitu strategiju optimizacije performansi čitanja i kako smo proširili suradnju sa sustavom Azure Cosmos DB radi pouzdane obrade nezabilježene potražnje.
Habitat je nastao iz jednostavne zamisli: produktni inženjeri ne bi se trebali baviti upravljanjem bazama podataka. Habitat je prvi put pokrenut za podršku GPT‑ovima na događaju DevDay 2023. kao mala Python biblioteka koja je komunicirala s glavnim poslužiteljem ChatGPT‑ja. Podržavao je mali skup operacija koje su se u pozadini preslikavale na bazu podataka Azure Cosmos DB.
Zadatak biblioteke bio je produktnim timovima omogućiti jednostavnu pohranu i dohvat podataka bez potrebe za ovladavanjem pojedinostima temeljnog sustava. Habitat je obavljao nužan posao: utvrđivao vrstu podataka, odakle ih treba dohvatiti ili kamo ih poslati, je li zahtjev dopušten i drugo.
Produktni inženjeri ne moraju se baviti dohvatom sheme, usmjeravanjem, autorizacijom, šifriranjem, serijalizacijom, oblikovanjem zahtjeva ni udruživanjem veza. Nisu morali ni razmišljati odakle podaci dolaze: iz sustava Azure Cosmos DB, predmemorija ili drugih vrsta pohrane.
Slika 02 · Usluga Habitat
Pojednostavljeni tijek zahtjeva Habitata
Izdvajanjem logike pohrane u samostalnu uslugu uspostavili smo jedinstvenu upravljačku točku za implementacije, opservabilnost i unaprjeđenja platforme.
- Zahtjev
- Odgovor
Ta je Python biblioteka dobro radila i produktni inženjeri u OpenAI-ju brzo su prihvatili Habitat, iako nije bilo usklađene središnje inicijative za napuštanje samostalne upotrebe Postgresa i sustava Azure Cosmos DB.
Kako su se potrebe proizvoda razvijale, programeri su zajedničkoj biblioteci mogli lako dodavati podršku za značajke poput predmemoriranja na strani klijenta, sažimanja ili šifriranja.
Do sredine 2025. Habitat je dosegnuo granice implementacije na strani klijenta. Kako je sloj Habitata postajao složeniji, a broj OpenAI-jevih usluga rastao, promjene protokola kompatibilne sa starijim verzijama postale su neizvedive.
U jednom smo slučaju najvažnije skupove podataka željeli migrirati na regionalno raspoređene račune sustava Azure Cosmos DB kako bismo smanjili posljedice prekida rada u pojedinoj regiji. Ta je promjena zahtijevala dodavanje nove logike usmjeravanja u klijent, isprva isključene pomoću zastavice značajke, uvođenje promjene svim klijentima i zatim uključivanje zastavice.
Usklađivanje implementacija u desecima usluga i suradnja sa svakim timom na uvođenju trajali su danima. Prije uključivanja shvatili smo da želimo uvesti zrcaljenje zahtjeva kako bismo provjerili ispravnost logike particioniranja. Za to je trebalo još nekoliko dana uvođenja. Ispravak pogreške koju smo uočili? Još nekoliko dana. Konačno smo bili spremni uključiti zastavicu, no jedan je tim iz nepovezanih razloga vratio svoju uslugu na prethodnu verziju klijenta s pogreškom, što je uzrokovalo upravo prekid koji smo toliko nastojali izbjeći.
Promjene klijentske biblioteke zahtijevale su složeno usklađivanje desetaka usluga, a taj se postupak pokazao sve krhkijim, neučinkovitijim i podložnijim operativnim kvarovima. Kako bismo ubuduće smanjili operativno grananje implementacija, odlučili smo izdvojiti Habitat u zasebnu uslugu.
U jednom smo slučaju najvažnije skupove podataka željeli migrirati na regionalno raspoređene račune sustava Azure Cosmos DB kako bismo smanjili posljedice prekida rada u pojedinoj regiji. Ta je promjena zahtijevala dodavanje nove logike usmjeravanja u klijent, isprva isključene pomoću zastavice značajke, uvođenje promjene svim klijentima i zatim uključivanje zastavice.
Centralizirana usluga pruža nam i jedinstvenu kontrolnu točku za najsnažnije temeljne mehanizme sigurnosti i privatnosti podataka. U usluzi Habitat možemo centralno provoditi pravila kontrole pristupa, voditi zapise revizije i ograničavati pristup temeljnim resursima pohrane kao što je Azure Cosmos DB. Habitat ima ključnu ulogu u zaštiti korisničkih podataka i sprječavanju neovlaštenog pristupa vanjskih i unutarnjih aktera te agenata.
Znali smo da nam treba usluga, ali još nismo željeli napustiti Python, unatoč dodatnom opterećenju koje Python donosi kada se upotrebljava za uslugu. Upotreba Pythona za uslugu visoke propusnosti povećala je mrežnu latenciju te znatno povećala troškove procesorskih i memorijskih resursa pri skaliranju u usporedbi s lokalnim izvršavanjem biblioteke. Osim toga, znali smo da neučinkovitost Pythona neće biti prihvatljiva pri 100 puta većem opsegu, pa je buduće prepisivanje bilo gotovo neizbježno.
Ipak, smatrali smo to strateškim prihvaćanjem tehničkog duga. Naš glavni cilj tada nije bio optimizirati troškove ili resurse, nego omogućiti razvoj proizvoda i postići stabilnost platforme. Kratkoročnim prihvaćanjem kompromisa u performansama Python usluge mogli smo dati prednost hitnijim izazovima, uspostaviti temeljne API-je i izgraditi robusnu infrastrukturu.
Također smo se promišljeno kladili da će brz napredak naših modela za programiranje ubuduće pojednostavniti tehnički put. Računali smo na to da će Codex i GPT omogućiti potpunu migraciju s Pythona kada ona postane nužna. Ta se oklada naposljetku isplatila.
Pokretanje Habitata kao Python usluge bilo bi neoptimalno u pogledu performansi, ali nužno. Python nam omogućuje brz rad, ali to ne znači da smo mogli zanemariti oprez i prihvatiti osjetno veće latencije. Kada prosječan korisnički zahtjev uzrokuje stotine poziva bazi podataka, korisnik osjeti upravo najsporiji poziv. Utvrdili smo da je upravljanje latencijama na repu distribucije glavni izazov rada Python usluge u ovom opsegu.
Asyncio Pythonu omogućuje istodobno izvršavanje poslova ograničenih ulazom i izlazom, ali ne zaobilazi Pythonov GIL niti omogućuje paralelno procesorsko izvršavanje. Uz prosljeđivanje zahtjeva s mnogo ulazno-izlaznih operacija, Habitat obavlja brojne procesorski zahtjevne poslove i pozadinske zadatke: usmjeravanje, sažimanje, šifriranje, izračun kontrolnih zbrojeva, provjeru stanja nizvodnih sustava, zrcaljenje zahtjeva i zaštitno slanje dodatnih zahtjeva.
Uz toliko procesorski zahtjevnih poslova i pozadinskih zadataka, kašnjenje raspoređivanja asyncioa lako može postati glavni uzrok latencije zahtjeva na repu distribucije. Prije optimizacije za prvo pokretanje usluge, u tragovima zahtjeva s latencijom p99 i višom vidjeli smo da su zahtjevi često zastajali čekajući ponovno raspoređivanje odgovorne korutine radi obrade odgovora, iako je nizvodna pohrana brzo odgovarala.
Slika 03 · Praćenje kašnjenja asyncioa
Istodobnost nije procesorski paralelizam
Pythonov asyncio omogućuje istodobnu obradu zahtjeva, ali se na procesorskoj niti u određenom trenutku izvršava samo jedan zahtjev. To znatno utječe na latencije zahtjeva kada treba obaviti mnogo procesorskog rada.
Malo procesorskog rada
Kratki Python koraci; čekanja na U/I preklapaju seMnogo procesorskog rada
Dugi Python koraci zadržavaju spremne odgovoreZa Python usluge u OpenAI-ju ključno je, uz standardne metrike iskorištenosti i zasićenja memorije, procesora, mreže i diska, pratiti koliko je petlja asyncio opterećena te je u skladu s tim optimizirati.
Periodičnim raspoređivanjem pozadinskih zadataka i bilježenjem razlike između očekivanog i stvarnog vremena izvršavanja možemo empirijski i u stvarnom vremenu mjeriti kašnjenje raspoređivanja petlje događaja. Pri visokoj iskorištenosti i velikom broju zahtjevnih zadataka čak je i umjeren broj istodobnih zahtjeva po procesu dovoljan za znatna odstupanja u raspoređivanju, do nekoliko stotina milisekundi, a u rubnim slučajevima i nekoliko sekundi.
Zato svaki proces poslužuje samo mali broj istodobnih zahtjeva, a umjesto toga uvelike povećavamo broj Python radnih procesa.
Pri prvom pokretanju usluge profiliranjem procesora uživo otkrili smo jedan od glavnih uzroka velikog kašnjenja asyncioa, a time i velikih latencija na repu distribucije: periodičko raščlanjivanje JSON konfiguracija zastavica značajki putem Statsiga, alata za upravljanje zastavicama značajki koji se može upotrebljavati za A/B testiranje i drugo.
Statsig je prema zadanim postavkama svake minute i bez vremenskog odstupanja provjeravao osvježene konfiguracije, koje su sadržavale sva produkcijska pravila svih usluga. Zasebnom arhitektonskom odlukom određeno je pokretanje do osam Python procesa po podu radi veće iskorištenosti procesora i nižih latencija. Zajedno je to značilo da bi svake minute u svakom podu došlo do trenutka kada bi svi njegovi radni procesi zastali s obradom aktivnih zahtjeva i umjesto toga procesorske cikluse trošili na raščlanjivanje goleme konfiguracijske datoteke.
Kada nam je profiliranje procesora pomoglo utvrditi glavni uzrok, rješenje je bilo jednostavno: uvesti manju, ciljanu konfiguraciju, produljiti interval osvježavanja i dodati vremensko odstupanje ovakvim pozadinskim zadacima.
Za održavanje malog kašnjenja asyncioa ključno je i dobro uravnotežiti zahtjeve među poslužiteljskim procesima; bez optimizacije udruživanje veza može djelovati upravo suprotno.
Uz udruživanje veza na strani klijenta jedan klijentski proces koji šalje mnogo istodobnih zahtjeva može uspostaviti tek nekoliko veza s poslužiteljem i zato cijelo opterećenje usmjeriti na samo nekoliko procesa. Prije prilagodbe uravnoteženja opterećenja iskorištenost naše usluge znatno je varirala, a neki su rubni procesi posluživali pet do deset puta više istodobnih zahtjeva od prosjeka.
To smo slučajno otkrili tijekom incidenta kada je dio procesa ostao degradiran dugo nakon naleta prometa, iako smo zaustavili klijent koji je preopterećivao dio usluge. Primijetili smo da se stanje tih procesa nekontrolirano pogoršavalo te su primali sve više zahtjeva dok ih nismo ponovno pokrenuli. Kada bi se pod preopteretio, određeno bi ponašanje usmjeravalo još više prometa na njega. Bila je to vrsta kvara koju su neki naši suradnici dobro poznavali iz prethodnog rada: metastabilni kvar(otvara se u novom prozoru).
Posumnjali smo na skup veza i tu smo sumnju provjerili ograničavanjem maksimalnog trajanja ponovne upotrebe veze, čime smo doista ograničili pogoršanje i potvrdili smjer istrage. Daljnja je istraga pokazala da Pythonov aiohttp TCPConnector prema zadanim postavkama veze ponovno upotrebljava prema LIFO-u: za sljedeći se zahtjev odabire posljednja vraćena veza. To je obično razumna zadana postavka: ponovna upotreba nedavno vraćenih veza omogućuje da dodatne veze stvorene zbog naleta prometa isteknu nakon mirovanja, čime se smanjuje trošak održavanja dodatnih veza. U našem je slučaju to izazvalo metastabilni kvar. Tijekom naleta zahtjeva sporiji, preopterećeni poslužitelji kasnije su vraćali veze u skup, pa su se te veze češće odabirale za naknadne zahtjeve, postupno usmjeravajući još više prometa na podove koji su već imali poteškoća. Izmjena skupa veza radi ponovne upotrebe prema FIFO-u prekinula je tu povratnu petlju i smanjila varijacije u broju zahtjeva između procesa u stabilnom stanju.
Slika 04A · Udruživanje veza na strani klijenta
LIFO vraća nove zadatke sporom procesu
Nakon naleta zahtjeva sporiji poslužitelji posljednji vraćaju veze u skup. LIFO potiče koncentriranje većeg opterećenja na tim istim sporijim poslužiteljima.
Početni nalet stiže do A, B i sporijeg procesa C.
Slika 04B · Udruživanje veza na strani klijenta
FIFO prekida povratnu petlju ponovne upotrebe veza
FIFO nakon naleta zadržava više aktivnih veza, ali ravnomjerno raspoređuje opterećenje na sve poslužitelje.
Početni nalet stiže do A, B i sporijeg procesa C.
Danas se uglavnom oslanjamo na Istio i Envoy za udruživanje veza i bolje strategije uravnoteženja opterećenja prilagođene opterećenju poslužitelja u cijeloj OpenAI-jevoj infrastrukturi, čime potpuno izbjegavamo taj problem.
Jedna je posljedica optimizacije za malo kašnjenje asyncioa i velikog broja Python procesa to što golem broj veza može vrlo lako preopteretiti nizvodne sustave o kojima ovisimo, što je poznato kao „stampedo zahtjeva”.
Uobičajena dnevna implementacija, ako nije podešena da se odvija polako, može uzrokovati znatno procesorsko opterećenje zbog neprestanog obnavljanja veza. Curenje veza može pak srušiti mrežu zasićenjem NAT pristupnika. Ti problemi nisu rijetki ni u drugim uslugama, ali red veličine više procesa znatno snižava prag njihova nastanka te često zasićuje mrežne resurse za koje klijenti, ako gledaju samo propusnost, ne očekuju da će ih morati osigurati u stabilnom stanju.
Na Envoy se oslanjamo i kako bismo maksimalno objedinili veze. Njime Pythonove HTTP/1 veze nadograđujemo na HTTP/2 radi multipleksiranja, a zatim ih udružujemo i produljujemo im vijek trajanja. Envoy nam pruža i središnje mjesto za implementaciju ograničenja stope zahtjeva i circuit breaker mehanizama, koji bi bili manje učinkoviti u svakom samostalnom Python procesu.
Slika 05 · Objedinjavanje veza
Isti zahtjevi, manje veza
Udruživanje veza i multipleksiranje HTTP/2 veza smanjuju opterećenje vezama u nizvodnim sustavima.
Jedan od razloga zbog kojih smo Python mogli toliko skalirati bio je ograničeni API Habitata, koji trošak zahtjeva čini predvidljivim. Umjesto da klijentima omogući sastavljanje proizvoljnih SQL upita koji mogu pokrenuti opsežno pretraživanje tablica ili spajanje mnogih tablica, Habitat nudi jednostavan NoSQL API. Odsutnost moćnog API-ja svjestan je kompromis u dizajnu Habitata.
Cilj nam je optimizirati jednostavne, predvidljive zahtjeve sa stalnom količinom rada. Prema našem iskustvu, takve je sustave mnogo lakše skalirati, a teško ih je pogrešno implementirati ili zloupotrijebiti. Zahtjevi s nepredvidljivim grananjem operativno su opasni: otežavaju izolaciju i uravnoteženje opterećenja te stvaraju nagle skokove latencije zbog kojih je teško skalirati i uslugu i njezine klijente.
Prije prelaska na Habitat i Azure Cosmos DB većina OpenAI-jevih online podataka bila je pohranjena u Postgresu. Tada je bilo lako pregledati sve promjene upita i sheme te prije uvođenja u produkciju provjeriti jesu li primjerene i rade li nad indeksiranim podacima. Kako su tim i proizvodi rasli, to je brzo postalo neodrživo i često uzrokovalo prekide rada jer bi jedan novi, skupi upit na često korištenoj putanji srušio bazu podataka.
Problem je neravnoteža troškova: lako je i jeftino napisati SQL upite čije je izvršavanje skupo i teško. U Habitatu to izbjegavamo i klijentima vrlo jasno pokazujemo koji su upiti skupi. Nema neograničenih upita koji mogu preopteretiti Habitat, a složena spajanja i obilasci grafa zahtijevaju da produktni timovi sami odrade dio zahtjevnog posla, što općenito potiče učinkovitiji dizajn.
Habitat nudi NoSQL API oblikovan oko vrsta objekata i bridova koje definiraju klijenti, nadahnut sustavom TAO(otvara se u novom prozoru). Klijenti unaprijed definiraju objekte i bridove te njihove međusobne odnose, ali ne i sadržaj svake vrste. Nastali odnosi nalikuju grafu, ali sam Habitat ne podržava uobičajene upite za obilazak grafa osim upita o izravnim bridovima određenog objekta.
Graf particioniramo tako da se svaki objekt i njegovi bridovi nalaze u istoj particiji na razini pohrane, ali na razini baze podataka ne pokušavamo sustavno smjestiti zajedno objekte i udaljene objekte prema kojima vode njihovi bridovi. Zato se model lako particionira radi vodoravnog skaliranja, ali obilasci grafa nisu učinkoviti jer svaki prijelaz između objekata može zahtijevati dohvaćanje iz dvaju potpuno različitih računa sustava Azure Cosmos DB u različitim regijama.
Klijentima sa složenijim potrebama za upitima nudimo offline sekundarni prikaz Habitata putem Rockseta. Snimanjem promjena podataka (CDC) gotovo u stvarnom vremenu prenosimo promjene iz online pohrane u izolirane instance Rockseta. Svaki klijentski tim odgovoran je za skaliranje vlastite instance Rockseta prema svojim potrebama za složenim upitima.
Priprema Rockseta stvara dodatne poteškoće klijentima, ali smatramo da je to trenutačno pravi kompromis: jednostavni upiti zadani su izbor, a onima kojima trebaju složeni upiti pružamo alternativu. Takav dizajn izolira našu online pohranu od analitičkih i pretraživačkih opterećenja s mnogo čitanja.
Odgoda prepisivanja usluge iz Pythona za godinu dana omogućila nam je da se tijekom iznimno brzog rasta usredotočimo na hitnije i važnije izazove. Kako je platforma sazrijevala, a rast se nastavljao ubrzavati, napokon je došlo vrijeme da se odmaknemo od Pythona. Habitat je po broju jezgri bio druga najveća usluga u OpenAI-ju, a po upotrebi Envoya četvrta. Na vrhuncu nam je Python omogućio posluživanje više od 20 milijuna zahtjeva u sekundi.
U drugom tromjesečju 2026., uz samo dva inženjera, Codex i GPT‑5.5, uspjeli smo cijelu uslugu prepisati u Rustu. Nova usluga u Rustu sada obrađuje 95 % naših produkcijskih zahtjeva, a Python ćemo potpuno ukinuti u sljedećim tjednima. Naši podaci pokazuju da je usluga u Rustu šest puta učinkovitija u upotrebi procesora i 15 puta učinkovitija u upotrebi memorije od verzije u Pythonu, uz znatno niže prosječne latencije i latencije na repu distribucije. Više ćemo saznanja podijeliti u budućoj objavi na blogu.
Usluga u Pythonu, a sad u Rustu, samo je jedan dio Habitata. U drugom dijelu serije o brzom skaliranju online pohrane za više od milijardu korisnika ChatGPT‑ja govorit ćemo o sloju pohrane i tome kako Habitat poslužuje više od 500 petabajta podataka te obrađuje više od 70 milijuna zahtjeva u sekundi.
Ako želite raditi na OLTP sustavima u najzahtjevnijem opsegu i zanima vas ovakvo inženjerstvo, pogledajte ovo otvoreno radno mjesto u našem timu.


