Jäta vahele ja mine põhisisu juurde
OpenAI

22. jaanuar 2026

Inseneriteadus

PostgreSQLi skaleerimine 800 miljoni ChatGPT kasutaja toetamiseks

Bohan Zhang, tehnilise meeskonna liige

Laadimine…

PostgreSQL on aastaid olnud üks olulisemaid, taustal töötavaid andmesüsteeme, mis toetavad selliseid põhitooteid nagu ChatGPT ja OpenAI API. Kuna meie kasutajaskond kasvab kiiresti, on nõudmised meie andmebaasidele samuti oluliselt kasvanud. Viimase aasta jooksul on meie PostgreSQL-i koormus kasvanud enam kui 10 korda ja see kasv jätkub.

Meie jõupingutused tootmistaristu edasiarendamiseks selle kasvu toetamiseks tõid esile uue arusaama: PostgreSQL-i saab skaleerida nii, et see toetab usaldusväärselt palju suuremaid lugemisintensiivseid töökoormusi, kui paljud varem võimalikuks pidasid. Süsteem (mille algselt lõi California Ülikooli Berkeley teadlaste meeskond) on võimaldanud meil toetada tohutut ülemaailmset liiklust ühe esmase Azure PostgreSQL paindliku serveriinstantsiga(avaneb uues aknas) ja peaaegu 50 kirjutuskaitstud hoidlaga, mis on jaotatud üle mitme piirkonna kogu maailmas. See on lugu sellest, kuidas me OpenAI-s PostgreSQL-i skaleerisime, et toetada miljoneid päringuid sekundis 800 miljoni kasutaja jaoks rangete optimeerimiste ja tugeva inseneritöö abil; käsitleme ka peamisi õppetunde.

Probleemid meie esialgse kavandiga

Pärast ChatGPT turule toomist kasvas liiklus enneolematu kiirusega. Selle toetamiseks rakendasime kiiresti ulatuslikke optimeerimisi nii rakenduse kui ka PostgreSQL-i andmebaasikihtides, suurendasime mahutavust instantsi suuruse tõstmisega ja lisasime rohkem kirjutuskaitstud andmekogusid. See süsteem on meid pikka aega hästi teeninud. Pideval täiustamisel pakub see jätkuvalt piisavalt kasvuruumi tulevaseks arenguks.

Võib tunduda üllatav, et OpenAI mahunõudeid saab täita ühe esmase süsteemiga, kuid selle praktikas toimima panemine ei ole lihtne. Esinenud on mitmeid Postgresi ülekoormusest põhjustatud intsidente, mis järgivad sageli sama mustrit: varasema etapi probleem põhjustab andmebaasi koormuse järsu hüppe, näiteks vahemälu vead vahemälukihti rikke tõttu, CPU-d ülekoormav kulukas mitmepoolsete ühenduste loomine või uue funktsiooni käivitamisest tingitud päringute üleküllus. Ressursside kasutuse suurenemisel tõuseb ka päringulatentsus ja tekib probleem päringute aegumisega. Korduskatsed suurendavad koormust veelgi, käivitades nõiaringi, millel on potentsiaal halvendada kõikide ChatGPT ja API teenuste toimimist.

Koormusdiagrammi skaleerimine

Kuigi PostgreSQL skaleerub hästi meie lugemismahukate töökoormuste jaoks, puutume siiski kokku väljakutsetega suure kirjutusliikluse perioodidel. See on suuresti tingitud PostgreSQL-i multiversioonilise samaaegse juhtimise (MVCC) teostusest, mis muudab selle kirjutamismahukate töökoormuste puhul vähem tõhusaks. Näiteks, kui päring uuendab kirjet või isegi ühte välja, kopeeritakse kogu rida uue versiooni loomiseks. Suure kirjutuskoormuse puhul põhjustab see märkimisväärset ülekoormust. See suurendab ka lugemiskoormust, kuna päringud peavad uusima kirja leidmiseks läbi skaneerima mitmeid kirjete versioone (surnud kirjed). MVCC toob kaasa täiendavaid probleeme, nagu tabelite ja indeksite paisumine, suurenenud indeksihalduse koormus ning keeruline autovacuumi häälestamine. (Nende probleemide põhjaliku käsitluse leiad blogipostitusest, mille kirjutasin koos prof Andy Pavloga Carnegie Melloni Ülikoolist ja mille pealkiri on „The Part of PostgreSQL We Hate the Most“(avaneb uues aknas); sellele on viidatud(avaneb uues aknas) PostgreSQL-i Vikipeedia lehel.)

PostgreSQL-i skaleerimine miljonite päringuteni sekundis

