Pāriet uz galveno saturu
OpenAI

2026. gada 22. janvāris

Inženierija

PostgreSQL mērogošana, apkalpojot 800 miljonus ChatGPT lietotāju

Bohan Zhang, tehniskā personāla loceklis

Notiek ielāde…

Jau gadiem PostgreSQL ir bijusi viena no vissvarīgākajām, aizkulisēs strādājošajām datu sistēmām, kas darbina tādus pamatproduktus kā ChatGPT un OpenAI API. Tā kā mūsu lietotāju bāze strauji aug, arī prasības mūsu datubāzēm ir eksponenciāli kāpušas. Pēdējā gada laikā mūsu PostgreSQL slodze ir palielinājusies vairāk nekā desmitkārtīgi, un tā turpina strauji augt.

Mūsu centieni uzlabot ražošanas infrastruktūru, lai uzturētu šo izaugsmi, atklāja jaunu atziņu: PostgreSQL var paplašināt tā, lai tas uzticami atbalstītu daudz lielākas, uz lasīšanu orientētas darba slodzes, nekā daudzi iepriekš uzskatīja par iespējamu. Šī sistēma (ko sākotnēji izveidoja Kalifornijas Universitātes (Bērklija) zinātnieku komanda) ir ļāvusi mums atbalstīt milzīgu globālo datplūsmu ar vienu primāro Azure PostgreSQL elastīgā servera instanci(atveras jaunā logā) un gandrīz 50 lasīšanas replikām, kas izvietotas vairākos pasaules reģionos. Šis ir stāsts par to, kā OpenAI izvērsa PostgreSQL, lai, izmantojot stingru optimizāciju un stabilu inženieriju, atbalstītu miljoniem vaicājumu sekundē 800 miljoniem lietotāju; mēs arī pastāstīsim par galvenajām atziņām, ko guvām šajā procesā.

Plaisas mūsu sākotnējā projektā

Pēc ChatGPT palaišanas datplūsma pieauga vēl nebijušā ātrumā. Lai to atbalstītu, mēs strauji ieviesām plašus optimizācijas pasākumus gan lietojumprogrammas, gan PostgreSQL datubāzes līmenī, veicām mērogošanu uz augšu, palielinot instanču jaudu, un mērogošanu uz āru, pievienojot papildu lasīšanas replikas. Šī arhitektūra mums ir labi kalpojusi jau ilgu laiku. Ar pastāvīgiem uzlabojumiem tā turpina nodrošināt pietiekamas spējas nākotnes izaugsmei.

Var šķist pārsteidzoši, ka OpenAI mēroga prasības var izpildīt viena primārā arhitektūra, tomēr praksē to īstenot nav vienkārši. Mēs esam novērojuši vairākus SEV incidentus, ko izraisījusi PostgreSQL pārslodze, un tie bieži seko vienam un tam pašam scenārijam – augšējā līmeņa problēma izraisa strauju datubāzes noslodzes pieaugumu, piemēram, plašus kešatmiņas trāpījumu zudumus kešdarbes slāņa atteices dēļ, dārgu daudzpakāpju savienojumu pieplūdumu, kas noslogo CPU, vai intensīvu rakstīšanas vilni, ko izraisa jaunas funkcionalitātes palaišana. Pieaugot resursu noslodzei, palielinās vaicājumu latentums un pieprasījumiem sāk iestāties noildze. Atkārtoti mēģinājumi pēc tam vēl vairāk palielina slodzi, izraisot apburto loku, kas var pasliktināt visu ChatGPT un API pakalpojumu darbību.

Mērogošanas slodzes diagramma

Lai gan PostgreSQL labi mērogojas mūsu lasīšanas intensīvajām darba slodzēm, mēs joprojām saskaramies ar grūtībām periodos ar lielu rakstīšanas slodzi. Tas lielā mērā ir saistīts ar PostgreSQL daudzversiju vienlaicīguma kontroles (MVCC) ieviešanu, kas padara to mazāk efektīvu rakstīšanas intensīvām darba slodzēm. Piemēram, ja vaicājums atjaunina ierakstu vai pat tikai vienu lauku, tiek nokopēta visa rinda, lai izveidotu jaunu versiju. Pie lielām rakstīšanas slodzēm tas rada ievērojamu rakstīšanas pastiprinājumu. Tas arī palielina lasīšanas pastiprinājumu, jo vaicājumiem ir jāizskata vairākas ierakstu versijas (novecojuši ieraksti), lai iegūtu jaunāko versiju. MVCC rada papildu grūtības, piemēram, tabulu un indeksu pārblīvētību, lielāku indeksu uzturēšanas slodzi un sarežģītu autovacuum regulēšanu. (Šo jautājumu padziļinātu izpēti var atrast blogā, ko rakstīju kopā ar Kārnegī Melona Universitātes profesoru Endiju Pavlo, ar nosaukumu The Part of PostgreSQL We Hate the Most Most(atveras jaunā logā), citēts(atveras jaunā logā) PostgreSQL Vikipēdijas lapā.)

