Pereiti prie pagrindinio turinio
OpenAI

2026 m. sausio 22 d.

Inžinerija

„PostgreSQL“ mastelio didinimas 800 mln. „ChatGPT“ naudotojų

Autorius: Bohan Zhang, techninio personalo narys

Įkeliama...

Daugelį metų „PostgreSQL“ buvo viena svarbiausių fone veikiančių duomenų sistemų, palaikančių pagrindinius produktus, tokius kaip „ChatGPT“ ir „OpenAI“ API. Sparčiai augant mūsų naudotojų bazei, eksponentiškai padidėjo ir duomenų bazėms keliami reikalavimai. Per pastaruosius metus mūsų „PostgreSQL“ apkrova išaugo daugiau nei 10 kartų ir toliau sparčiai didėja.

Mūsų pastangos tobulinti gamybinę infrastruktūrą siekiant palaikyti šį augimą atskleidė naują įžvalgą: „PostgreSQL“ mastelį galima keisti taip, kad ji patikimai palaikytų daug didesnius skaitymo krūvius, nei daugelis manė esant įmanoma. Sistema (iš pradžių sukurta Kalifornijos universiteto Berklyje mokslininkų komandos) leido mums palaikyti didžiulį pasaulinį srautą naudojant vieną pirminį „Azure PostgreSQL“ lankstaus serverio egzempliorių(atsidaro naujame lange) ir beveik 50 skaitymo replikų, paskirstytų keliuose regionuose visame pasaulyje. Tai pasakojimas apie tai, kaip, pasitelkę kruopštų optimizavimą ir solidžią inžineriją, padidinome „OpenAI“ naudojamos „PostgreSQL“ mastelį, kad ji palaikytų milijonus užklausų per sekundę 800 mln. naudotojų; taip pat aptarsime pagrindines pakeliui išmoktas pamokas.

Pradinio projekto trūkumai

Paleidus „ChatGPT“, srautas augo precedento neturinčiu tempu. Siekdami jį palaikyti, skubiai įdiegėme plataus masto optimizacijas tiek programos, tiek „PostgreSQL“ duomenų bazės lygmenyse, padidinome mastelį naudodami galingesnius egzempliorius ir išplėtėme sistemą pridėdami daugiau skaitymo replikų. Ši architektūra mums ilgą laiką puikiai tarnavo. Nuolat tobulinama, ji ir toliau suteikia pakankamai erdvės būsimam augimui.

Gali skambėti neįtikėtinai, kad vieno pirminio serverio architektūra gali patenkinti „OpenAI“ masto poreikius, vis dėlto praktiškai tai įgyvendinti nėra paprasta. Susidūrėme su keliais incidentais (SEV), kuriuos sukėlė „Postgres“ perkrova, ir jie dažnai vykdavo pagal tą patį scenarijų: dėl problemos aukštesniame lygmenyje staiga padidėdavo duomenų bazės apkrova, pavyzdžiui, dėl visuotinio podėlio duomenų neradimo sutrikus podėlio sluoksniui, procesorių prisotinusio brangių daugiakrypčių junginių antplūdžio arba rašymo audros paleidus naują funkciją. Didėjant išteklių naudojimui, ilgėja užklausų delsa, o užklausų laikas pradeda baigtis. Pakartotiniai bandymai dar labiau padidina apkrovą, sukeldami užburtą ratą, galintį pabloginti visų „ChatGPT“ ir API paslaugų veikimą.

Apkrovos mastelio keitimo diagrama

Nors „PostgreSQL“ gerai tinka mūsų skaitymo krūvių masteliui keisti, vis dar susiduriame su iššūkiais esant dideliam rašymo srautui. Tai daugiausia lemia „PostgreSQL“ kelių versijų lygiagretumo valdymo (multiversion concurrency control, MVCC) įgyvendinimas, dėl kurio ji tampa mažiau efektyvi atliekant daug rašymo reikalaujančius darbus. Pavyzdžiui, kai užklausa atnaujina kortežą (lentelės eilutės įrašą) ar net vieną lauką, visa eilutė nukopijuojama sukuriant naują versiją. Esant didelėms rašymo apkrovoms, tai lemia didelį rašymo pagausėjimą. Tai taip pat padidina skaitymo pagausėjimą, nes, norint gauti naujausią versiją, užklausos turi nuskaityti kelias kortežų versijas (nebegaliojančius kortežus). MVCC sukelia papildomų iššūkių, tokių kaip lentelių ir indeksų išsipūtimas, didesnės indeksų priežiūros sąnaudos ir sudėtingas automatinio valymo derinimas. (Išsamią šių problemų analizę galite rasti tinklaraščio įraše, kurį parašiau kartu su Carnegie Mellon universiteto prof. Andy Pavlo, pavadinimu The Part of PostgreSQL We Hate the Most(atsidaro naujame lange), pacituotame(atsidaro naujame lange) „PostgreSQL“ „Wikipedia“ puslapyje.)