Nende piirangute leevendamiseks ja kirjutuskoormuse vähendamiseks oleme ja jätkame lõigustatud (st horisontaalselt jagatavate) ja suure kirjutuskoormusega protsesside migreerimist lõigustatud süsteemidesse, nagu Azure Cosmos DB, optimeerides rakenduse loogikat tarbetute kirjutusprotsesside vähendamiseks. Me ei luba enam ka uute tabelite lisamist praegusesse PostgreSQL-i süsteemi. Uued töökoormused suunatakse vaikimisi lõigustatud süsteemidesse.

Kuigi meie infrastruktuur on arenenud, pole PostgreSQL lõigustatud, kusjuures kõiki kirjutusi teenindab üksainus peamine instants. Peamine põhjendus on see, et olemasolevate rakenduste töökoormuste lõigustamine oleks äärmiselt keeruline ja aeganõudev, nõudes muudatusi sadades rakenduse lõpp-punktides ning võttes potentsiaalselt kuid või isegi aastaid. Kuna meie töökoormused on peamiselt lugemismahukad ja oleme rakendanud ulatuslikke optimeerimisprotsesse, pakub praegune arhitektuur endiselt piisavalt ruumi liikluse jätkuva kasvu toetamiseks. Kuigi me ei välista tulevikus PostgreSQL-i lõigustamist, ei ole see lähiajal prioriteet, arvestades piisavat varu, mis meil on praeguse ja tulevase kasvu jaoks.

Järgmistes jaotistes süveneme probleemidesse, millega me silmitsi seisime, ja ulatuslikesse optimeerimisprotsessidesse, mida me rakendasime nende lahendamiseks ja tulevaste katkestuste vältimiseks, viies PostgreSQL-i enda võimekuse ülemise piirini ja skaleerides selle miljonite päringuteni sekundis (QPS).

Põhimudeli koormuse vähendamine

Probleem: ainult ühe kirjutajaga ei suuda põhimudel kirjutusi skaleerida. Kirjutuskoormuse suured muutused võivad põhimudeli kiiresti üle koormata ja mõjutada selliseid teenuseid nagu ChatGPT ja meie API.

Lahendus: minimeerime põhimudeli koormust nii palju kui võimalik nii lugemiste kui ka kirjutuste osas, et tagada piisav võimekus suure kirjutuskoormuse talumiseks. Lugemispäringute liiklus suunatakse võimalusell kirjutuskaitstud andmekogudesse. Kuid mõned lugemispäringud peavad jääma põhimudelisse, sest need on osa kirjutustoimingutest. Nende puhul keskendume nende tõhususele ja aeglaste päringute vältimisele. Kirjutusliikluse jaoks oleme migreerinud lõigustatavad, kirjutusmahukad töökoormused lõigustatud süsteemidesse, nagu Azure CosmosDB. Keerukamalt lõigustatavate, kuid siiski suurt kirjutusmahtu põhjustavate töökoormused migreerimine võtab kauem aega ja see protsess on endiselt pooleli. Samuti optimeerisime oma rakendusi agressiivselt kirjutuskoormuse vähendamiseks; näiteks parandasime rakenduse vead, mis põhjustasid üleliigseid kirjutusi, ja võtsime kasutusele poolautomaatsed kirjutused, kus see oli asjakohane, et liikluse kasvust põhjustatud koormust leevendada. Lisaks, kui täidame tabelivälju tagantjärele, kehtestame liigse kirjutuskoormuse vältimiseks ranged kiiruspiirangud.

Päringute optimeerimine

Probleem: tuvastasime PostgreSQL-is mitu ressursimahukat päringut. Varem tarbisid nende päringute äkilised mahuhüpped suuri CPU ressursse, aeglustades nii ChatGPT‑d kui ka API päringuid.

Lahendus: mõnede mahukate päringute, näiteks nende, mis ühendavad mitmeid tabeleid, kvaliteet võib oluliselt halvendada või kogu teenus võib katkeda. Peame PostgreSQL-i päringuid pidevalt optimeerima, et tagada nende tõhusus ja vältida levinud sidusa tehingutöötluse (OLTP) antimustreid. Näiteks tuvastasime kunagi äärmiselt mahuka päringu, mis ühendas 12 tabelit ja mille tippkoormused olid varem põhjustanud mitmeid kriitilisi intsidente. Peaksime võimalusel vältima keerulisi mitme tabeli liitmisi. Kui liitmised on vajalikud, õppisime kaaluma päringu osadeks jaotamist ning keeruka liitmisloogika viimist rakenduse tasandile. Paljud neist probleemsetest päringutest luuakse objekt-relatsioonvastenduse (ORM) raamistike abil, seega on oluline hoolikalt üle vaadata nende loodud SQL ja veenduda, et see toimib ootuspäraselt. PostgreSQL-i puhul on samuti tavaline leida pikaajalisi jõudeolekus päringuid. Ajapiirangute, nagu idle_in_transaction_session_timeout, seadistamine on oluline, et need ei saaks autovacuumi blokeerida.

