OpenAI

2. marraskuuta 2026

Tekniikka

Gitin skaalaaminen OpenAI:lla

Rakennamme agenttien mittakaavaan skaalautuvaa versionhallintaa ja panostamme samalla Git-ekosysteemiin.

Kirjoittajat: Aaron Friel, Taylor Blau ja Ted Nyman, teknisen henkilöstön jäsenet

Ladataan...

Viime vuoden aikana monorepositoriomme koko ja sille asetetut vaatimukset ovat kasvaneet huimaa vauhtia. Oli selvää, että versionhallintajärjestelmämme oli uudistettava, jotta se skaalautuisi Codexin mahdollistaman rinnakkaisen työn tasolle.

Rakensimme Pandon, uuden taustajärjestelmän Git-repositorioille, keskeyttämättä kehitystyötä tai muuttamatta tiimimme tapaa käyttää Gitiä. Nyt kaikki OpenAI:n monorepositoriossa tehtävä kehitystyö perustuu Pandoon. Pando suunniteltiin täyttämään kaksi kunnianhimoista tavoitetta. Ensimmäinen on vaakasuunnassa skaalautuva kirjoitus, joka on optimoitu samanaikaisille lähetyksille useisiin haaroihin. Toinen on lukemisen suoritustehon maksimointi, jotta asiakkaat voivat ladata dataa niin nopeasti, että koko käytettävissä oleva verkkokaista tulee hyödynnettyä.

Saavutimme nämä tavoitteet säilyttäen yhteensopivuuden Git-protokollan ja -asiakasohjelman kanssa. Näin sekä kehittäjämme että agenttimme pystyivät ottamaan Pandon saumattomasti osaksi nykyisiä työnkulkujaan. Tuotannossa Pando lyhensi lähetysviiveen mediaanin lähes viidesosaan. Se toimittaa nyt lähes petatavun Git-dataa päivässä.

Tässä kerromme, miksi rakensimme uuden versionhallintajärjestelmän ja miksi päätimme säilyttää Git-yhteensopivuuden. Vertaamme järjestelmäämme yleisiin tapoihin skaalata Gitiä ja kuvaamme, miksi Pando pystyy vastaamaan OpenAI:n skaalautumistarpeisiin ainutlaatuisella tavalla. Käsittelemme myös tulevia suunnitelmiamme ja sitä, miten jatkamme Gitin kehittämistä agenttien työskentelyn mittakaavan tukemiseksi.

Miksi tarvitsimme uuden versionhallintajärjestelmän

Codex on muuttanut OpenAI:n kehitystyön mittakaavaa ja tahtia: kehittäjät voivat nyt tehdä huomattavasti enemmän työtä rinnakkain. Se tarkoittaa enemmän haaroja, lähetyksiä ja yhdistämisiä sekä enemmän hakuja ja kloonauksia kehitysympäristöistä, tutkimusajoista ja jatkuvan integraation järjestelmistä.

Nämä vaatimukset kertautuvat. Yhdellä kehittäjällä on nyt useita muutoksia valmiina jatkuvaan integraatioon samanaikaisesti, ja jokainen lähetys voi käynnistää useita ajoja, jotka hakevat saman kommitin.

Viime vuoden lopulta alkaen monorepositoriomme taustajärjestelmillä alkoi olla vaikeuksia pysyä tahdissa. Haut ja lähetykset olivat hitaita ja yhdistämiset epäonnistuivat. Luotettavuus laski ajoittain alle 90 prosentin. Olimmeko törmänneet itse Gitin rajoihin vai siihen, miten tarjosimme monorepositoriomme käyttöön? Git syntyi yhteisössä, joka vaihtoi ytimen korjaustiedostoja sähköpostitse. Yli kahden vuosikymmenen ajan kehittäjät ovat mukauttaneet työkalujaan Gitin ympärille ohjelmistokehityksen tapojen muuttuessa. Kun omassa monorepositoriossamme alkoi ilmetä kitkaa, meille oli tärkeää voida jatkaa tämän työn pohjalta.

Näimme tavan säilyttää tuttu työnkulku ja rakentaa taustajärjestelmä uudelleen niin, että se käsittelee lähetyksiä eri haaroihin rinnakkain ja tarjoaa saman historian monille lukijoille samanaikaisesti. Gitin säilyttäminen versionhallinnan työnkulkumme perustana tarkoitti, että asiakasohjelman parannukset voisivat hyödyttää muitakin kuin OpenAI:ta. Halusimme viedä nämä parannukset omasta Git-versiostamme⁠(avautuu uudessa ikkunassa) alkuperäiseen projektiin ja jakaa ne laajemman yhteisön kanssa.

Gitin suunnittelu suureen mittakaavaan

Versionhallintajärjestelmän skaalaamisessa on kaksi keskeistä ulottuvuutta: monet kirjoittajat lähettävät muutoksia eri haaroihin, ja monet lukijat hakevat samaa historiaa. Pando optimoi molemmat.

Ensinnäkin Pando koordinoi kunkin haaran päivityksiä itsenäisesti. Toisistaan riippumattomien haarojen päivitykset voivat edetä rinnakkain, ja haaraa hakeva lukija saa kyseisen version tarvitseman historian. Vastapainona useita haaroja tarkasteleva lukija voi nähdä niiden tilat eri ajanhetkiltä.

Toiseksi Pando käyttää pakettitiedostoja uudelleen eri hauissa sen sijaan, että loisi jokaiselle asiakkaalle oman tiedoston. Pakettitiedosto on Gitin muoto useiden objektien pakkaamiseen yhteen. Asiakas saattaa ladata joitakin jo omistamiaan objekteja, mutta palvelin voi toimittaa samat tavut monille asiakkaille vähäisellä laskennalla.

Näiden valintojen ansiosta voimme skaalata kirjoituksia eri haaroihin ja palvella lukuja välimuistista. Jotta näemme, miten nämä ratkaisut sopivat yhteen, tarkastellaan ensin, miten Git tallentaa ja siirtää historiaa.

Gitin objektitallennuksen perusteet