PostgreSQL mērogošana līdz miljoniem QPS

Lai mazinātu šos ierobežojumus un samazinātu rakstīšanas spiedienu, mēs esam migrējuši un turpinām migrēt šardējamas (t.i., horizontāli sadalāmas), rakstīšanas intensīvas darba slodzes uz šardētām sistēmām, piemēram, Azure Cosmos DB, optimizējot lietojumprogrammas loģiku, lai samazinātu nevajadzīgu rakstīšanu. Mēs arī vairs neatļaujam pievienot jaunas tabulas pašreizējai PostgreSQL izvietošanai. Jaunās darba slodzes pēc noklusējuma tiek novirzītas uz šardētajām sistēmām.

Pat mūsu infrastruktūrai attīstoties, PostgreSQL ir palicis nešardēts, un visas rakstīšanas darbības apkalpo viena primārā instance. Galvenais iemesls ir tas, ka esošo lietojumprogrammu darba slodžu sadalīšana šardos būtu ļoti sarežģīta un laikietilpīga, prasot izmaiņas simtiem lietojumprogrammu galapunktu un potenciāli aizņemot mēnešus vai pat gadus. Tā kā mūsu darba slodzes galvenokārt ir lasīšanas intensīvas un mēs esam ieviesuši plašas optimizācijas, pašreizējā arhitektūra joprojām nodrošina pietiekamu rezerves jaudu, lai atbalstītu turpmāku trafika pieaugumu. Lai gan mēs neizslēdzam PostgreSQL šardošanas ieviešanu nākotnē, tuvākajā laikā tā nav prioritāte, ņemot vērā pietiekamo rezervi, kas mums ir pašreizējai un nākotnes izaugsmei.

Turpmākajās sadaļās mēs detalizēti aplūkosim grūtības, ar kurām saskārāmies, kā arī plašos optimizācijas pasākumus, ko ieviesām, lai tās risinātu un nepieļautu turpmākus darbības pārtraukumus, virzot PostgreSQL līdz tā veiktspējas robežām un mērogojot to līdz miljoniem vaicājumu sekundē (QPS).

Slodzes samazināšana uz primārā mezgla

Izaicinājums: konfigurācijā ar vienu primāro mezglu un tikai vienu rakstītāju rakstīšanas darbības nav iespējams mērogot. Strauji rakstīšanas pieaugumi var ātri pārslogot primāro mezglu un ietekmēt tādus pakalpojumus kā ChatGPT un mūsu API.

Risinājums: Mēs pēc iespējas samazinām primārā mezgla slodzi – gan lasīšanu, gan rakstīšanu –, lai nodrošinātu, ka tam ir pietiekama jauda, lai apstrādātu straujus rakstīšanas kāpumus. Lasīšanas datplūsma, kur vien iespējams, tiek novirzīta uz replikām. Tomēr daži lasīšanas vaicājumi ir jāatstāj primārajā mezglā, jo tie ir daļa no rakstīšanas darījumiem. Mēs koncentrējamies uz to, lai tie būtu efektīvi, un izvairāmies no lēniem vaicājumiem. Rakstīšanas datplūsmai mēs esam pārcēluši šardējamās, rakstīšanas intensīvās darba slodzes uz šardētām sistēmām, piemēram, Azure CosmosDB. Tādu darba slodžu pārcelšana, kuras ir grūtāk sadalīt, bet kuras joprojām rada lielu rakstīšanas apjomu, aizņem vairāk laika, un šis process joprojām turpinās. Mēs arī agresīvi optimizējām savas lietojumprogrammas, lai samazinātu rakstīšanas slodzi; piemēram, esam novērsuši lietojumprogrammu kļūdas, kas izraisīja liekas rakstīšanas darbības, un ieviesuši aizkavētu rakstīšanu, kur tas ir piemēroti, lai izlīdzinātu straujus datplūsmas kāpumus. Turklāt, aizpildot tabulu laukus atpakaļejoši, mēs piemērojam stingrus ātruma ierobežojumus, lai novērstu pārmērīgu rakstīšanas slodzi.

Vaicājumu optimizēšana

Izaicinājums: Mēs identificējām vairākus resursietilpīgus vaicājumus PostgreSQL. Iepriekš pēkšņi šo vaicājumu apjoma pieaugumi patērēja lielu CPU resursu daudzumu, palēninot gan ChatGPT, gan API pieprasījumus.