Üksikrikete probleemi leevandamine

Probleem: kui kirjutuskaitstud hoidla lakkab töötamast, saab liiklust endiselt suunata teistesse hoidlatesse. Siiski tähendab ühele kirjutajale toetumine üksikriket – kui see rivist välja läheb, mõjutab see kogu teenust.

Lahendus: enamik kriitilisi päringuid hõlmab ainult lugemispäringuid. Üksikrikke riski vähendamiseks suunasime need lugemised kirjutajalt kirjutuskaitstud hoidlatesse, tagades, et need päringud toimivad isegi siis kui põhimudel on rivist väljas. Kuigi kirjutamistoimingud ebaõnnestuvad endiselt, on selle mõju väiksem; see ei ole enam SEV0, kuna lugemised jäävad kättesaadavaks.

Põhimudeli tõrgete leevendamiseks käitame seda kõrge käideldavuse (HA) režiimis koos kuumvarusüsteemiga – pidevalt sünkroniseeritud kirjutuskaitstud hoidlaga, mis on alati valmis liikluse teenindamise üle võtma. Kui põhimudel läheb rivist välja või tuleb hoolduseks võrgust lahutada, saame seisuaja minimeerimiseks kiiresti varusüsteemi aktiveerida. Azure'i PostgreSQL-i meeskond on teinud märkimisväärset tööd, et tagada nende tõrkeülevõtmiste turvalisus ja töökindlus isegi väga suure koormuse all. Kirjutuskaitstud hoidlate tõrgete käsitlemiseks juurutame igas piirkonnas mitu hoidlat piisava võimekusvaruga, tagades, et ühe hoidla rike ei põhjusta piirkondlikku katkestust.

Töökoormuse isoleeritus

Probleem: sageli puutume kokku olukordadega, kus teatud päringud tarbivad PostgreSQL-i instantsides ebaproportsionaalselt palju ressursse. See võib põhjustada teiste sama instantsi peal töötavate töökoormuste jõudluse halvenemist. Näiteks võib uue funktsiooni käivitamine tuua kaasa ebaefektiivseid päringuid, mis koormavad suurel määral PostgreSQL-i protsessorit, aeglustades teiste kriitiliste funktsioonide päringuid.

Solution: To mitigate the “noisy neighbor” problem, we isolate workloads onto dedicated instances to ensure that sudden spikes in resource-intensive requests don’t impact other traffic. Specifically, we split requests into low-priority and high-priority tiers and route them to separate instances. This way, even if a low-priority workload becomes resource-intensive, it won’t degrade the performance of high-priority requests. We apply the same strategy across different products and services as well, so that activity from one product does not affect the performance or reliability of another.

Connection pooling

Challenge: Each instance has a maximum connection limit (5,000 in Azure PostgreSQL). It’s easy to run out of connections or accumulate too many idle ones. We’ve previously had incidents caused by connection storms that exhausted all available connections.

Solution: We deployed PgBouncer as a proxy layer to pool database connections. Running it in statement or transaction pooling mode allows us to efficiently reuse connections, greatly reducing the number of active client connections. This also cuts connection setup latency: in our benchmarks, the average connection time dropped from 50 milliseconds (ms) to 5 ms. Inter-region connections and requests can be expensive, so we co-locate the proxy, clients, and replicas in the same region to minimize network overhead and connection use time. Moreover, PgBouncer must be configured carefully. Settings like idle timeouts are critical to prevent connection exhaustion.

postgreSQL puhverserveri diagramm

Igal kirjutuskaitstud hoidlal on oma Kubernetesi juurutus, mis käitab mitut PgBounceri podi. Me haldame mitut Kubernetese juurutust sama Kubernetese teenuse raames, mis tasakaalustab liiklust podide vahel.

Caching

Challenge: A sudden spike in cache misses can trigger a surge of reads on the PostgreSQL database, saturating CPU and slowing user requests.