Gitin on pystyttävä pitämään repositorion kaksi osaa synkronoituina: objektit ja viitteet.

Git-repositorio tallentaa tiedostojen tilannekuvat ja niitä yhdistävän historian objektien verkkona. Objekti voi olla blob, puu, kommitti tai tunniste. Blobit sisältävät yksittäisten tiedostojen sisällön. Puut yhdistävät nimiä blobeihin tai muihin puihin ja muodostavat näin hakemistorakenteen. Kommitit osoittavat juuripuuhun ja nollaan tai useampaan vanhempana toimivaan kommittiin muodostaen repositorion historian.

Objektit tunnistetaan niiden tyypistä ja sisällöstä lasketulla tiivisteellä. Objektit ovat myös muuttumattomia: muuttuneen tiedoston tallentaminen luo uuden blobin, kun taas muuttumattomat tiedostot ja hakemistot voivat käyttää olemassa olevia objekteja uudelleen.

Haarat ja tunnisteet ovat kommitteihin osoittavia viitteitä eli ”refejä”. Kommitointi haaraan luo uuden kommitin ja päivittää haaran viitteen osoittamaan siihen.

Haara refs/heads/main osoittaa sitoutumisen C2, jonka vanhempi on C1. C1 osoittaa juuripuuhun T1, jossa parser.py viittaa blobiin B1. C2 osoittaa juuripuuhun T2, jossa parser.py viittaa blobiin B2. Molemmissa juuripuissa docs/ viittaa samaan puuhun T3. Sen README.md-merkintä osoittaa blobiin B3 ja usage.md blobiin B4.

Git-objektit viittaavat toisiinsa tunnuksilla: sitoutumiset puihin ja puut toisiin puihin ja blobeihin. Haara refs/heads/main osoittaa sitoutumiseen C2, jonka vanhempi on C1. C1 osoittaa juuripuuhun T1, jossa parser.py viittaa blobiin B1. C2 osoittaa juuripuuhun T2, jossa parser.py viittaa blobiin B2. Molemmissa juuripuissa docs/ viittaa samaan puuhun T3. Sen README.md-merkintä osoittaa blobiin B3 ja usage.md blobiin B4.

Git tallentaa objektit joko ”irrallisina” tai ”pakattuina”. Irralliset objektit tallennetaan erillisiin tiedostoihin, jotka tunnistetaan objektitunnuksella. Pakatut objektit tallennetaan yhdessä pakettitiedostoon, jolloin samankaltaiset objektit voidaan tallentaa toistensa erotuksina eli deltoina.

Tiedoston parser.py kaksi versiota näkyvät hakemistossa $GIT_DIR/objects. Irrallisina objekteina blob A sisältää funktion parse() ja blob B sekä funktion parse() että funktion parse_file(). Pakettitiedosto tallentaa A:n kokonaan ja esittää B:n ohjeina, jotka kopioivat koko A:n ja lisäävät loppuun funktion parse_file(). Mukana oleva *.idx-tiedosto paikantaa molemmat blobit pakettitiedostosta objektitunnuksen perusteella.

Git voi tallentaa blobit erillisinä tiedostoina tai pakata ne yhteen esittäen yhden blobin erotuksena toisesta.

Gitissä objekti on saavutettavissa sitoutumisesta, jos Git löytää sen seuraamalla linkkejä kyseisestä sitoutumisesta sen vanhempiin, puihin ja blobeihin. Haun aikana asiakas kertoo palvelimelle, mitkä sitoutumiset se haluaa ja mitkä sillä jo on. Palvelin etsii halutuista sitoutumista saavutettavat objektit, jättää pois asiakkaalla jo oleviksi tietämänsä objektit ja lähettää loput pakettitiedostona samassa muodossa, jota Git käyttää levyllä. Täysi kloonaus alkaa ilman objekteja, joten se tarvitsee kaikki kloonattavasta historiasta saavutettavat objektit.

Lähetys siirtää objekteja vastakkaiseen suuntaan ja pyytää palvelinta päivittämään yhden tai useamman viitteen. Asiakas käyttää palvelimen ilmoittamia viitteitä välttääkseen palvelimella jo olevien objektien lähettämisen. Lähetettävä paketti voi siksi riippua olemassa olevista objekteista: pelkän paketin vastaanottaminen ei riitä uuden historian muodostamiseen.

Git-repositorion replikointi tarkoittaa sekä objektien että viitteiden pitämistä saatavilla useilla palvelimilla. Ennen kuin replika voi tarjota viitteen uuden arvon, sen on pystyttävä toimittamaan tästä arvosta saavutettavat objektit. Palvelun on myös koordinoitava kilpailevia viitepäivityksiä eli lähetyksiä, jotka yrittävät siirtää saman haaran samasta vanhasta kärjestä eri uusiin sitoutumisiin. Järjestelmät, jotka asettavat kaikki repositorion kirjoitukset yhteen järjestykseen, voivat pakottaa toisistaan riippumattomien haarojen lähetykset odottamaan toisiaan.

Hajautettujen Git-palvelujen nykyiset toteutustavat

Pandoa suunnitellessamme arvioimme perinteisiä tapoja skaalata Git-pohjaista versionhallintaa. Toinen koordinoi repositorion replikoiden viitepäivityksiä kolmivaiheisella sitoutumisella (3PC, protokolla sitoutumisen vahvistamiseen useissa solmuissa). Toinen järjestää päivitykset blob-tallennustilassa olevan jaetun ennakkokirjauslokin avulla (WAL, loki, johon muutokset kirjataan ennen niiden soveltamista).

Kolmivaiheinen sitoutuminen (3PC)

Mallintamassamme kolmivaiheisen sitoutumisen ratkaisussa Git-palvelu pitää repositorion täydellisen kopion useissa replikoissa. Kun mikä tahansa palvelin vastaanottaa lähetyksen, saapuva pakettitiedosto kopioidaan ja lähetetään kaikille replikoille rinnakkain. Lähetyksen julkaiseminen edellyttää, että enemmistö replikoista hyväksyy viitepäivityksen. Tätä hallinnoiva palvelin toimii koordinaattorina. Prosessi vaatii useita viestintäkierroksia koordinaattorin ja kunkin muun replikan välillä.