„PostgreSQL“ mastelio keitimas iki milijonų užklausų per sekundę (QPS)

Siekdami sušvelninti šiuos apribojimus ir sumažinti rašymo spaudimą, perkėlėme ir toliau perkeliame skaidomus (t. y. horizontaliai skirstomus), daug rašymo reikalaujančius krūvius į segmentuotas sistemas, tokias kaip „Azure Cosmos DB“, optimizuodami programos logiką, kad sumažintume nereikalingų įrašų skaičių. Taip pat nebeleidžiame į dabartinį „PostgreSQL“ diegimą įtraukti naujų lentelių. Nauji krūviai pagal numatytąsias nuostatas nukreipiami į segmentuotas sistemas.

Nors mūsų infrastruktūra keitėsi, „PostgreSQL“ liko nesegmentuota, o visi įrašai atliekami viename pirminiame egzemplioriuje. Pagrindinis motyvas – esamų programos krūvių segmentavimas būtų itin sudėtingas ir imlus laikui, reikalautų pakeitimų šimtuose programos prieigos taškų ir galėtų užtrukti mėnesius ar net metus. Kadangi mūsų krūviai daugiausia susiję su skaitymu, o mes įdiegėme daugybę optimizacijų, dabartinė architektūra vis dar suteikia pakankamai atsargos tolesniam srauto augimui palaikyti. Nors neatmetame galimybės ateityje segmentuoti „PostgreSQL“, artimiausiu metu tai nėra prioritetas, nes turime pakankamai galimybių dabartiniam ir būsimam augimui.

Tolesniuose skyriuose aptarsime kilusius iššūkius ir plačias optimizacijas, kurias įgyvendinome siekdami juos įveikti ir išvengti būsimų sutrikimų, stumdami „PostgreSQL“ galimybių ribas ir didindami mastelį iki milijonų užklausų per sekundę (QPS).

Pirminio serverio apkrovos mažinimas

Iššūkis: esant tik vienam rašymo serveriui, vieno pirminio mazgo sąranka negali užtikrinti rašymo mastelio. Dideli rašymo šuoliai gali greitai perkrauti pirminį serverį ir paveikti tokias paslaugas kaip „ChatGPT“ bei mūsų API.

Sprendimas: kiek įmanoma sumažiname pirminio serverio apkrovą – tiek skaitymo, tiek rašymo, – kad užtikrintume pakankamą pajėgumą rašymo šuoliams atlaikyti. Skaitymo srautas, kai tik įmanoma, nukreipiamas į replikas. Vis dėlto kai kurios skaitymo užklausos turi likti pirminiame serveryje, nes jos yra rašymo operacijų dalis. Tokiais atvejais stengiamės užtikrinti, kad jos būtų veiksmingos, ir vengiame lėtų užklausų. Kalbant apie rašymo srautą, skaidomus, daug rašymo reikalaujančius krūvius perkėlėme į segmentuotas sistemas, pavyzdžiui, „Azure CosmosDB“. Krūvius, kuriuos segmentuoti sunkiau, bet kurie vis tiek generuoja didelę rašymo apimtį, perkelti užtrunka ilgiau, ir šis procesas vis dar vyksta. Taip pat agresyviai optimizavome savo programas, kad sumažintume rašymo apkrovą; pavyzdžiui, ištaisėme programos klaidas, dėl kurių atsirasdavo perteklinių įrašų, ir, kur tinka, įdiegėme atidėtuosius rašymus srauto šuoliams sušvelninti. Be to, pildydami lentelių laukus atgaline data, taikome griežtus srauto ribojimus, kad išvengtume per didelio rašymo spaudimo.

Užklausų optimizavimas

Iššūkis: nustatėme keletą brangių užklausų „PostgreSQL“ sistemoje. Anksčiau staigūs šių užklausų kiekio šuoliai sunaudodavo daug procesoriaus išteklių, sulėtindami tiek „ChatGPT“, tiek API užklausas.

