Brzo skaliranje mrežne pohrane za više od milijardu korisnika ChatGPT‑a
Kako smo Python platformu Habitat prilagodili dosad nezabilježenom rastu.
Autori: Jon Lee, Chaomin Yu i Ben Ries, članovi tehničkog osoblja
Svaki OpenAI proizvod zavisi od brzog i pouzdanog pristupa podacima, bilo da se neko prijavljuje, provjerava postavke Codexa ili započinje novi razgovor u ChatGPT‑u. Svaka od tih radnji može zahtijevati mnogo zasebnih pretraživanja 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 mrežnu pohranu koju smo izgradili kako bi OpenAI proizvodi mogli brzo i pouzdano pristupati potrebnim informacijama. Habitat sada obrađuje više od 70 miliona zahtjeva svake sekunde i podržava proizvode koje svake sedmice koristi 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 sistem koji poslužuje više od 500 petabajta podataka.
Slika 01 · Šta je Habitat?
Platforma za mrežnu pohranu
Habitat je platforma za mrežnu pohranu koju smo izgradili kako bi OpenAI proizvodi brzo i pouzdano pristupali potrebnim informacijama.
- Zahtjev
- Odgovor
- Promjene (CDC)
Izgradnja i rad infrastrukture u ovom obimu nisu nimalo laki, ali ni posebno zahtjevni. Našu je situaciju činila jedinstvenom dosad nezabilježena brzina kojom smo morali skalirati radi ogromnog rasta broja korisnika i potražnje za proizvodima, istovremeno gradeći zrelu platformu. Sistemski inženjeri često grade za deset puta veći obim i nadaju se da će potrajati nekoliko godina dok se pripremaju za naredno deseterostruko povećanje. U našem slučaju, tokom posljednje tri godine rasli smo više od deset puta iz godine u godinu. Zato se izgradnja i rad Habitata svode na niz taktičkih odluka i pažljivo određivanje redoslijeda: razumijevanje svake komponente do najnižeg nivoa radi maksimalnog iskorištavanja postojećeg tehnološkog sistema, uz prevladavanje ograničenja kapaciteta pohrane i računarstva kako bismo dobili vrijeme za temeljna ulaganja.
- 70 mil.+
zahtjeva u sekundi
- 1 mlrd.+
ljudi sedmično
- 500 PB+
podataka
Kako je OpenAI rastao, Habitat je morao rasti s njim: prvo postati dovoljno pouzdan za ključni produkcijski saobraćaj, zatim dovoljno brz za korisnike širom svijeta i naposljetku sposoban vješto raditi u ogromnom obimu. Ova objava prva je u dvodijelnoj seriji o tome kako smo skalirali mrežnu pohranu. U ovoj objavi pokazat ćemo kako se Habitat razvijao, zašto smo ga iz biblioteke pretvorili u uslugu i kako smo uslugu napisanu u jeziku neuobičajenom za ovaj tehnološki sistem, Pythonu, proširili u pouzdan sloj platforme za pohranu.
U budućoj objavi detaljno ćemo opisati kako smo osigurali pouzdanost višekorisničkog rada u velikom obimu, našu višeslojnu strategiju optimizacije čitanja i kako smo proširili saradnju s Azure Cosmos DB-om radi pouzdane obrade dosad nezabilježene potražnje.
Habitat je nastao iz jednostavne ideje: razvojni inženjeri proizvoda 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 serverom ChatGPT‑a. Podržavala je mali skup operacija koje su se u pozadini preslikavale na aplikaciju baze podataka Azure Cosmos DB.
Zadatak biblioteke bio je pružiti timovima proizvoda jednostavan način pohrane i dohvaćanja podataka bez potrebe za ovladavanjem detaljima sistema u pozadini. Habitat je obavljao neophodan posao: utvrđivao vrstu podataka, odakle trebaju doći ili kamo trebaju otići, je li zahtjev dopušten i drugo.
Razvojni inženjeri proizvoda ne moraju se baviti pronalaženjem šeme, usmjeravanjem, autorizacijom, šifriranjem, serijalizacijom, oblikovanjem zahtjeva ni udruživanjem veza. Nisu čak morali razmatrati ni odakle podaci dolaze: iz Azure Cosmos DB-a, predmemorija ili drugih vrsta pohrane.
Slika 02 · Usluga Habitat
Pojednostavljeni tok zahtjeva u Habitatu
Odvajanjem logike pohrane u samostalnu uslugu uspostavili smo jedinstvenu kontrolnu tačku za uvođenja, opservabilnost i poboljšanja platforme.
- Zahtjev
- Odgovor
Ova Python biblioteka dobro je radila i razvojni inženjeri proizvoda u OpenAI-ju brzo su prihvatili Habitat, iako nije bilo organiziranog centralnog nastojanja da se napuste samouslužni Postgres i Azure Cosmos DB.
Kako su se potrebe proizvoda razvijale, razvojni inženjeri mogli su čak jednostavno dodavati podršku u zajedničku biblioteku za funkcije poput klijentskog predmemoriranja, kompresije ili šifriranja.
Do sredine 2025. Habitat je kao implementacija na strani klijenta dostigao svoje granice. Kako je sloj Habitata postajao složeniji, a broj OpenAI-jevih usluga rastao, izmjene protokola kompatibilne sa starijim verzijama postale su neizvodive.
U jednom slučaju željeli smo smanjiti razmjere posljedica prekida u bilo kojoj regiji za naše najvažnije skupove podataka tako što bismo ih migrirali na regionalno distribuiran skup računa Azure Cosmos DB-a. Za ovu promjenu trebalo je klijentu dodati logiku usmjeravanja, isključenu funkcijskom zastavicom, osigurati uvođenje svim klijentima, a zatim uključiti zastavicu.
Usklađivanje uvođenja u desecima usluga i saradnja sa svakim timom trajali su danima. Prije uključivanja shvatili smo da želimo uvesti preslikavanje zahtjeva kako bismo provjerili ispravnost logike particioniranja. Za to je trebalo još nekoliko dana. Ispravka greške za nešto za šta smo shvatili da nije tačno? Još nekoliko dana. Napokon smo bili spremni uključiti zastavicu, ali je jedan tim iz nepovezanih razloga vratio svoju uslugu na raniju verziju s neispravnim klijentom, izazvavši upravo prekid koji smo se toliko trudili izbjeći.
Izmjene klijentske biblioteke zahtijevale su složeno usklađivanje desetaka usluga, a taj je postupak postajao sve krhkiji, neefikasniji i podložniji operativnim kvarovima. Da bismo smanjili operativno širenje budućih uvođenja, odlučili smo Habitat izdvojiti u zasebnu uslugu.
Odvajanjem logike pohrane u samostalnu uslugu uspostavili smo jedinstvenu kontrolnu tačku za uvođenja, opservabilnost i poboljšanja platforme. Umjesto upravljanja rascjepkanim ažuriranjima, poboljšanja smo mogli uvoditi centralno i odmah donijeti korist svakom OpenAI proizvodu.
Centralizirana usluga pruža nam i jednu kontrolnu tačku za najsnažnije osnovne mehanizme sigurnosti i privatnosti podataka. U usluzi Habitat možemo centralno provoditi pravila kontrole pristupa, voditi dnevnike revizije i ograničiti pristup temeljnim resursima pohrane poput Azure Cosmos DB-a. Habitat ima presudnu ulogu u zaštiti korisničkih podataka i sprečavanju neovlaštenog pristupa vanjskih, internih i agentskih aktera.
Znali smo da nam treba usluga, ali još nismo željeli napustiti Python, uprkos dodatnim troškovima koje donosi kao usluga. Korištenje Pythona za uslugu visokog protoka povećalo je mrežnu latenciju te znatno povećalo troškove skaliranja CPU-a i memorije u odnosu na lokalno izvršavanje biblioteke. Osim toga, znali smo da neefikasnost Pythona neće biti prihvatljiva pri 100 puta većem obimu, pa je eventualno ponovno pisanje bilo gotovo izvjesno.
Međutim, na to smo gledali kao na strateško preuzimanje tehničkog duga. Naš glavni cilj tada nije bio optimizirati troškove ili resurse, nego ukloniti prepreke razvojnim inženjerima proizvoda i postići stabilnost platforme. Kratkoročnim prihvatanjem kompromisa u performansama Python usluge mogli smo dati prednost hitnijim izazovima, uspostaviti osnovne API-je i izgraditi robusnu infrastrukturu.
Također smo se proračunato kladili da će brz napredak naših modela za programiranje kasnije pojednostaviti tehnički put. Kladili smo se da će Codex i GPT omogućiti migraciju kada potpuno napuštanje Pythona postane neophodno. Ta se opklada na kraju pokazala ispravnom.
Pokretanje Habitata kao Python usluge bilo bi neoptimalno u pogledu performansi, ali neophodno. Python nam omogućava brz napredak, 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 onaj najsporiji. Utvrdili smo da je glavni izazov rada Python usluge u ovom obimu upravljanje krajnjim latencijama.
Asyncio omogućava Pythonu istovremeno izvršavanje radnih opterećenja ograničenih ulazom/izlazom, ali ne zaobilazi Python GIL niti omogućava paralelizam CPU-a. Pored prosljeđivanja zahtjeva s intenzivnim ulazom/izlazom, Habitat obavlja brojne CPU-intenzivne zadatke i pozadinske poslove: usmjeravanje, kompresiju, šifriranje, izračun kontrolnih suma, provjeru stanja nizvodnih sistema, preslikavanje i zaštitno dupliciranje zahtjeva.
Uz toliko CPU-intenzivnih opterećenja i pozadinskih zadataka u našoj usluzi, kašnjenje raspoređivanja u asyncio petlji lako može postati glavni uzrok krajnje latencije zahtjeva. Prije podešavanja za prvo pokretanje usluge, u tragovima zahtjeva s latencijom p99 i višom vidjeli smo da su se zahtjevi često zaustavljali, iako je nizvodna pohrana brzo odgovarala, čekajući da odgovorna korutina bude ponovo raspoređena radi obrade odgovora.
Slika 03 · Praćenje kašnjenja asyncio petlje
Istovremenost nije paralelizam CPU-a
Python asyncio omogućava istovremenu obradu zahtjeva, ali se na CPU niti u datom trenutku izvršava samo jedan zahtjev. To snažno utječe na latenciju zahtjeva kada treba obaviti mnogo CPU posla.
Malo CPU opterećenje
Kratki Python koraci; čekanja ulaza/izlaza se preklapajuVeliko CPU opterećenje
Dugi Python koraci zadržavaju spremne odgovoreZa Python usluge u OpenAI-ju smatramo da je, pored standardnih metrika iskorištenosti i zasićenja memorije, CPU-a, mreže i diska, presudno pratiti asyncio petlju i njeno opterećenje te je prilagođavati u skladu s tim.
Periodičnim raspoređivanjem pozadinskih zadataka i bilježenjem razlike između očekivanog i stvarnog vremena izvršenja možemo empirijski mjeriti kašnjenje raspoređivanja petlje događaja u stvarnom vremenu. Pri visokoj iskorištenosti i brojnim zahtjevnim zadacima, čak je i umjeren broj istovremenih zahtjeva po procesu dovoljan da izazove znatna odstupanja u raspoređivanju, do nekoliko stotina milisekundi, a u nekim rubnim slučajevima i nekoliko sekundi.
Zato svaki proces ograničavamo na mali broj istovremenih zahtjeva, a umjesto toga drastično povećavamo broj Python radnih procesa.
Pri prvom pokretanju usluge, profiliranjem CPU-a aktivne usluge otkrili smo jedan od osnovnih uzroka velikog kašnjenja asyncio petlje, a time i visokih krajnjih latencija: periodično raščlanjivanje JSON konfiguracija funkcijskih zastavica putem Statsiga, alata za upravljanje zastavicama, provođenje A/B testova i drugo.
Statsig je prema zadanim postavkama svake minute bez vremenskog odstupanja provjeravao osvježene konfiguracije, a konfiguracija je sadržavala sva produkcijska pravila svih usluga. Usto je donesena arhitektonska odluka da se po podu pokreće do osam Python procesa radi veće iskorištenosti CPU-a i nižih latencija. To je značilo da bi svakog minuta došlo do trenutka kada svi radni procesi u podu zaustave obradu aktivnih zahtjeva i CPU cikluse troše na raščlanjivanje ogromne konfiguracijske datoteke.
Nakon što je profiliranje CPU-a pomoglo pronaći osnovni uzrok, rješenje je bilo jednostavno: uvesti manju, ciljanu konfiguraciju, produžiti interval osvježavanja i dodati vremensko odstupanje ovakvim pozadinskim zadacima.
Za održavanje malog kašnjenja asyncio petlje presudno je i dobro balansirati zahtjeve između serverskih procesa; bez podešavanja udruživanje veza može djelovati upravo suprotno.
Uz udruživanje veza na strani klijenta, jedan klijentski proces koji šalje mnogo istovremenih zahtjeva može uspostaviti samo nekoliko veza sa serverom i tako cjelokupno opterećenje slati tek nekolicini procesa. Prije prilagođavanja balansiranja opterećenja iskorištenost naše usluge znatno je varirala, pa su neki krajnji procesi obrađivali 5–10 puta više istovremenih zahtjeva od prosjeka.
To smo slučajno otkrili tokom incidenta kada je dio procesa ostao u pogoršanom stanju dugo nakon navale saobraćaja, iako smo zaustavili klijenta koji je preopterećivao dio usluge. Zapravo smo primijetili nekontrolirano pogoršavanje tih procesa: primali su sve više zahtjeva dok ih nismo ponovo pokrenuli. Kada bi se pod preopteretio, određeno ponašanje usmjeravalo je još više saobraćaja na njega. Bila je to vrsta kvara koju su neki članovi našeg tima dobro poznavali iz ranijeg rada: metastabilni kvar(otvara se u novom prozoru).
Sumnjali smo na skup veza i to provjerili ograničavanjem maksimalnog trajanja ponovne upotrebe veze, što je zaista ograničilo pogoršanje i potvrdilo smjer istrage. Daljnja istraga pokazala je da Pythonov aiohttp TCPConnector prema zadanim postavkama koristi LIFO ponovnu upotrebu veza: za sljedeći zahtjev bira se najskorije vraćena veza. To je obično razumna zadana postavka: ponovna upotreba nedavnih veza omogućava da dodatne veze stvorene radi obrade navale saobraćaja isteknu tokom mirovanja, čime se smanjuju troškovi njihovog održavanja. U ovom slučaju to nam je izazvalo metastabilni kvar. Tokom navale zahtjeva sporiji, preopterećeni serveri kasnije su vraćali veze u skup, pa su ih naredni zahtjevi češće birali i postepeno usmjeravali još više saobraćaja na podove koji su već imali poteškoća. Izmjena skupa veza radi korištenja FIFO ponovne upotrebe prekinula je ovu povratnu petlju i smanjila varijacije zahtjeva u stabilnom stanju.
Slika 04A · Udruživanje veza na strani klijenta
LIFO vraća novi posao sporom procesu
Nakon navale zahtjeva sporiji serveri posljednji vraćaju veze u skup. LIFO podstiče koncentriranje dodatnog posla na tim istim sporijim serverima.
Početna navala 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 navale održava više aktivnih veza, ali ravnomjerno raspoređuje opterećenje na sve servere.
Početna navala stiže do A, B i sporijeg procesa C.
Danas se uglavnom oslanjamo na Istio i Envoy za udruživanje veza i bolje strategije balansiranja koje uzimaju u obzir opterećenje servera širom OpenAI infrastrukture, čime potpuno izbjegavamo ovaj problem.
Jedna posljedica podešavanja radi malog kašnjenja asyncio petlje i velikog broja Python procesa jeste da je nizvodne zavisnosti vrlo lako preopteretiti golemim brojem veza, što je poznato kao „stampedo zahtjeva“.
Redovno dnevno uvođenje, ako nije podešeno da bude sporo, može izazvati znatno opterećenje CPU-a zbog stalnog obnavljanja veza. Ili curenje veza može oboriti mrežu zasićenjem NAT pristupnika. Ovi problemi nisu rijetki ni u drugim uslugama, ali red veličine više procesa znatno snižava prag za njihovo pokretanje i često zasićuje mrežne resurse za koje klijenti ne očekuju da će ih morati podržavati u stabilnom stanju samo na osnovu protoka.
Na Envoy se oslanjamo i radi maksimalnog objedinjavanja veza. Koristimo ga za nadogradnju Pythonovih HTTP/1 veza na HTTP/2 kako bismo iskoristili multipleksiranje, a zatim te veze udružili i produžili im vijek trajanja. Envoy nam pruža i centralno mjesto za uvođenje ograničenja stope i prekidača strujnog kola, koji bi bili manje efikasni u svakom zasebnom Python procesu.
Slika 05 · Objedinjavanje veza
Isti zahtjevi, manje veza
Udruživanje veza i multipleksiranje HTTP/2 veza pomažu smanjiti opterećenje vezama na nizvodnim sistemima.
Python smo mogli skalirati do ove mjere i zbog ograničenog Habitatovog API-ja, koji održava trošak zahtjeva predvidljivim. Umjesto da klijentima dopusti sastavljanje proizvoljnih SQL upita koji mogu dovesti do opsežnog skeniranja ili spajanja mnogih tabela, Habitat pruža jednostavan NoSQL API. Odsustvo moćnog API-ja namjeran je kompromis u dizajnu Habitata.
Nastojimo optimizirati jednostavne, predvidljive zahtjeve sa stalnom količinom posla. Prema našem iskustvu, takve sisteme znatno je lakše skalirati, a teško ih je pogrešno primijeniti ili zloupotrijebiti. Zahtjevi s nepredvidljivim širenjem operativno su opasni: otežavaju izolaciju i balansiranje opterećenja te stvaraju nagle skokove latencije koje je teško skalirati i za uslugu i za njene klijente.
Prije prelaska na Habitat i Azure Cosmos DB, većina OpenAI-jevih mrežnih podataka bila je pohranjena u Postgresu. Tada je bilo lako pregledati sve izmjene upita i šeme kako bismo prije uvođenja u produkciju provjerili da su ispravne i da rade nad indeksiranim podacima. Kako su tim i proizvodi rasli, to je brzo postalo neizvodivo i često uzrokovalo prekide kada bi jedan novi, skupi upit na kritičnoj putanji oborio bazu podataka.
Problem je neravnoteža troškova: lako je i jeftino napisati SQL upite koje je teško i skupo izvršavati. Habitat to izbjegava i klijentu čini skupe upite krajnje očiglednim. Nema neograničenih upita koji mogu preopteretiti Habitat, dok složena spajanja i kretanje kroz graf zahtijevaju da timovi proizvoda obave dio zahtjevnog posla, što općenito podstiče efikasniji dizajn.
Habitat pruža NoSQL API zasnovan na vrstama objekata i veza koje definiraju klijenti, po uzoru na TAO(otvara se u novom prozoru). Klijenti unaprijed definiraju objekte i veze te njihove međusobne odnose, ali ne i sadržaj svake vrste. Dobijeni odnosi nalikuju grafu, ali sam Habitat ne podržava tipične upite za kretanje kroz graf, osim upita o neposrednim vezama određenog objekta.
Graf dijelimo tako da se svaki objekt i pripadajuće veze nalaze u istoj particiji pohrane, ali na nivou baze podataka ne pokušavamo planski smjestiti zajedno objekte i udaljene objekte na koje njihove veze upućuju. Tako se model lako particionira za horizontalno skaliranje, ali je kretanje kroz graf neefikasno jer svaki pojedinačni korak između objekata može zahtijevati dohvaćanje iz dva potpuno različita računa Azure Cosmos DB-a pohranjena u različitim regijama.
Klijentima sa složenijim potrebama za upitima ipak nudimo sekundarni izvanmrežni prikaz Habitata putem Rockseta. Koristimo evidentiranje promjena podataka (CDC) da bismo promjene iz mrežne pohrane gotovo u stvarnom vremenu slali u izolirane instance Rockseta. Svaki klijentski tim odgovoran je za skaliranje vlastite instance Rockseta prema svojim potrebama za složenim upitima.
Ovo osiguravanje Rockseta stvara dodatne poteškoće klijentima, ali smatramo da je trenutno pravi kompromis: jednostavni upiti su zadani, a onima kojima trebaju složeni pružamo alternativu. Ovaj dizajn izolira našu mrežnu pohranu od analitičkih i pretraživačkih opterećenja s mnogo čitanja.
Odgoda ponovnog pisanja Pythona za godinu omogućila nam je da se tokom izuzetno brzog rasta usmjerimo na hitnije i važnije izazove. Kako je platforma sazrijevala, a rast se i dalje ubrzavao, te budući da je ovo bila druga najveća usluga u OpenAI-ju prema broju jezgri, a četvrta prema upotrebi Envoya, napokon je došlo vrijeme da napustimo Python. Na vrhuncu nam je Python pomagao obraditi više od 20 miliona zahtjeva svake sekunde.
U drugom tromjesečju 2026. samo su dva inženjera, uz Codex i GPT‑5.5, uspjela cijelu uslugu ponovo napisati u Rustu. Nova Rust usluga sada obrađuje 95% naših produkcijskih zahtjeva; Python ćemo u potpunosti povući u narednim sedmicama. Naši podaci pokazuju da Rust usluga šest puta efikasnije koristi CPU i 15 puta efikasnije memoriju od Python verzije, uz znatno niže prosječne i krajnje latencije. Više saznanja planiramo podijeliti u budućem blogu.
Python usluga, a sada Rust usluga, samo je jedan aspekt Habitata. U drugom dijelu ove serije o brzom skaliranju mrežne pohrane za više od milijardu korisnika ChatGPT‑a govorit ćemo o sloju pohrane i tome kako Habitat poslužuje više od 500 petabajta i preko 70 miliona zahtjeva svake sekunde.
Ako želite raditi na OLTP sistemima graničnog obima i zanima vas ovakvo inženjerstvo, pogledajte ovo otvoreno radno mjesto u našem timu.