Hyväksyäkseen viitepäivityksen kukin replika lukitsee oman viitekopionsa ja tarkistaa, että se osoittaa yhä asiakkaan odottamaan sitoutumiseen. Koordinaattori lähettää sitten esisitoutumisviestin päivityksen hyväksyneille replikoille. Kun enemmistö kuittaa esisitoutumisviestin, koordinaattori käskee niitä suorittamaan päivityksen. Tämän jälkeen mikä tahansa ajan tasalla oleva replika voi ilmoittaa haaran uuden kärjen paikallisesta repositoriokopiostaan.

Täydellisten replikoiden ylläpito mahdollistaa lukujen palvelemisen paikallisesti ja takaa asiakkaille konsistentin näkymän kaikkiin viitteisiin valitusta replikasta riippumatta. Tämän seurauksena viitteet päivitetään yksi kerrallaan, ja jokainen lähetys vaatii useita edestakaisia viestintäkierroksia viitepäivityksen koordinoimiseksi replikoiden kesken.

Enemmistön odottaminen tekee replikoiden levysuorituskyvystä ja viestintäviiveestä osan lähetyksen kriittistä polkua. Kirjoitusmäärän kasvaessa replikoiden on pysyttävä sekä saapuvien pakettien että lukuliikenteen tahdissa.

Ennakkokirjausloki (WAL)

Mallintamassamme WAL-pohjaisessa ratkaisussa Git-palvelu käyttää blob-tallennustilan jaettuja kokoonpanotietoja koko repositorion päivitysten järjestämiseen. Kun palvelin vastaanottaa lähetyksen, se lataa saapuvan pakettitiedoston blob-tallennustilaan ja valmistelee viitepäivityksen paikallisessa repositoriokopiossaan. Julkaistakseen lähetyksen se lisää blob-tallennustilan jaettuihin kokoonpanotietoihin merkinnän, joka kirjaa viitepäivityksen ja osoittaa pakettitiedostoon. Git-palvelin päivittää sitten kokoonpanotiedot vertaa ja vaihda -operaatiolla. Operaatio joko korvaa kokoonpanotiedot atomisesti tai hylkää muutoksen. Jos toinen kirjoittaja on päivittänyt niitä sillä välin, palvelin lukee väliin tulleet merkinnät, tarkistaa oman viitepäivityksensä olevan yhä kelvollinen ja yrittää uudelleen jo lataamallaan pakettitiedostolla.

Kirjoittajat voivat ladata pakettitiedostojaan rinnakkain, mutta myös toisistaan riippumattomiin haaroihin tehtävät lähetykset edellyttävät samojen kokoonpanotietojen päivittämistä. Onnistuneen vertaa ja vaihda -operaation edestakainen viive rajoittaa sitä, kuinka usein repositorio voi julkaista uudet kokoonpanotiedot. Pienen viiveen blob-tallennustila nopeuttaa tätä vaihetta. Eräkäsittely mahdollistaa usean viitteen päivittämisen yhdellä kokoonpanotietojen päivityksellä, mutta se edellyttää päivitysten jonottamista ja kasvattaa viivettä.

Blob-tallennustila voi vastaanottaa pakettitiedostoja rinnakkain, mutta jaettujen kokoonpanotietojen päivitykset kilpailevat silti keskenään. Pelkkä blob-tallennustilan kapasiteetin kasvattaminen ei poista tätä pullonkaulaa. Jokaisen replikan on edelleen luettava ja indeksoitava paketit blob-tallennustilasta ennen kuin se voi tarjota niitä paikallisesti. Jos saapuvia kirjoituksia on enemmän kuin tämä työ ehtii käsitellä, replikat jäävät jälkeen ja asiakkaat joutuvat odottamaan kauemmin juuri lähetettyjen sitoutumisten hakemista.

Pandon arkkitehtuuri

Tästä pääsemme Pandoon. Pando on uusi arkkitehtuuri Git-repositorioiden tarjoamiseen. Sen tavoitteena on skaalautua palvelemaan monia samanaikaisesti lähettäviä asiakkaita. Näin se toimii:

Rajoitteiden uudelleenarviointi

Ennen Pandon kehittämistä arvelimme voivamme täyttää vaatimuksemme luopumatta Gitistä. Meidän oli kuitenkin tingittävä joistakin asioista, joita useimmat Git-järjestelmät pitävät välttämättöminä:

  • Koko repositorion kattava johdonmukaisuus: Kaikkien viitteiden johdonmukainen tilannekuva tietyltä ajanhetkeltä edellyttää koordinointia koko repositorion laajuudella. Järjestelmässä, joka järjestää kaikki viitepäivitykset yhteiseen järjestykseen, toisistaan riippumattomiin haaroihin tehtävät lähetykset kilpailevat samasta koordinointipisteestä.

  • Asiakaskohtaiset pakettitiedostot: Jos kaksi asiakasta, joiden paikalliset historiat eroavat toisistaan, hakee saman haaran, palvelimen voi olla tarpeen luoda kummallekin oma paketti, jotta jo olemassa olevia objekteja ei lähetetä uudelleen. Näiden vastausten luominen kuluttaa suoritinaikaa ja levyn I/O-kapasiteettia, mikä vaikeuttaa skaalautumista suurelle lukijamäärälle.

Pando käyttää sen sijaan väljempiä johdonmukaisuusvaatimuksia (kausaalista johdonmukaisuutta) kirjoitusten skaalaamiseen ja hyödyntää pakettitiedostoja uudelleen lukujen skaalaamiseksi.

Kausaalinen johdonmukaisuus (CC)

Kun asiakas lähettää muutoksia haaraan, Pando tallentaa saapuvan pakettitiedoston muuttumattomana blobina blob-tallennustilaan. Aina kun haara siirtyy, Pando tallentaa metatietovarastoon viiteversion, joka sisältää uuden kärjen, sen tuoneen paketin ja kaikki aiemmat viiteversiot, joista paketti riippuu. Sekä blob-tallennustila että metatietovarasto skaalautuvat vaakasuunnassa.