Sprendimas: kelios brangios užklausos, pavyzdžiui, jungiančios daug lentelių, gali smarkiai pabloginti arba net visiškai sustabdyti visos paslaugos veikimą. Turime nuolat optimizuoti „PostgreSQL“ užklausas, kad užtikrintume jų efektyvumą ir išvengtume įprastų operatyviojo operacijų apdorojimo (OLTP) antimodelių. Pavyzdžiui, kartą aptikome itin brangią užklausą, jungusią 12 lentelių; šios užklausos šuoliai anksčiau buvo sukėlę didelio prioriteto incidentus. Turėtume vengti sudėtingų kelių lentelių junginių, kai tik įmanoma. Jei junginiai būtini, išmokome apsvarstyti galimybę suskaidyti užklausą ir sudėtingą jungimo logiką perkelti į programos lygmenį. Daugelį šių problemiškų užklausų sugeneruoja objektinio relacinio atvaizdavimo (ORM) karkasai, todėl svarbu atidžiai peržiūrėti jų kuriamą SQL kodą ir įsitikinti, kad jis veikia taip, kaip tikimasi. Taip pat „PostgreSQL“ sistemoje dažnai pasitaiko ilgai neveikiančių užklausų. Būtina sukonfigūruoti skirtąjį laiką, pavyzdžiui, „idle_in_transaction_session_timeout“, kad jos neblokuotų automatinio valymo.

Vieno trikties taško rizikos mažinimas

Iššūkis: sugedus skaitymo replikai, srautą vis tiek galima nukreipti į kitas replikas. Tačiau pasikliaujant vienu rašymo serveriu atsiranda vienas trikties taškas – jam sugedus, paveikiama visa paslauga.

Sprendimas: dauguma svarbiausių užklausų apima tik skaitymą. Siekdami sumažinti pirminio serverio kaip vieno trikties taško riziką, perkėlėme šiuos skaitymus iš rašymo serverio į replikas, užtikrindami, kad šios užklausos būtų aptarnaujamos net ir sugedus pirminiam serveriui. Nors rašymo operacijos vis tiek nepavyktų, poveikis yra mažesnis; tai nebėra SEV0 lygio incidentas, nes skaitymas išlieka pasiekiamas.

Siekdami sušvelninti pirminio serverio gedimus, naudojame pirminį serverį didelio pasiekiamumo (angl. High-Availability, HA) režimu su karštąja atsargine kopija – nuolat sinchronizuojama replika, kuri visada pasiruošusi perimti srauto aptarnavimą. Jei pirminis serveris sugenda arba jį reikia atjungti techninei priežiūrai, galime greitai panaudoti atsarginę kopiją, kad sumažintume prastovos laiką. „Azure PostgreSQL“ komanda atliko didelį darbą užtikrindama, kad šie perjungimai išliktų saugūs ir patikimi net esant labai didelei apkrovai. Kad susitvarkytume su skaitymo replikų gedimais, kiekviename regione įdiegiame kelias replikas su pakankama pajėgumo atsarga, užtikrindami, kad vienos replikos gedimas nesukeltų regioninio sutrikimo.

Krūvių atskyrimas

Iššūkis: dažnai susiduriame su situacijomis, kai tam tikros užklausos sunaudoja neproporcingai daug „PostgreSQL“ egzempliorių išteklių. Tai gali pabloginti kitų tuose pačiuose egzemplioriuose vykdomų krūvių našumą. Pavyzdžiui, paleidus naują funkciją gali atsirasti neveiksmingų užklausų, kurios smarkiai apkrauna „PostgreSQL“ procesorių, sulėtindamos kitų svarbių funkcijų užklausas.

Sprendimas: valdome beveik 50 skaitymo replikų keliuose geografiniuose regionuose, kad sumažintume delsą. Tačiau esant dabartinei architektūrai pirminis serveris turi perduoti WAL į kiekvieną repliką. Nors šiuo metu sistema gerai plečiasi naudojant labai didelius egzempliorių tipus ir didelį tinklo pralaidumą, negalime be galo pridėti replikų galiausiai neperkraudami pirminio serverio. Siekdami tai išspręsti, bendradarbiaujame su „Azure PostgreSQL“ komanda kurdami pakopinę replikaciją(atsidaro naujame lange), kai tarpinės replikos perduoda WAL pasroviui esančioms replikoms. Šis metodas leidžia padidinti mastelį iki daugiau nei šimto replikų neapkraunant pirminio serverio. Tačiau tai taip pat sukelia papildomą operacinį sudėtingumą, ypač susijusį su perjungimo valdymu. Funkcija vis dar testuojama; prieš diegdami ją gamybinėje aplinkoje, užtikrinsime, kad ji būtų patikima ir galėtų saugiai atlikti perjungimą.

„PostgreSQL“ pakopinės replikacijos diagrama

Srauto ribojimas

Iššūkis: staigus srauto šuolis konkrečiuose prieigos taškuose, brangių užklausų antplūdis arba pakartotinių bandymų audra gali greitai išnaudoti svarbius išteklius, tokius kaip procesorius, įvestis / išvestis ir ryšiai, o tai pablogina platų paslaugų veikimą.