Risinājums: Daži resursietilpīgus vaicājumi, piemēram, tie, kas apvieno daudzas tabulas, var būtiski pasliktināt vai pat apturēt visu pakalpojumu. Mums ir nepārtraukti jāoptimizē PostgreSQL vaicājumi, lai nodrošinātu to efektivitāti un izvairītos no izplatītiem tiešsaistes darījumu apstrādes (OLTP) antiparaugmodeļiem. Piemēram, mēs reiz identificējām ārkārtīgi resursietilpīgu vaicājumu, kas savienoja 12 tabulas, un šī vaicājuma strauji pieaugumi bija atbildīgi par iepriekšējiem augstas smaguma pakāpes SEV incidentiem. Ja vien iespējams, jāizvairās no sarežģītiem vairāku tabulu savienojumiem. Ja savienošanas ir nepieciešamas, mēs iemācījāmies apsvērt iespēju sadalīt vaicājumu un tā vietā sarežģīto savienošanas loģiku pārcelt uz lietojumprogrammu slāni. Daudzi no šiem problemātiskajiem vaicājumiem tiek ģenerēti ar objektu–relāciju kartēšanas (ORM) ietvaru palīdzību, tāpēc ir svarīgi rūpīgi pārskatīt to ģenerēto SQL un pārliecināties, ka tas darbojas, kā paredzēts. PostgreSQL ir arī bieži sastopami ilgstoši dīkstāvē esoši pieprasījumi. Lai novērstu autovacuum bloķēšanu, ir svarīgi konfigurēt tādas noildzes kā idle_in_transaction_session_timeout.

Viena atteices punkta mazināšana

Izaicinājums: ja kāda lasīšanas replika nedarbojas, datplūsmu joprojām var novirzīt uz citām replikām. Tomēr paļaušanās uz vienu rakstītāju nozīmē, ka pastāv viens kļūmes punkts – ja tas nedarbojas, tas ietekmē visu pakalpojumu.

Risinājums: Lielākā daļa kritiski svarīgo pieprasījumu ietver tikai lasīšanas vaicājumus. Lai mazinātu primārā mezgla vienīgo kļūmes punktu, mēs šos lasījumus no rakstītāja pārnesām uz replikām, tādējādi nodrošinot, ka šie pieprasījumi var tikt apstrādāti arī tad, ja primārais mezgls nedarbojas. Lai gan rakstīšanas darbības joprojām neizdodas, ietekme ir samazināta; tas vairs nav SEV0, jo lasīšanas darbības paliek pieejamas.

Lai mazinātu primārā mezgla atteices, mēs darbinām to augstas pieejamības (HA) režīmā ar karsto rezerves instanci – nepārtraukti sinhronizētu repliku, kas vienmēr ir gatava pārņemt datplūsmas apkalpošanu. Ja primārais mezgls pārstāj darboties vai ir jāatvieno apkopei, mēs varam ātri paaugstināt rezerves mezglu, lai samazinātu darbības pārtraukuma ilgumu. Azure PostgreSQL komanda ir veikusi nozīmīgu darbu, lai nodrošinātu, ka šīs pārslēgšanās paliek drošas un uzticamas pat ļoti augstas slodzes apstākļos. Lai novērstu lasīšanas repliku atteices, mēs katrā reģionā izvietojam vairākas replikas ar pietiekamu jaudas rezervi, nodrošinot, ka vienas replikas atteice neizraisa reģionālu darbības pārtraukumu.

Darba slodzes izolācija

Izaicinājums: Mēs bieži sastopamies ar situācijām, kad daži pieprasījumi patērē nesamērīgi daudz resursu PostgreSQL instancēs. Tas var izraisīt veiktspējas pasliktināšanos citām darba slodzēm, kas darbojas tajās pašās instancēs. Piemēram, jaunas funkcijas palaišana var ieviest neefektīvus vaicājumus, kas intensīvi izmanto PostgreSQL CPU, palēninot pieprasījumus citām kritiski svarīgām funkcijām.

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 starpniekservera diagramma

Katrai lasīšanas replikai ir sava Kubernetes izvietošana, kurā darbojas vairākas PgBouncer pod instances. Mēs veicam vairākus Kubernetes izvietojumus aiz viena un tā paša Kubernetes pakalpojuma, kas līdzsvaro trafiku starp pod instancēm.

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(atveras jaunā logā), 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 kaskādes replikācijas diagramma

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(atveras jaunā logā). 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(atveras jaunā logā) 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.

Autors

Bohan Zhang

Pateicības

Īpaša pateicība Jon Lee, Sicheng Liu, Chaomin Yu un Chenglong Hao, kuri sniedza ieguldījumu šajā ierakstā, un visai komandai, kas palīdzēja mērogot PostgreSQL. Mēs arī vēlamies pateikties Azure PostgreSQL komandai par viņu ciešo sadarbību.