Sitoutumisen tai viitteen hakeminen Pandosta edellyttää viiteversioiden eli pakettitiedostojen sarjan toistamista asiakkaalle. Näin palautetaan sen asiakkaan tila, joka loi haettavan viiteversion. Tämä tarjoaa heikomman johdonmukaisuudenkoko repositorion tasolla mutta takaa yksittäisten viitteiden päivitysten sarjallistettavuuden. Asiakkaiden välille syntyy ristiriita vain, jos ne lähettävät muutoksia samaan viitteeseen samanaikaisesti. Useita haaroja lukeva asiakas ei voi olettaa lukujen kuvaavan yhtä ja samaa ajanhetkeä koko repositoriossa.

Vasemmalla kolme peräkkäistä päähaaran pakettia sisältävät sitoutumiset A, B ja C; D ja E; sekä F. Oikealla päähaara ja aihehaara erkanevat kohdassa C. Päähaara etenee kohtaan G, kun taas aihehaara etenee kohtien D, E ja F kautta. Uusin aihehaaran paketti sisältää D:n, E:n ja F:n. Katkoviivareunus osoittaa, että D ja E sisältyvät myös aiempaan aihehaaran pakettiin. Sininen nuoli merkitsee uuden paketin riippuvuutta päähaaran kohdasta G. F:n vanhempi Gitissä on E.

Lähetys päähaaraan lisää inkrementaalisen paketin, joka sisältää yhden tai useamman sitoutumisen. Jokainen lähetys sivuhaaraan sisältää uudelleen aihehaaran aiemmat sitoutumiset, joten asiakas, jolla on ilmoitettu päähaaran versio, voi hakea aihehaaran yhtenä pakettina.

Tämä on eräs kausaalisen johdonmukaisuuden muoto. Viitteen hakemiseksi lukija näkee sen tuottaneen kirjoittajan historian. Lähetyksen aikana Pando ohjaa sitä, minkä yhteisen historian asiakas ja palvelin sopivat jakavansa. Näin asiakkaat tuottavat helpommin jaettavia pakettitiedostoja.

Siksi Pando ei tarjoa Git-operaatioiden aikana kaikkien viitteiden tilaa yhdeltä ajanhetkeltä eikä viitepäivitysten järjestystä kloonauksen tai haun sisällä. Oletetaan esimerkiksi, että haarat foo ja bar päivittyvät molemmat täyden kloonauksen neuvotteluvaiheessa. Neuvottelun aikana yksi asiakas voi nähdä haaran foo version 1 ja haaran bar version 2, kun taas toinen näkee haaran foo version 2 ja haaran bar version 1. Käytännössä käyttäjille ja agenteille viitepäivitysten globaali järjestys ei ole olennainen. Ne tarvitsevat vain yksittäisen viitteen päivitysjärjestyksen.

Lähestymistapojen vertailu

Tässä kolmen johdonmukaisuusmallin simulaatiossa asetamme 1 000 asiakasta valitsemaan kukin oman haaransa ja lähettämään siihen toistuvasti yksilöllisiä sitoutumisia. Mittaamme kokonaiskestoa ja viivettä lähetyksestä hakemiseen. Jälkimmäinen on työkuormien kannalta tärkeä mittari, sillä se kertoo edestakaisen viiveen, jonka käyttäjät ja agentit kohtaavat tehdessään yhteistyötä tai käyttäessään muita versionhallintaan tukeutuvia järjestelmiä. Simulaatio mallintaa laitteistoja perustasosta huipputasoon sekä virtuaalikoneiden että blob-tallennusjärjestelmien osalta. Tässä simulaatiossa olemme väljentäneet koko repositorion johdonmukaisuusvaatimusta kolmivaiheisen sitoutumisen kohdalla.

Simulating Git Server Implementations

Follow each writer through repeated pushes, and separately measure when an independent reader can check out each commit.

Three-phase commit

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Object-store WAL

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Pando

Ready
Simulated time
0 s
Mean push to fetch
—
Writers done
0 / 1,000

Each square represents one writer. All selected architectures run the same workload. Squares lighten as pushes are acknowledged and turn blue when a writer finishes. The chart shows writers finished over simulated time; independent readers can continue fetching afterward. Use arrow keys to select a writer, Home or End to jump, and Escape to clear.

0 / 10,000 pushes acknowledged · 0 fetched

Select a square to inspect that writer.

Writer progress through verified fetches

  • Three-phase commit
  • Object-store WAL
  • Pando
05001,00000 s
  • Waiting
  • Pushing
  • All pushes acknowledged
0 sLater

Synthetic teaching models, not production benchmarks. Mean push to fetch covers topic pushes, from the first attempt through retries until an independent reader verifies that commit. It includes waiting for a reader slot and excludes builds and tests. With merges enabled, writer completion includes the required fetches and trunk merge.

Experiment settings

Preparing simulation…

Results

Play the comparison to see the recorded results.

Synthetic teaching models, not production benchmarks. Mean push to fetch covers topic pushes, from the first attempt through retries until an independent reader verifies that commit. It includes waiting for a reader slot and excludes builds and tests. With merges enabled, writer completion includes the required fetches and trunk merge.

Suorita simulaatio, joka vertaa Pandoa kahteen muuhun lähestymistapaan. Valitse infrastruktuuri perustasosta huippulaitteistoon, asiakkaiden määrä ja muut asetukset ja katso, miten ratkaisut vertautuvat toisiinsa.

Mallinnetun kolmivaiheisen sitoutumisjärjestelmän kirjoitusviive kasvaa kuormituksessa huomattavasti levyjen kapasiteetin täyttyessä. Ennakkokirjauslokiin perustuvissa järjestelmissä taas lukuviive kasvaa samasta syystä merkittävästi, kun palvelimet eivät ehdi lukea lokia riittävän nopeasti. Sekä monorepositoriomme käytännön testeissä että tässä simulaatiossa Pando tukee useita tuhansia samanaikaisesti lähettäviä asiakkaita ilman, että suorituskyky heikkenee kuormituksessa.