Sprendimas: įdiegėme srauto ribojimą keliuose lygmenyse – programos, ryšių telkimo priemonės, tarpinio serverio ir užklausų, – kad staigūs srauto šuoliai neperkrautų duomenų bazės egzempliorių ir nesukeltų pakopinių gedimų. Taip pat labai svarbu vengti pernelyg trumpų pakartotinio bandymo intervalų, kurie gali sukelti pakartotinių bandymų audras. Taip pat patobulinome ORM sluoksnį, kad jis palaikytų srauto ribojimą ir prireikus visiškai blokuotų tam tikras užklausų santraukas. Ši tikslinė apkrovos mažinimo forma leidžia greitai atsigauti po staigių brangių užklausų antplūdžių.

Schemų valdymas

Iššūkis: net ir nedidelis schemos pakeitimas, pavyzdžiui, stulpelio tipo keitimas, gali sukelti visos lentelės perrašymą(atsidaro naujame lange). Todėl schemų pakeitimus taikome atsargiai – apsiribojame lengvomis operacijomis ir vengiame tokių, kurios perrašo visas lenteles.

Sprendimas: leidžiami tik smulkūs schemos pakeitimai, pavyzdžiui, tam tikrų stulpelių, kuriems nereikia perrašyti visos lentelės, pridėjimas arba pašalinimas. Schemų pakeitimams taikome griežtą penkių sekundžių skirtąjį laiką. Leidžiama lygiagrečiai kurti ir šalinti indeksus. Schemų pakeitimai taikomi tik esamoms lentelėms. Jei naujai funkcijai reikia papildomų lentelių, jos turi būti alternatyviose segmentuotose sistemose, tokiose kaip „Azure CosmosDB“, o ne „PostgreSQL“. Pildydami lentelės lauką atgaline data, taikome griežtus srauto ribojimus, kad išvengtume rašymo šuolių. Nors šis procesas kartais gali užtrukti ilgiau nei savaitę, jis užtikrina stabilumą ir padeda išvengti bet kokio poveikio gamybinei aplinkai.

Rezultatai ir ateities planai

Šios pastangos rodo, kad tinkamai suprojektavus ir optimizavus, „Azure PostgreSQL“ mastelį galima keisti taip, kad ji atlaikytų didžiausius gamybinius krūvius. „PostgreSQL“ apdoroja milijonus QPS, susijusių su skaitymo krūviais, ir palaiko svarbiausius „OpenAI“ produktus, tokius kaip „ChatGPT“ ir API platforma. Pridėjome beveik 50 skaitymo replikų, išlaikydami beveik nulinį replikacijos vėlavimą, užtikrinome mažą skaitymo delsą geografiškai paskirstytuose regionuose ir sukūrėme pakankamą pajėgumų atsargą ateities augimui.

Šis mastelio keitimas veikia kartu mažinant delsą ir gerinant patikimumą. Gamybinėje aplinkoje nuosekliai užtikriname mažą dviženklę milisekundžių p99 kliento pusės delsą ir 99,999 proc. pasiekiamumą. Per pastaruosius 12 mėnesių turėjome tik vieną SEV-0 „PostgreSQL“ incidentą (jis įvyko per virusinį „ChatGPT ImageGen“ paleidimą(atsidaro naujame lange), kai rašymo srautas staiga išaugo daugiau nei 10 kartų, per savaitę užsiregistravus daugiau nei 100 mln. naujų naudotojų).

Nors džiaugiamės tuo, kiek „PostgreSQL“ mums padėjo, ir toliau bandome jos galimybių ribas, siekdami užtikrinti pakankamą erdvę ateities augimui. Jau perkėlėme skaidomus, daug rašymo reikalaujančius krūvius į savo segmentuotas sistemas, tokias kaip „CosmosDB“. Likusius daug rašymo reikalaujančius krūvius segmentuoti sunkiau – aktyviai perkeliame ir juos, kad dar labiau sumažintume „PostgreSQL“ pirminiam serveriui tenkantį rašymo krūvį. Taip pat bendradarbiaujame su „Azure“, kad įgalintume pakopinę replikaciją ir galėtume saugiai padidinti skaitymo replikų skaičių.

Žvelgdami į ateitį, ir toliau ieškosime papildomų būdų masteliui didinti, įskaitant segmentuotą „PostgreSQL“ arba alternatyvias paskirstytąsias sistemas, nes mūsų infrastruktūros poreikiai toliau auga.

Autorius

Bohan Zhang

Padėkos

Ypatingas ačiū Jon Lee, Sicheng Liu, Chaomin Yu ir Chenglong Hao, prisidėjusiems prie šio įrašo, ir visai komandai, padėjusiai keisti „PostgreSQL“ mastelį. Taip pat norėtume padėkoti „Azure PostgreSQL“ komandai už stiprią partnerystę.