Solution: To reduce read pressure on PostgreSQL, we use a caching layer to serve most of the read traffic. However, when cache hit rates drop unexpectedly, the burst of cache misses can push a large volume of requests directly to PostgreSQL. This sudden increase in database reads consumes significant resources, slowing down the service. To prevent overload during cache-miss storms, we implement a cache locking (and leasing) mechanism so that only a single reader that misses on a particular key fetches the data from PostgreSQL. When multiple requests miss on the same cache key, only one request acquires the lock and proceeds to retrieve the data and repopulate the cache. All other requests wait for the cache to be updated rather than all hitting PostgreSQL at once. This significantly reduces redundant database reads and protects the system from cascading load spikes.

Scaling read replicas

Challenge: The primary streams Write Ahead Log (WAL) data to every read replica. As the number of replicas increases, the primary must ship WAL to more instances, increasing pressure on both network bandwidth and CPU. This causes higher and more unstable replica lag, which makes the system harder to scale reliably.

Solution: We operate nearly 50 read replicas across multiple geographic regions to minimize latency. However, with the current architecture, the primary must stream WAL to every replica. Although it currently scales well with very large instance types and high-network bandwidth, we can’t keep adding replicas indefinitely without eventually overloading the primary. To address this, we’re collaborating with the Azure PostgreSQL team on cascading replication(avaneb uues aknas), where intermediate replicas relay WAL to downstream replicas. This approach allows us to scale to potentially over a hundred replicas without overwhelming the primary. However, it also introduces additional operational complexity, particularly around failover management. The feature is still in testing; we’ll ensure it’s robust and can fail over safely before rolling it out to production.

postgreSQL kaskaadse replikatsiooni diagramm

Rate limit

Challenge: A sudden traffic spike on specific endpoints, a surge of expensive queries, or a retry storm can quickly exhaust critical resources such as CPU, I/O, and connections, which causes widespread service degradation.

Solution: We implemented rate-limiting across multiple layers—application, connection pooler, proxy, and query—to prevent sudden traffic spikes from overwhelming database instances and triggering cascading failures. It’s also crucial to avoid overly short retry intervals, which can trigger retry storms. We also enhanced the ORM layer to support rate limiting and when necessary, fully block specific query digests. This targeted form of load shedding enables rapid recovery from sudden surges of expensive queries.

Schema Management

Challenge: Even a small schema change, such as altering a column type, can trigger a full table rewrite(avaneb uues aknas). We therefore apply schema changes cautiously—limiting them to lightweight operations and avoiding any that rewrite entire tables.

Solution: Only lightweight schema changes are permitted, such as adding or removing certain columns that do not trigger a full table rewrite. We enforce a strict 5-second timeout on schema changes. Creating and dropping indexes concurrently is allowed. Schema changes are restricted to existing tables. If a new feature requires additional tables, they must be in alternative sharded systems such as Azure CosmosDB rather than PostgreSQL. When backfilling a table field, we apply strict rate limits to prevent write spikes. Although this process can sometimes take over a week, it ensures stability and avoids any production impact.

Results and the road ahead

This effort demonstrates that with the right design and optimizations, Azure PostgreSQL can be scaled to handle the largest production workloads. PostgreSQL handles millions of QPS for read-heavy workloads, powering OpenAI’s most critical products like ChatGPT and the API platform. We added nearly 50 read replicas, while keeping replication lag near zero, maintained low-latency reads across geo-distributed regions, and built sufficient capacity headroom to support future growth.

This scaling works while still minimizing latency and improving reliability. We consistently deliver low double-digit millisecond p99 client-side latency and five-nines availability in production. And over the past 12 months, we’ve had only one SEV-0 PostgreSQL incident (it occurred during the viral launch(avaneb uues aknas) of ChatGPT ImageGen, when write traffic suddenly surged by more than 10x as over 100 million new users signed up within a week.)

While we’re happy with how far PostgreSQL has taken us, we continue to push its limits to ensure we have sufficient runway for future growth. We’ve already migrated the shardable write-heavy workloads to our sharded systems like CosmosDB. The remaining write-heavy workloads are more challenging to shard—we’re actively migrating those as well to further offload writes from the PostgreSQL primary. We’re also working with Azure to enable cascading replication so we can safely scale to significantly more read replicas.

Looking ahead, we’ll continue to explore additional approaches to further scale, including sharded PostgreSQL or alternative distributed systems, as our infrastructure demands continue to grow.

Autor

Bohan Zhang

Tänuavaldused

Erilised tänud Jon Lee’le, Sicheng Liu’le, Chaomin Yu’le ja Chenglong Hao’le, kes panustasid sellesse postitusse, ning kogu meeskonnale, kes aitas PostgreSQL-i skaleerida. Sooviksime tänada ka Azure PostgreSQL meeskonda nende kindla partnerluse eest.