Käsitellessään lähetystä Pando validoi saapuvan pakettitiedoston samalla kun suoratoistaa sen blob-tallennustilaan purkamatta sitä paikalliseen repositorioon. Kun asiakas aloittaa haun, Pando valitsee lukijan tarvitsemat tallennetut paketit, ja lukija lataa ne. Yhdenkään palvelimen ei tarvitse soveltaa pakettitiedostoja paikalliseen repositorioon tai tehdä raskaita purku- ja pakkausoperaatioita. Koska palvelimet hoitavat pääasiassa neuvottelun ja pakettitiedostojen valinnan, Pando-palvelimet voivat toimia tavanomaisella laitteistolla.

Näin Pando voi skaalautua asiakkaiden, asiakkaiden ja Pandon välisen verkon sekä blob-tallennuspalvelun kapasiteettirajoihin asti. Kun kapasiteettia on riittävästi, toisistaan riippumattomissa haaroissa työskentelevät asiakkaat voivat kukin siirtää paketteja oman yhteytensä enimmäisnopeudella. Voimme palvella useampia asiakkaita tällä nopeudella lisäämällä Pando-palvelimia ja skaalaamalla metatietovarastoa ja blob-tallennustilaa niiden rinnalla.

Pushing and Fetching a Branch in Pando

Pando stores the writer’s packfile in blob storage and records the ref version in metadata service. On fetch, Pando selects the packs the reader needs, and Express serves them.

Stream the push

  • Packfile bytes
  • Metadata
  • Request / acknowledgment
  • Packfile URIs

Agentti muokkaa tiedostoja, luo sitoutuminen paikallisesti ja suorittaa komennon git push, joka luo muutoksista pakettitiedoston haaran päivittämiseksi. Pando vastaanottaa paketin ja suoratoistaa sen blob-tallennustilaan. Validoituaan saapuvan lähetyksen yhdellä dekoodauskierroksella Pando käyttää usean avaimen transaktiota viiteversion tallentamiseen metatietovarastoon ja viiteosoittimen atomiseen päivittämiseen. Näin Pando voi tarjota johdonmukaisuustakuun, jossa ”omat kirjoitukset näkyvät omissa luennoissa”. Koko kirjoitusoperaatio vaatii O(1)O(1) metatietojen luku- ja kirjoitusoperaatiota.

Kun toinen asiakas hakee haaran, Pando valitsee tallennetut paketit asiakkaalla jo olevan historian perusteella. Tämä operaatio vaatii O(log⁡Δ)O(\log \Delta) metatietojen lukuoperaatiota. Tässä Δ\Delta on lyhin viiteversioina mitattu etäisyys asiakkaan nykyisen ja haluaman tilan välillä. Palvelin palauttaa pakettitiedostojen URI-osoitteet, ja asiakas lataa tiedostot Express-palvelun kautta. Express tallentaa pakettitiedostot alueellisiin välimuisteihin.

Tämä ratkaisu perustuu Pandon arkkitehtuurin kolmeen keskeiseen palveluun: lähetyksiin, hakuihin ja tiivistämiseen.

Lähetysten skaalaaminen

Kun asiakas lähettää muutoksia, perinteinen Git-palvelin toimii kuin pokerinpelaaja, joka näyttää kaikki korttinsa: se paljastaa asiakkaalle jokaisen haaransa. Asiakas kokoaa sitten sitoutumiset, puut ja blobit pakettitiedostoksi, josta jätetään pois objektit, joiden se tietää jo olevan palvelimella.

Useampien viitteiden ilmoittaminen voi pienentää lähetystä. Se voi myös vaikeuttaa paketin uudelleenkäyttöä, koska toiselta asiakkaalta saattaa puuttua kirjoittajan pois jättämiä objekteja.

Pando toimii toisin. Kaikkien korttien näyttämisen sijaan se ilmoittaa asiakkaalle vain valikoidut haarat. Tähän on kaksi syytä:

  1. Johdonmukaisen näkymän tarjoaminen jokaiseen viitteeseen on kallista. Kun haaroja on miljoonia, jo pelkkä viiteilmoitus voi ylittää 100 MiB. Sen tuottamiseksi jokaisen palvelimen on joko ylläpidettävä ajantasaista viitekartoitusta, mikä aiheuttaa huomattavaa koordinointikuormaa, tai tehtävä tietokantakysely, jonka kustannus kasvaa viitteiden määrän mukana.

  2. Kun asiakkaalle annetaan vain osa viitteistä, sen luoma paketti riippuu ainoastaan siitä, minkä palvelin nimenomaisesti sallii asiakkaan jättää pois. Riippuvuuksien seurannan ansiosta Pando voi käyttää asiakkaan yhdessä lähetyksessä luomaa pakettitiedostoa uudelleen vastauksena myöhempään hakuun.

Mitä enemmän viitteitä Git-palvelin ilmoittaa, sitä useampien lähteiden perusteella lähettävät asiakkaat voivat jättää objekteja pois ja tuottaa pienempiä paketteja. Näiden pakettitiedostojen uudelleenkäyttö edellyttää kuitenkin, että palvelin pystyy varmistamaan hakevilla asiakkailla olevan kaikki riippuvuudet. Muuten pakettitiedostosta voi puuttua asiakkaan tarvitsemia objekteja.

Jos taas Git-palvelin ei ilmoita yhtään viitettä, asiakas luo pakettitiedoston, joka sisältää repositorion koko historian. Mikä tahansa toinen asiakas voi käyttää tätä pakettitiedostoa, mutta hinta on kova: minkä tahansa haaran hakeminen vastaa käytännössä täyttä kloonausta.

Käyrä kuvaa ilmoitettujen viitteiden vaikutusta pakettitiedoston kokoon: ilman viitteitä paketti sisältää koko historian, pelkän päähaaran ilmoittaminen pienentää sitä, ja kaikkien viitteiden ilmoittaminen rajaa sen uusiin objekteihin.

Useampien viitteiden ilmoittaminen pienentää pakettitiedostoja. Suurin osa koon pienenemisestä voidaan saavuttaa ilmoittamalla vain yksi viite.

Oletusarvoisesti Pando ilmoittaa uuden ominaisuushaaran lähettävälle asiakkaalle pohjaksi vain nimetyn päähaaran. Näin ilmoituksen koko pysyy samana repositorion haaramäärän kasvaessa, mutta ratkaisu vaatii kompromisseja. Kun kehittäjä lähettää muutoksia samaan haaraan toistuvasti tai rakentaa yhden ominaisuushaaran toisen päälle, asiakkaan on lähetettävä kaikki päähaaran ulkopuolinen sisältö uudelleen.

Tämä kasvattaa peräkkäisten haaralähetysten kokoa, tuo niihin mahdollisesti tarpeettomia objekteja ja kuluttaa enemmän asiakkaan verkkokaistaa. Monorepositoriossamme näin tuotetun pakettitiedoston mediaanikoko oli alle 20 KiB ja 99. persentiili alle 3 MiB. Meille tämä oli järkevä kompromissi, sillä lukija, jolla on jo ilmoitettu päähaaran historia, voi hakea haaran yhdellä pakettitiedostolla.

Valittuaan asiakkaalle ilmoitettavat viitteet Pando hyväksyy lähetyksen ja päivittää metatietovarastonsa. Pando jakaa metatietopäivityksen synkroniseen ja asynkroniseen osaan. Synkroninen metatietopäivitys varmistaa, että asiakkaat voivat heti hakea juuri päivitetyn sitoutumisen. Se kirjoittaa uuden viiteversion ja päivittää viiteosoittimen osoittamaan siihen. Versioon tallennetaan uusi kärki, pakettitiedoston neuvottelussa käytetyt riippuvuudet ja linkki lähetettyyn pakettitiedostoon.

Samassa transaktiossa kirjataan myös asynkroniset tehtävät, kuten tiivistämisen ajastaminen. Erittäin suurissa lähetyksissä vain osa sitoutumisista kirjoitetaan synkronisesti. Näin metatietovarastoon tarvitaan vain vakiomäärä lukuja ja kirjoituksia lähetyksen koosta riippumatta.

Olennaista on, että Pando-palvelimet voivat vastaanottaa toisistaan riippumattomiin viitteisiin kohdistuvia lähetyksiä itsenäisesti. Ainoa kilpailun kohteena oleva avain on viiteosoitin, jonka suojaamme atomisella vertaa ja vaihda -tyyppisellä operaatiolla. Voimme kasvattaa kirjoituksen suoritustehoa lisäämällä Pando-palvelimia, metatietovaraston skaalausyksiköitä tai blob-tallennustiloja.

Haut ja kloonaukset verkon täydellä nopeudella

Kun asiakas tekee haun, se antaa palvelimelle kaksi sitoutumistunnusten joukkoa, jotka protokollassa tunnetaan nimillä have ja want. Perinteinen Git-palvelin laskee joukkoerotuksen want-tietojen ja have-tietojen kautta saavutettavien objektien välillä, pakkaa erotukseen kuuluvat objektit ja lähettää tuloksen asiakkaalle. Vaikka avoimen lähdekoodin Git-palvelimella on useita paikallisia indeksejä tämän operaation nopeuttamiseen, pakettitiedostojen laskenta voi olla raskasta, eikä niitä yleensä ole helppo hyödyntää välimuistissa.

Pando sen sijaan etsii asiakkaan have- ja want-tietoja vastaavat sitoutumiset lähetysten yhteydessä tallennetuista kartoituksista ja selvittää viiteversiot, jotka sisältävät ne. Jokainen näistä viiteversioista linkittyy Pandon aiemmin vastaanottamaan pakettitiedostoon. Palvelin selvittää tämän avulla asiakkaan tarpeet ja valitsee pakettitiedostot, jotka kattavat asiakkaan tarvitsemat objektit.

Planning fetches in Pando

Pando compares what a client has with what it wants, then selects the stored packfiles needed—including any missing branch dependencies.

Already heldFetchMissing branch dependency

Fetch 27 trunk packs.

Select a branch to include its trunk dependencies.

Pando muuntaa Git-protokollan have- ja want-tiedot viiteversioiden sarjaksi. Sivuhaaran pyytäminen edellyttää myös päähaaran historian hakemista haaran riippuvuuksiin asti.

Git-protokolla sallii vain yhden pakettitiedoston lähettämisen kloonauksen tai haun HTTP-vastauksessa. Git-protokollan vähälle huomiolle jäänyt ominaisuus packfile-uri antaa kuitenkin palvelimen palauttaa linkkejä lisäpakettien lataamiseen erikseen. Pando käyttää yksinomaan tätä tapaa ja lähettää itse vastauksessa tyhjän pakettitiedoston. Tämän ominaisuuden tukemiseksi OpenAI toimitti useita packfile-uri-parannuksia alkuperäiseen Git-projektiin.

OpenAI:n järjestelmät toimivat monilla maantieteellisillä alueilla, joten ylläpidämme kullakin alueella Pando-klustereita paikallisine välimuisteineen. Pakettien toimituspalvelu Express toimii blob-tallennustilamme välimuistina, ja erillinen palvelu toimii metatietovaraston välimuistina. Näiden välimuistien ansiosta Pando voi vastata sitoutumistunnukseen kohdistuviin pyyntöihin tai erityiseen viitteen lukuun kokonaan kyseisen klusterin välimuistin perusteella. Reititämme pakettitiedostopyynnöt Express-palvelimille johdonmukaisella hajautuksella. Välimuistin osumaprosentti on yli 99 %.

Tämä välimuistijärjestelmä tarjoaa erittäin suuren suoritustehon, joka pystyy käyttämään asiakkaiden ja Pandon välisen verkkokapasiteetin kokonaan. Olemme varmistaneet, että näiden pakettitiedostojen URI-osoitteiden ja paikallisten välimuistien avulla kloonaukset ja haut käyttävät 10 Gbit/s:n verkkoyhteydet täysimääräisesti jo pilvipalveluntarjoajien tavallisilla virtuaalikoneilla.

Tiivistäminen ja ensimmäisen tavun viive

Useimmissa Git-palvelimissa uudelleenpakkaus ja roskienkeruu ovat välttämättömiä kasvavan repositorion suorituskyvyn ylläpitämiseksi. Molemmat vapauttavat tilaa, mutta vaativat paljon laskentaa ja I/O-kapasiteettia.

OpenAI:n monorepositorion kaltaisessa nopeasti muuttuvassa repositoriossa ei ole käytännöllistä lähettää erillistä pakettitiedoston URI-osoitetta jokaiselle viime haun jälkeen tehdylle lähetykselle. Asiakkaan pitäisi ladata päivittäin kymmeniätuhansia pakettitiedostoja pitääkseen päähaaransa ajan tasalla.

Pando sen sijaan yhdistää paketteja taustalla vähentääkseen tätä lisäkuormaa. Ratkaisu muistuttaa lokirakenteisten yhdistämispuiden eli LSM-puiden tiivistämistä. Jokainen lähetys tuottaa pakettitiedoston, jota Pando kutsuu ”L0”-paketiksi. Se on pienin datayksikkö, jonka Pando voi siirtää. Ajan mittaan taustaprosessit kokoavat näistä pakettitiedostoista viiteversioiden sarjoja kattavia koosteita, joiden koko kasvaa geometrisesti L0-tasolta alkaen. Nykyisin monorepositoriomme käyttää pakettitiedostokoosteita L4-tasolle asti.

Näillä koosteilla on kaksi tehtävää. Kun kooste on riittävän täysi, tiivistysprosessi ottaa sen käsiteltäväkseen ja tuottaa yhden pakettitiedoston. Tämä parantaa pakkaussuhdetta järjestämällä pakettitiedoston objektit uudelleen. Samalla kooste parantaa hakuneuvottelun suorituskykyä toimimalla viiteversioiden hyppylistana. Käymällä kaikkien tasojen indeksejä läpi samanaikaisesti Pando voi valita asiakkaalle lähetettävät paketit logaritmisessa ajassa. Nämä pakettitiedostokoosteet tehostavat haun suunnittelua riippumatta siitä, onko ne pakattu uudelleen. Näin Pandon suoritusteho- ja viivevaatimukset kevenevät.

Compaction in Pando

Small packfiles are grouped into larger covers across levels, improving compression and speeding up fetches.

Compaction in progressPublished cover

Tiivistäminen yhdistää monien viiteversioiden pakettitiedostoja taustalla, mikä tehostaa hakuja ja vähentää tarvittavien tiedostojen määrää.

Toisin kuin monissa Git-palvelimissa, pakettitiedostot säilytetään jokaisella tasolla eikä niitä poisteta tai siivota roskienkeruussa. Kaikkien tasojen paketteja käytetään jatkuvasti asiakkaiden palvelemiseen haussa annettujen have- ja want-tietojen perusteella. Kun asiakas käyttää Pandoa rajapintana ja lukee mielivaltaisen objektin pakettitiedostosta, L0-paketista tarvitsee yleensä lukea vähemmän dataa kuin L4-paketista, koska objekti on pienemmällä todennäköisyydellä pakattu.

Pandon tiivistäminen vähentää merkittävästi asiakkaille siirrettävän datan kokonaismäärää. Se myös mahdollistaa pakettien suunnittelun skaalautumisen alilineaarisesti suhteessa siihen, kuinka paljon asiakas on jäljessä. Tämä on erityisen tärkeää suurille ja nopeasti muuttuville repositorioille, joiden odotamme muodostuvan ohjelmistokehityksen uudeksi normaaliksi.

Pandon rakentaminen

Rakensimme Pandon Codexin avulla ja etenimme aloituksesta tuotantoon vain 10 viikossa. Pandon ytimen suunnitteli yksi kehittäjä, toteutuksesta vastasivat agenttitiimit ja käyttöönotosta pieni joukko kehittäjiä. Pando alkoi palvella tuotantoliikennettä tämän vuoden huhtikuussa. Se on osa OpenAI:n laajempaa versionhallintatyökalujen kokonaisuutta.

Varmensimme Pandon suunnitteluratkaisuja monin eri menetelmin. Sovelsimme periaatteitamme turvallisemman ohjelmistoperustan rakentamiseen⁠. Koska aloitimme puhtaalta pöydältä, päätimme toteuttaa Pandon Rustilla ilman vanhoja riippuvuuksia. Kirjoitimme yhteensopivuustestisarjan, jonka avulla agentit pystyivät testaamaan muutoksiaan Gitin vakiotoimintaa vasten. Kehitimme myös deterministisen simulaatiotestauksen arviointikehyksiä järjestelmän invarianttien ja ominaisuuksien tarkistamiseen. Niiden avulla löysimme ja lievensimme vaikeasti havaittavia kilpailutilanteita sekä neuvottelun ja pakettien suunnittelun regressioita.

Monet mallit osallistuivat järjestelmän kehittämiseen. Kun uusia malleja tuli saataville, käytimme niitä Pandon suorituskyvyn ja luotettavuuden parantamiseen. GPT‑6 Astraa käyttävät agentit kirjoittivat Lean- ja TLA+-kuvaukset formalisoidakseen ”Pandon teorian”. Sen avulla löysimme ja korjasimme toteutuksen virheitä sekä todistimme järjestelmän ominaisuuksia. Useat keskeytymättömät istunnot kestivät satoja tunteja ja etsivät sekä korjasivat Pandon reunatapauksia. Lisäksi agentit testaavat Gitin ja Pandon turvallisuutta hyökkääjän näkökulmasta ympäri vuorokauden Daybreak-kykyisillä malleilla.

Pandon käyttöönotto

Otimme Pandon aluksi käyttöön välityspalvelimena, joka ohjasi luvut ja kirjoitukset olemassa olevaan versionhallintajärjestelmäämme. Näin pystyimme pitämään Pandon ja aiemman järjestelmän synkronoituina ja siirtämään liikenteen turvallisesti Pandoon ilman käyttökatkoja.

Osana välimuistiratkaisuaan Pando voi myös poistaa päällekkäisiä pyyntöjä ja yhdistää niitä ennen välityspalvelintoimintaa. Näin nykyiset työkalumme pysyivät toimintakunnossa, kun siirsimme järjestelmiä Pandoon yksi kerrallaan. Kun siirsimme lisää työkuormia Pandoon, niiden lähetykset täyttivät Pandon välimuistia ja paransivat aiemman taustajärjestelmämme luotettavuutta.

Optimoidaksemme Pandon suorituskyvyn aloimme toimittaa julkista Git-jakeluamme kehittäjien koneille ja ChatGPT‑työpöytäsovelluksen mukana. Siirsimme asiakkaat Pandoon vaiheittain Gitin komentoriviliittymän ympärille rakennetun sisäisen kääreohjelman avulla. Loimme myös monia muita työkaluja muutospyyntöjen käsittelyyn ja koodikatselmointiin sekä rajapintoja automaatioita varten. Git-liikenteen ohella siirsimme satoja integraatioita, jotka olivat riippuvaisia vanhoista rajapinnoista, webhookeista ja repositoriolatauksista.

Myös Codex auttoi kehittäjiä ja tiimejä siirtymässä. Loimme taitoja nykyisten työkopioiden valmisteluun ja agenttien opastamiseen uuden järjestelmän käytössä. Näin kehittäjät saattoivat vain pyytää Codexia siirtämään kehitysympäristönsä ja palvelunsa.

Siirtyminen Pandoon paransi yhdistämisten luotettavuutta ja lyhensi lähetysviiveen mediaania lähes 80 %.

Pando pystyy toimittamaan petatavun Git-dataa päivässä vain muutamalla suoritinytimellä. Pando on toimittanut yli 57 teratavua Git-paketteja yhden tunnin aikana, ja yli 99 % tavuista tuli paikallisesta levyvälimuistista.

Pakettien uudelleenkäytön ansiosta monet asiakkaat voivat ladata saman repositoriohistorian niin, että palvelevat solmut tarvitsevat vain vähän laskentaa. Tämä esimerkki koskee yhtä repositoriota, mutta Pando on suunniteltu tukemaan paljon useampia. Kysynnän kasvaessa voimme skaalata datan toimitusta ja Git-neuvottelua toisistaan riippumatta.

Parannusten palauttaminen Git-projektiin

Pandon rakentaminen Git-protokollan ja -asiakasohjelman varaan auttoi meitä löytämään virheitä ja mahdollisuuksia parantaa Gitin omaa suorituskykyä.

Pando esimerkiksi toimittaa uudelleenkäytettäviä paketteja suoraan asiakkaille. Siksi niiden lataamisesta ja indeksoinnista tuli keskeinen osa järjestelmän nopeuden ja luotettavuuden varmistamista. Työssä nousi esiin reunatapauksia, jotka liittyivät rinnakkaisiin latauksiin, keskeytyneiden siirtojen jälkien siivoukseen ja jo valmistuneiden latausten jatkamiseen. Korjasimme nämä suorituspolut, lisäsimme tarkistuksia olemassa olevan paketin hyväksymiseen haussa ja toimitimme parannukset alkuperäiseen Git-projektiin.

Meidän piti myös nähdä, mihin aika ja verkkokaista kuluivat. Lisäsimme siksi packfile-uri-latausten jäljityksen ja pakettien luonnin tavulaskurit. Näin oli helpompi selvittää, kuluiko hitaan haun aika pakettien luomiseen vai siirtämiseen.

OpenAI:n Git-versiossa⁠(avautuu uudessa ikkunassa) asiakas voi ladata ja indeksoida toisistaan riippumattomia paketteja rinnakkain. Lisäsimme ”eksplisiittisten have-tietojen” käsitteen. Sen avulla palvelin voi ilmoittaa haaran nykyisen kärjen erillään historiasta, jonka lähettävä asiakas saa jättää paketistaan pois. Pandossa tämä antaa asiakkaiden tarkistaa valitsimella --force-with-lease, ettei ominaisuushaara ole siirtynyt, ja rakentaa paketin pelkän päähaaran pohjalta. Kuka tahansa, jolla on kyseinen päähaaran historia, voi sitten hakea haaran samalla paketilla.

Useat näistä parannuksista ovat jo mukana alkuperäisessä Git-projektissa ja monet muut julkisessa repositoriossamme. Jatkamme yhteistyötä Git-yhteisön kanssa, jotta nämä parannukset hyödyttäisivät muitakin kuin Pandon käyttäjiä. Voit seurata työtä julkisessa korjausseurannassamme⁠(avautuu uudessa ikkunassa).

Mitä seuraavaksi

Pando kyseenalaistaa totutut käsitykset Git-repositorioiden skaalaamisesta. Sen ansiosta voimme skaalata monorepositoriotamme muuttamatta kehittäjiemme ja agenttiemme nykyisiä Git-työnkulkuja. Pando on mahdollistanut monorepositoriossamme entistä laajemman rinnakkaisuuden, parantanut yhdistämisten luotettavuutta ja nopeuttanut koodimuutosten julkaisemista. Monorepositoriomme lisäksi tutkimme Pandolle muitakin käyttökohteita OpenAI:lla, kuten työkuormia, joissa suuri määrä agentteja tekee yhteistyötä jaetussa Git-repositoriossa.

Kun kehittäjät ja agentit tuottavat yhä enemmän ohjelmistoja, yhä useammat tiimit myös OpenAI:n ulkopuolella kohtaavat samat versionhallinnan rajat kuin me. Selvitämme parhaillaan tapoja jakaa Pandon mahdollistava teknologia käyttäjiemme kanssa.

Pando pohjautuu Git-repositorioiden käyttäjien ja ylläpitäjien kahden vuosikymmenen kokemukseen. Jatkamme Pandon kehittämistä ja teemme yhteistyötä avoimen lähdekoodin Git-yhteisön kanssa jakaaksemme parannukset, jotka hyödyttävät Git-käyttäjiä laajemminkin.

Tekijät

OpenAI