Git mērogošana uzņēmumā OpenAI
Veidojam pirmkoda kontroli aģentu darba mērogam, vienlaikus ieguldot Git ekosistēmā.
Pēdējā gada laikā mūsu monorepozitorija apjoms un tam izvirzītās prasības ir augušas pārsteidzošā tempā. Bija skaidrs, ka mums jāpārveido pirmkoda kontroles sistēma, lai tā spētu nodrošināt tādu vienlaicīga darba apjomu, kādu padara iespējamu Codex.
Mēs izveidojām Pando — jaunu aizmugursistēmu Git repozitorijiem —, nepārtraucot izstrādes darbu un nemainot to, kā mūsu komanda izmanto Git. Tagad Pando nodrošina visu izstrādi OpenAI monorepozitorijā. Pando ir veidots diviem ambicioziem mērķiem. Pirmais — horizontāli mērogojama rakstīšana, kas optimizēta vienlaicīgai izmaiņu nosūtīšanai uz daudziem zariem. Otrais — maksimāla lasīšanas caurlaidspēja, lai klienti varētu lejupielādēt datus pietiekami ātri un pilnībā izmantot pieejamo tīkla joslas platumu.
Šos mērķus sasniedzām, saglabājot saderību ar Git protokolu un klientu, tāpēc gan mūsu inženieri, gan aģenti varēja bez grūtībām iekļaut Pando savās esošajās darbplūsmās. Ražošanas vidē Pando samazināja nosūtīšanas aizkaves mediānu gandrīz pieckārt. Tagad tas piegādā gandrīz petabaitu Git datu dienā.
Šeit pastāstīsim, kāpēc veidojām jaunu pirmkoda kontroles sistēmu un kāpēc izvēlējāmies saglabāt saderību ar Git. Salīdzināsim savu sistēmu ar izplatītām Git mērogošanas pieejām un izskaidrosim, kāpēc tieši Pando spēj apmierināt OpenAI mērogojamības vajadzības. Apskatīsim arī turpmākos plānus un to, kā turpināsim dot ieguldījumu Git, lai atbalstītu darbu aģentu mērogā.
Codex ir mainījis izstrādes mērogu un tempu uzņēmumā OpenAI, ļaujot inženieriem paralēli paveikt daudz vairāk darba. Tas nozīmē vairāk zaru un nosūtīšanu, vairāk apvienošanu, kā arī vairāk izgūšanu un klonēšanu no izstrādes vidēm, pētniecības uzdevumiem un nepārtrauktās integrācijas (CI) sistēmām.
Šīs prasības savstarpēji pastiprinās. Vienam inženierim tagad vienlaikus ir vairākas CI gatavas izmaiņas, un katra nosūtīšana var likt vairākiem uzdevumiem izgūt vienu un to pašu fiksējumu.
Aptuveni pagājušā gada beigās mūsu monorepozitorija atbalsta sistēmām sāka kļūt grūti tikt līdzi. Izgūšana un nosūtīšana bija lēna, apvienošanas neizdevās, un uzticamība brīžiem nokritās zem 90 %. Vai bijām sasnieguši paša Git iespēju robežu vai arī robežu tam, kā apkalpojām savu monorepozitoriju? Git radās kopienā, kas pa e-pastu apmainījās ar kodola ielāpiem. Vairāk nekā divdesmit gadus izstrādātāji ir pielāgojuši savus rīkus darbam ar Git, mainoties programmatūras izstrādes veidiem. Kad sākām saskarties ar grūtībām savā monorepozitorijā, mums bija svarīgi turpināt balstīties uz šo darbu.
Mēs saskatījām iespēju saglabāt ierasto darbplūsmu, vienlaikus pārbūvējot aizmugursistēmu, lai tā paralēli apstrādātu nosūtīšanas uz dažādiem zariem un vienlaikus piegādātu vienu vēsturi daudziem lasītājiem. Izmantojot Git kā pirmkoda kontroles darbplūsmas pamatu, klienta uzlabojumi varēja noderēt arī ārpus OpenAI. Vēlējāmies šos uzlabojumus no savas Git kopijas(atveras jaunā logā) iesniegt pamatprojektā, daloties ar tiem plašākā kopienā.
Pirmkoda kontroles sistēmas mērogošanai ir divas būtiskas dimensijas: daudzi rakstītāji, kas nosūta izmaiņas uz dažādiem zariem, un daudzi lasītāji, kas izgūst vienu vēsturi. Pando optimizē abas.
Pirmkārt, Pando katra zara atjauninājumus koordinē neatkarīgi. Nesaistītu zaru atjaunināšana var notikt paralēli, un lasītājs, kas izgūst zaru, saņem attiecīgajai revīzijai nepieciešamo vēsturi. Kompromiss ir tāds, ka lasītājs, aplūkojot vairākus zarus, var redzēt to stāvokļus dažādos laika punktos.
Otrkārt, Pando atkārtoti izmanto pakotņu failus (Git formātu vairāku objektu kopīgai saspiešanai) dažādās izgūšanās, nevis ģenerē atsevišķu pakotnes failu katram klientam. Klients var lejupielādēt dažus objektus, kas tam jau ir, taču serveris var piegādāt tos pašus baitus daudziem klientiem ar nelielu skaitļošanas slodzi.
Šīs izvēles ļauj mērogot rakstīšanu dažādos zaros un apkalpot lasīšanu no kešatmiņas. Lai saprastu, kā tas viss darbojas kopā, vispirms apskatīsim, kā Git glabā un pārsūta vēsturi.
Git jāspēj sinhronizēt divas repozitorija daļas: objektus un atsauces.
Git repozitorijs glabā failu momentuzņēmumus un tos savienojošo vēsturi kā objektu grafu. Objekts var būt blobs, koks, fiksējums vai atzīme. Blobi glabā atsevišķu failu saturu, bet koki sasaista nosaukumus ar blobiem vai citiem kokiem, veidojot direktoriju struktūru. Fiksējumi norāda uz saknes koku un nulli vai vairākiem vecākfiksējumiem, veidojot repozitorija vēsturi.
Objektus identificē pēc to tipa un satura jaucējvērtības. Objekti ir arī nemaināmi: saglabājot mainītu failu, tiek izveidots jauns blobs, savukārt nemainīti faili un direktoriji var atkārtoti izmantot esošos objektus.
Zari un atzīmes ir atsauces jeb „refs”, kas norāda uz fiksējumiem. Fiksējot izmaiņas zarā, tiek izveidots jauns fiksējums un atjaunināta zara atsauce, lai tā uz to norādītu.
Git objekti atsaucas cits uz citu pēc ID: fiksējumi — uz kokiem, bet koki — uz citiem kokiem un blobiem. Zars refs/heads/main norāda uz fiksējumu C2, kura vecākfiksējums ir C1. C1 norāda uz saknes koku T1, kur parser.py atsaucas uz blobu B1. C2 norāda uz saknes koku T2, kur parser.py atsaucas uz blobu B2. Abos saknes kokos docs/ atsaucas uz vienu un to pašu koku — T3. Tā ieraksts README.md norāda uz blobu B3, bet usage.md — uz blobu B4.
Git glabā objektus vai nu „atsevišķi”, vai „sapakotus”. Atsevišķie objekti tiek glabāti individuālos failos, kurus identificē pēc objekta ID. Sapakotie objekti tiek glabāti kopā pakotnes failā, ļaujot līdzīgus objektus saglabāt kā atšķirības no citiem objektiem.
Git var glabāt blobus atsevišķos failos vai sapakot tos kopā, kodējot vienu blobu kā atšķirības no cita.
Git objekts ir sasniedzams no fiksējuma, ja Git var to atrast, sekojot saitēm no šī fiksējuma caur tā vecākfiksējumiem, kokiem un blobiem. Izgūšanas laikā klients paziņo serverim, kurus fiksējumus vēlas un kuri tam jau ir. Serveris atrod no vēlamajiem fiksējumiem sasniedzamos objektus, izslēdz tos, kas, kā tam zināms, klientam jau ir, un pārējos nosūta pakotnes failā tādā pašā formātā, kādu Git izmanto diskā. Pilna klonēšana sākas bez objektiem, tāpēc tai vajadzīgi visi objekti, kas sasniedzami no klonējamās vēstures.
Nosūtīšana pārsūta objektus pretējā virzienā, lūdzot serverim atjaunināt vienu vai vairākas atsauces. Klients izmanto servera norādīto atsauču kopu, lai nesūtītu objektus, kas serverim jau ir. Tādēļ nosūtāmā pakotne var būt atkarīga no esošiem objektiem: ar pakotnes saņemšanu vien nepietiek, lai atjaunotu jauno vēsturi.
Git repozitorija replicēšana nozīmē gan objektu, gan atsauču pieejamības uzturēšanu vairākos serveros. Pirms replika var nodrošināt atsauces jauno vērtību, tai jāspēj piegādāt no šīs vērtības sasniedzamos objektus. Pakalpojumam jākoordinē arī konkurējoši atsauču atjauninājumi, proti, nosūtīšanas, kas mēģina pārvietot vienu zaru no viena vecā gala uz dažādiem jauniem fiksējumiem. Sistēmas, kas visām rakstīšanām repozitorijā nosaka vienotu secību, var likt nosūtīšanām uz nesaistītiem zariem gaidīt citai uz citu.
Projektējot Pando, izvērtējām ierastās pieejas pirmkoda kontroles mērogošanai ar Git: vienu, kas koordinē atsauču atjauninājumus starp repozitorija replikām ar trīsfāžu apstiprināšanu (3PC — protokolu apstiprināšanas koordinēšanai vairākos mezglos), un otru, kas sakārto atjauninājumus ar kopīgu priekšrakstīšanas žurnālu (WAL — izmaiņu reģistru, kas tiek ierakstīts pirms izmaiņu piemērošanas) blobu krātuvē.
Mūsu modelētajā trīsfāžu apstiprināšanas risinājumā Git pakalpojums glabā pilnu repozitorija kopiju vairākās replikās. Kad kāds serveris saņem nosūtīšanu, ienākošais pakotnes fails tiek kopēts un paralēli nosūtīts visām replikām. Lai publicētu nosūtītās izmaiņas, atsauces atjauninājums jāpieņem vairākumam repliku. Serveris, kas to pārvalda, ir koordinators, un procesam nepieciešamas vairākas saziņas kārtas starp koordinatoru un katru pārējo repliku.
Lai pieņemtu atsauces atjauninājumu, katra replika bloķē savu atsauces kopiju un pārbauda, vai tā joprojām norāda uz klienta sagaidīto fiksējumu. Pēc tam koordinators replikām, kas atjauninājumu pieņēmušas, nosūta priekšapstiprināšanas ziņojumu. Kad vairākums apliecina priekšapstiprināšanas ziņojuma saņemšanu, koordinators liek tām veikt atjauninājumu. Pēc tam jebkura aktuāla replika var norādīt jauno zara galu no savas lokālās repozitorija kopijas.
Pilnu repliku uzturēšana ļauj apkalpot lasīšanu lokāli un garantē, ka klienti saņem konsekventu visu atsauču stāvokli neatkarīgi no izvēlētās replikas. Tādēļ atsauces tiek atjauninātas pa vienai, un katrai nosūtīšanai nepieciešami vairāki saziņas cikli, lai koordinētu atsauces atjauninājumu starp replikām.
Gaidot kvorumu, nosūtīšanas laiks kļūst atkarīgs no repliku disku veiktspējas un saziņas aizkaves. Pieaugot rakstīšanas apjomam, replikām jāspēj tikt galā gan ar ienākošajām pakotnēm, gan lasīšanas datplūsmu.
Mūsu modelētajā WAL risinājumā Git pakalpojums izmanto kopīgu deklarāciju blobu krātuvē, lai noteiktu atjauninājumu secību visā repozitorijā. Kad serveris saņem nosūtīšanu, tas augšupielādē ienākošo pakotnes failu blobu krātuvē un sagatavo atsauces atjauninājumu savā lokālajā repozitorija kopijā. Lai publicētu nosūtītās izmaiņas, tas pievieno blobu krātuvē glabātajai kopīgajai deklarācijai ierakstu, kas reģistrē atsauces atjauninājumu un norāda uz pakotnes failu. Pēc tam Git serveris atjaunina deklarāciju ar salīdzināšanas un apmaiņas operāciju. Tā atomāri aizstāj deklarāciju vai noraida izmaiņu. Ja pa to laiku deklarāciju atjauninājis cits rakstītājs, serveris nolasa starplaikā pievienotos ierakstus, pārbauda, vai tā atsauces atjauninājums joprojām ir derīgs, un mēģina vēlreiz, izmantojot jau augšupielādēto pakotnes failu.
Rakstītāji var augšupielādēt savus pakotņu failus paralēli, taču pat nosūtīšanām uz nesaistītiem zariem jāatjaunina viena un tā pati deklarācija. Sekmīgas salīdzināšanas un apmaiņas operācijas pilnā cikla laiks ierobežo to, cik bieži repozitorijs var publicēt jaunu deklarāciju. Blobu krātuve ar mazu aizkavi ļauj šo soli veikt ātri. Grupējot atjauninājumus, ar vienu deklarāciju var vienlaikus atjaunināt vairākas atsauces, taču atjauninājumi jāievieto rindā, palielinot aizkavi.
Blobu krātuve var saņemt pakotņu failus paralēli, taču kopīgās deklarācijas atjauninājumi joprojām savstarpēji konkurē. Ar blobu krātuves jaudas palielināšanu vien šo ierobežojumu nevar novērst. Katrai replikai joprojām jānolasa un jāindeksē pakotnes no blobu krātuves, pirms tā var tās piegādāt lokāli. Ja ienākošās rakstīšanas apsteidz šo darbu, replikas atpaliek un klientiem ilgāk jāgaida, lai izgūtu tikko nosūtītos fiksējumus.
Tas mūs noved pie Pando. Pando ir jauna Git repozitoriju apkalpošanas arhitektūra, kuras mērķis ir mērogoties līdz daudziem klientiem, kas vienlaikus nosūta izmaiņas. Lūk, kā tas darbojas:
Pirms Pando izstrādes mums bija nojauta, ka varam izpildīt savas prasības, neatsakoties no Git iespējām, taču bija jāatsakās no dažiem nosacījumiem, ko vairums Git sistēmu uzskata par obligātiem:
Konsekvence visā repozitorijā: Lai nodrošinātu visu atsauču konsekventu momentuzņēmumu vienā laika punktā, nepieciešama koordinācija visā repozitorijā. Sistēmā, kas visus atsauču atjauninājumus sakārto vienotā secībā, nosūtīšanas uz nesaistītiem zariem konkurē par vienu koordinācijas punktu.
Unikāli pakotņu faili katram klientam: Ja divi klienti ar atšķirīgu lokālo vēsturi izgūst vienu zaru, serverim var nākties ģenerēt atsevišķu pakotni katram, lai nenosūtītu objektus, kas tiem jau ir. Šo atbilžu veidošana patērē CPU un diska ievades/izvades resursus, apgrūtinot liela lasītāju skaita apkalpošanu.
Tā vietā Pando izmanto vājāku konsekvences modeli (cēlonisko konsekvenci), lai mērogotu rakstīšanu, un atkārtoti izmanto pakotņu failus, lai mērogotu lasīšanu.
Kad klients nosūta izmaiņas uz zaru, Pando saglabā ienākošo pakotnes failu kā nemaināmu blobu blobu krātuvē. Ikreiz, kad zars tiek pavirzīts uz priekšu, Pando metadatu krātuvē ieraksta atsauces versiju, kurā ietverts jaunais zara gals, pakotne, kas to piegādāja, un visas iepriekšējās atsauču versijas, no kurām pakotne ir atkarīga. Gan blobu krātuve, gan metadatu krātuve ir horizontāli mērogojamas.
Lai izgūtu fiksējumu vai atsauci no Pando, klientam secīgi jāsaņem atsauču versiju kopa (pakotņu faili), atjaunojot tā klienta stāvokli, kurš izveidoja izgūstamo atsauces versiju. Tas nodrošina vājāku konsekvenci visā repozitorijā, vienlaikus garantējot atsevišķu atsauču atjauninājumu serializējamību. Klienti konfliktē tikai tad, ja vienlaikus nosūta izmaiņas uz vienu atsauci. Klients, kas lasa vairākus zarus, nevar pieņemt, ka nolasītie dati atspoguļo vienu laika punktu visā repozitorijā.
Nosūtot izmaiņas uz galveno zaru, tiek pievienota inkrementāla pakotne ar vienu vai vairākiem fiksējumiem. Katrā nosūtīšanā uz sānu zaru tiek atkārtoti iekļauti šī zara iepriekšējie fiksējumi, lai klients ar servera norādīto galvenā zara versiju varētu izgūt sānu zaru vienā pakotnē.
Tas ir cēloniskās konsekvences veids. Lai izgūtu atsauci, lasītājs saņem tās rakstītāja vēsturi, kurš šo atsauci izveidojis. Nosūtīšanas laikā Pando kontrolē, kādu kopīgo vēsturi klients un serveris saskaņo, nodrošinot, ka klienti veido vieglāk koplietojamus pakotņu failus.
Tādēļ Pando Git operāciju laikā nenodrošina visu atsauču stāvokli vienā laika punktā vai vienotu atsauču atjauninājumu secību klonēšanas vai izgūšanas ietvaros. Piemēram, pieņemsim, ka pilnas klonēšanas saskaņošanas laikā tiek atjaunināti abi zari — foo un bar. Saskaņošanas laikā viens klients var redzēt foo 1. versiju un bar 2. versiju, savukārt cits — foo 2. versiju un bar 1. versiju. Praksē lietotājiem un aģentiem nav būtiska atsauču atjauninājumu globālā secība; tie paļaujas uz vienas atsauces atjauninājumu secību.
Šajā trīs konsekvences modeļu simulācijā konfigurējam 1000 klientus, lai katrs izvēlētos atsevišķu zaru un atkārtoti nosūtītu unikālus fiksējumus, mērot kopējo pagājušo laiku un aizkavi no nosūtīšanas līdz izgūšanai. Pēdējais ir svarīgs darba slodžu rādītājs, jo mēra pilna cikla laiku, kas lietotājiem un aģentiem nepieciešams sadarbībai vai citu uz versiju kontroli balstītu sistēmu izmantošanai. Simulācija modelē dažādus infrastruktūras līmeņus — no standarta līdz augstākās klases virtuālajām mašīnām un blobu krātuves sistēmām. Šajā simulācijā trīsfāžu apstiprināšanai esam mīkstinājuši prasību pēc konsekvences visā repozitorijā.
Simulating Git Server Implementations
Follow each writer through repeated pushes, and separately measure when an independent reader can check out each commit.
Palaidiet šo simulāciju, lai salīdzinātu Pando ar divām citām pieejām. Izvēlieties infrastruktūru no standarta līdz augstākās klases aparatūrai, klientu skaitu un citus iestatījumus, lai salīdzinātu rezultātus.
Modelētajā trīsfāžu apstiprināšanas sistēmā slodzes apstākļos ievērojami palielinās rakstīšanas aizkave, jo diski sasniedz caurlaidspējas robežu. Savukārt priekšrakstīšanas žurnāla sistēmās tā paša iemesla dēļ ievērojami palielinās lasīšanas aizkave — serveri nespēj pietiekami ātri lasīt žurnālu. Gan reālos testos mūsu monorepozitorijā, gan šajā simulācijā Pando atbalsta daudzus tūkstošus klientu, kas spēj vienlaikus nosūtīt izmaiņas, nepasliktinot veiktspēju slodzes apstākļos.
Apstrādājot nosūtīšanu, Pando validē ienākošo pakotnes failu, vienlaikus straumējot to uz blobu krātuvi un neizpakojot to lokālā repozitorijā. Kad klients sāk izgūšanu, Pando atlasa lasītājam nepieciešamās saglabātās pakotnes, un lasītājs tās lejupielādē. Nevienam serverim nav jāpiemēro pakotņu faili lokālam repozitorijam vai jāveic resursietilpīgas izpakošanas un pakošanas operācijas. Tā kā šie serveri galvenokārt veic saskaņošanu un pakotņu failu atlasi, Pando serveri var darboties uz standarta aparatūras.
Tas ļauj Pando mērogoties līdz klientu, tīkla starp klientiem un Pando, kā arī blobu krātuves pakalpojuma iespējām. Ja jauda ir pietiekama, katrs klients, kas strādā ar neatkarīgu zaru, var pārsūtīt pakotnes tik ātri, cik ļauj tā savienojums. Lai šādā ātrumā apkalpotu vairāk klientu, varam pievienot Pando serverus un līdztekus palielināt metadatu un blobu krātuvju jaudu.
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.
Aģents lokāli rediģē failus un izveido fiksējumu, pēc tam izpilda git push, kas no šīm izmaiņām izveido pakotnes failu zara atjaunināšanai. Pando saņem pakotni un straumē to uz blobu krātuvi. Pēc ienākošās nosūtīšanas validēšanas ar vienas caurlaides dekodēšanu Pando izmanto vairāku atslēgu transakciju, lai mūsu metadatu krātuvē ierakstītu atsauces versiju un atomāri atjauninātu atsauces rādītāju. Tas ļauj Pando nodrošināt konsekvenci pēc principa „lasīt paša ierakstīto”. Visai šai rakstīšanas operācijai nepieciešamas metadatu lasīšanas un rakstīšanas darbības.
Kad cits klients izgūst zaru, Pando atlasa saglabāto pakotņu kopu, ņemot vērā klientam jau pieejamo vēsturi. Šai operācijai nepieciešamas metadatu lasīšanas darbības, kur ir īsākais attālums atsauču versijās starp to, kas klientam ir, un to, ko klients vēlas. Serveris atgriež pakotņu failu URI, un klients tos lejupielādē, izmantojot Express pakalpojumu, kas glabā pakotņu failus reģionālās kešatmiņās.
Šis risinājums balstās uz trim Pando arhitektūras pamatpakalpojumiem: nosūtīšanu, izgūšanu un blīvēšanu.
Kad klients nosūta izmaiņas, parasts Git serveris līdzinās pokera spēlētājam, kas atklāj visas kārtis — tas parāda klientam visus savus zarus. Pēc tam klients apkopo fiksējumus, kokus un blobus, lai izveidotu pakotnes failu, kurā nav iekļauti objekti, kas, kā klientam zināms, serverim jau ir.
Norādot vairāk atsauču, var samazināt nosūtāmo datu apjomu. Taču tas var arī apgrūtināt pakotnes atkārtotu izmantošanu, jo citam klientam var trūkt rakstītāja izlaisto objektu.
Pando izmanto citu pieeju. Tā vietā, lai atklātu visas kārtis, tas klientam norāda tikai atlasītu zaru kopu. Tam ir divi iemesli:
Visu atsauču konsekventa attēlojuma nodrošināšana ir dārga. Ja ir miljoniem zaru, atsauču saraksts vien var pārsniegt 100 MiB. Lai to nodrošinātu, katram serverim jāuztur aktuāls atbilstību kartējums, kas rada ievērojamas koordinācijas papildizmaksas, vai jāveic datubāzes vaicājums, kura apjoms aug līdz ar atsauču skaitu.
Ja klientam norāda tikai daļu atsauču, tas ģenerē pakotni, kas atkarīga tikai no tā, ko serveris klientam skaidri atļāvis izlaist. Atkarību uzskaite ļauj Pando vienā nosūtīšanā klienta ģenerēto pakotnes failu izmantot atkārtoti, piegādājot to kā atbildi uz vēlāku izgūšanas pieprasījumu.
Jo vairāk atsauču Git serveris norāda, jo vairāk avotu nosūtošie klienti var izmantot objektu izslēgšanai, tā veidojot mazākas pakotnes. Tomēr, lai šos pakotņu failus izmantotu atkārtoti, serverim jāspēj pārliecināties, ka klientiem, kas tos izgūst, ir visas atkarības. Pretējā gadījumā pakotnes failā var trūkt klientam nepieciešamu objektu.
Savukārt, ja Git serveris nenorāda nevienu atsauci, klients ģenerē pakotnes failu ar visu repozitorija vēsturi. Šo pakotnes failu var izmantot jebkurš cits klients, taču cena ir augsta: jebkura zara izgūšana faktiski kļūst par pilnu klonēšanu.
Norādot vairāk atsauču, pakotņu faili kļūst mazāki. Lielāko daļu samazinājuma var panākt, norādot tikai vienu atsauci.
Pēc noklusējuma, kad klients nosūta jaunu funkcionalitātes zaru, Pando kā pamatu norāda tikai izraudzīto galveno zaru. Tādējādi norādīto atsauču apjoms nemainās, pieaugot zaru skaitam repozitorijā, taču ir arī kompromisi. Kad inženieris daudzkārt nosūta izmaiņas uz vienu zaru vai veido vienu funkcionalitātes zaru uz cita pamata, klientam atkārtoti jānosūta viss, kas nav galvenajā zarā.
Tādēļ secīgās nosūtīšanās uz zaru pārsūtāmais apjoms kļūst lielāks, tajās var būt lieki objekti un tiek patērēts papildu klienta tīkla joslas platums. Mūsu monorepozitorijā šādi veidota pakotnes faila lieluma mediāna bija zem 20 KiB, bet 99. procentile — zem 3 MiB. Mums tas bija saprātīgs kompromiss, jo lasītājs, kuram jau ir norādītā galvenā zara vēsture, var izgūt zaru ar šo vienu pakotnes failu.
Pēc klientam norādāmās atsauču kopas izvēles Pando pieņem nosūtīšanu un atjaunina savu metadatu krātuvi. Pando sadala metadatu atjaunināšanu sinhronajā un asinhronajā daļā. Sinhronā metadatu atjaunināšana nodrošina, ka klienti var nekavējoties izgūt tikko atjaunināto fiksējumu. Tiek ierakstīta jauna atsauces versija un atjaunināts atsauces rādītājs uz to, saglabājot jauno zara galu, pakotnes faila saskaņošanā izmantotās atkarības un saiti uz nosūtīto pakotnes failu.
Vienlaikus tajā pašā transakcijā tiek reģistrēti asinhronie darbi, piemēram, blīvēšanas ieplānošana. Ļoti lielām nosūtīšanām sinhroni tiek ierakstīta tikai daļa fiksējumu. Tas ļauj metadatu krātuvē veikt tikai konstantu lasīšanas un rakstīšanas darbību skaitu neatkarīgi no nosūtīšanas apjoma.
Svarīgi, ka Pando serveri var neatkarīgi pieņemt nosūtīšanas uz nesaistītām atsaucēm. Vienīgā atslēga, par kuru rodas konkurence, ir atsauces rādītājs, ko aizsargājam ar atomāru operāciju, kas līdzinās salīdzināšanai un apmaiņai. Rakstīšanas caurlaidspēju varam palielināt, pievienojot Pando serverus, metadatu krātuves mērogošanas vienības vai blobu krātuves.
Veicot izgūšanu, klients serverim norāda divas fiksējumu ID kopas, ko protokolā apzīmē ar have un want. Parasts Git serveris aprēķina starpību starp objektu kopām, kas sasniedzamas no esošajiem un vēlamajiem fiksējumiem, saspiež iegūtos objektus un nosūta rezultātu klientam. Lai gan atvērtā pirmkoda Git serverim lokāli ir dažādi indeksi šīs operācijas paātrināšanai, šādu pakotņu failu aprēķināšana var būt dārga, un tos parasti ir grūti izmantot kešatmiņā.
Tā vietā Pando izmanto nosūtīšanas laikā reģistrēto fiksējumu kartējumu, lai atrastu klienta have un want fiksējumus un noteiktu atsauču versiju kopu, kurā tie ietilpst. Katra no šīm atsauču versijām ir saistīta ar pakotnes failu, ko Pando saņēmis iepriekš. Serveris izmanto šo informāciju, lai noteiktu klientam nepieciešamo un atlasītu pakotņu failus, kas aptver visus vajadzīgos objektus.
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.
Fetch 27 trunk packs.
Select a branch to include its trunk dependencies.
Pando sasaista Git protokolā norādītos esošos un vēlamajos fiksējumus ar atsauču versiju secību. Pieprasot sānu zaru, tiek pieprasīta arī tā vēsture līdz atkarībām galvenajā zarā.
Git protokols klonēšanas vai izgūšanas HTTP atbildē ļauj nosūtīt tikai vienu pakotnes failu. Tomēr nepietiekami novērtēta Git protokola iespēja — packfile-uri — ļauj serverim atgriezt saites papildu pakotņu atsevišķai lejupielādei. Pando izmanto tikai šo iespēju un pašā atbildē nosūta tukšu pakotnes failu. Lai atbalstītu šo iespēju, OpenAI iesniedza vairākus packfile-uri uzlabojumus Git pamatprojektā.
OpenAI sistēmas darbojas daudzos ģeogrāfiskos reģionos, tāpēc katrā uzturam Pando klasterus ar lokālām kešatmiņām. Pakotņu piegādes pakalpojums Express kešo mūsu blobu krātuves datus, bet atsevišķs pakalpojums — metadatu krātuves datus. Šīs kešatmiņas ļauj Pando apkalpot fiksējuma ID pieprasījumus vai īpašus atsauces lasīšanas pieprasījumus, pilnībā izmantojot attiecīgajā klasterī kešoto stāvokli. Pakotnes faila pieprasījumu maršrutēšanai uz Express serveriem izmantojam konsekvento jaukšanu, sasniedzot vairāk nekā 99 % kešatmiņas trāpījumu īpatsvaru.
Šī kešatmiņu sistēma nodrošina ārkārtīgi augstu caurlaidspēju, spējot pilnībā izmantot tīkla savienojuma jaudu starp klientiem un Pando. Izmantojot šos pakotņu failu URI un lokālās kešatmiņas, esam pārbaudījuši, ka pat tikai ar mākoņpakalpojumu sniedzēja standarta virtuālajām mašīnām klonēšana un izgūšana pilnībā noslogo 10 Gbit/s tīkla savienojumus.
Vairumam Git serveru pārpakošana un atkritumu savākšana ir nepieciešama, lai saglabātu augoša repozitorija veiktspēju. Abas darbības atbrīvo vietu, taču ir skaitļošanas un ievades/izvades resursietilpīgas.
Tik strauji mainīgā repozitorijā kā OpenAI monorepozitorijs nav praktiski sūtīt atsevišķu pakotnes faila URI par katru nosūtīšanu kopš pēdējās izgūšanas. Klientam katru dienu būtu jālejupielādē desmitiem tūkstošu pakotņu failu, lai atjauninātu savu galveno zaru.
Tā vietā Pando fonā apvieno pakotnes, lai mazinātu šo papildu slodzi, izmantojot pieeju, kas līdzinās blīvēšanai žurnālstrukturētos sapludināšanas kokos. Katra nosūtīšana rada pakotnes failu, ko Pando sauc par „L0”, — mazāko datu vienību, ko Pando var pārsūtīt. Laika gaitā fona darba procesi apkopo šos pakotņu failus pārklājumos, kas aptver atsauču versiju secību un ģeometriski pieaug, sākot no L0. Pašlaik mūsu monorepozitorijā tiek izmantoti pakotņu failu pārklājumi līdz L4 līmenim.
Šiem pārklājumiem ir divējāds uzdevums. Kad pārklājums ir pietiekami pilns, blīvēšanas darba process pārņem tā apstrādi un izveido vienu pakotnes failu. Pārkārtojot objektus pakotnes failā, tiek uzlabota saspiešanas pakāpe. Vienlaikus tas uzlabo izgūšanas saskaņošanas veiktspēju, darbojoties kā atsauču versiju izlaidumu saraksts. Vienlaikus pārskatot indeksus katrā līmenī, Pando var atlasīt klientam nosūtāmo pakotņu kopu logaritmiskā laikā. Šie pakotņu failu pārklājumi — gan pārpakotie, gan nepārpakotie — ļauj efektīvāk plānot izgūšanu, mazinot Pando caurlaidspējas un aizkaves prasības.
Compaction in Pando
Small packfiles are grouped into larger covers across levels, improving compression and speeding up fetches.
Blīvēšana fonā apvieno daudzu atsauču versiju pakotņu failus, ļaujot efektīvāk izgūt datus ar mazāku failu skaitu.
Atšķirībā no daudziem Git serveriem pakotņu faili tiek saglabāti visos līmeņos, nevis atmesti vai izņemti atkritumu savākšanā. Visu līmeņu pakotnes tiek pastāvīgi izmantotas klientu apkalpošanai atbilstoši izgūšanas pieprasījumā norādītajiem have un want fiksējumiem. Savukārt klientiem, kas Pando izmanto kā API, patvaļīga objekta nolasīšanai no pakotnes faila parasti jālasa mazāk datu no L0 nekā no L4, jo ir mazāka varbūtība, ka objekts būs saspiests.
Blīvēšana Pando būtiski samazina klientiem pārsūtāmo datu kopapjomu un ļauj pakotņu plānošanas izmaksām augt lēnāk nekā lineāri attiecībā pret klienta atpalicību. Tas ir īpaši svarīgi lieliem un strauji mainīgiem repozitorijiem, kas, mūsuprāt, kļūs par jauno normu programmatūras izstrādē.
Pando izveidojām ar Codex, no projekta sākuma līdz ieviešanai ražošanas vidē nonākot tikai 10 nedēļās. Pando kodolu projektēja viens inženieris, īstenoja aģentu komandas un ieviesa daži inženieri. Pando sāka apkalpot ražošanas vides datplūsmu šī gada aprīlī un ir daļa no plašākas pirmkoda pārvaldības rīku sistēmas, ko izmanto OpenAI.
Pando arhitektūras validēšanai izmantojām ļoti dažādas pieejas. Mēs piemērojām savus drošāku programmatūras pamatu veidošanas principus. Tā kā projektu sākām no nulles, izvēlējāmies Pando izstrādāt Rust valodā un bez mantotām atkarībām. Izveidojām atbilstības testu kopu, lai aģenti varētu pārbaudīt savu izmaiņu atbilstību Git standarta darbībai. Izstrādājām arī deterministiskas simulācijas testēšanas izpildes ietvarus, kas ļauj pārbaudīt sistēmas invariantus un īpašības. Tas palīdzēja atrast un novērst grūti pamanāmus sacensības apstākļus un regresijas saskaņošanā un pakotņu plānošanā.
Šīs sistēmas tapšanā piedalījās daudzi modeļi; kļūstot pieejamiem jauniem modeļiem, tos izmantojām Pando veiktspējas un uzticamības uzlabošanai. Izmantojot GPT‑6 Astra, aģenti rakstīja Lean un TLA+, lai formalizētu „Pando teoriju”, ar kuru meklējām un labojām ieviešanas kļūdas un pierādījām sistēmas īpašības. Vairākas nepārtrauktas sesijas ilga simtiem stundu, meklējot un novēršot Pando problēmas robežgadījumos. Mēs arī visu diennakti darbinām aģentus, kas ar Daybreak spējīgiem modeļiem veic Git un Pando drošības pārbaudes, imitējot uzbrucējus.
Sākotnēji Pando ieviesām kā starpniekserveri, kas lasīšanas un rakstīšanas pieprasījumus pārsūtīja mūsu esošajai pirmkoda kontroles sistēmai. Tas ļāva uzturēt Pando un iepriekšējo sistēmu sinhronizētus, lai droši pārceltu datplūsmu uz Pando bez dīkstāves.
Pando kešošanas risinājums ļauj arī pirms pārsūtīšanas noņemt pieprasījumu dublikātus un apvienot pieprasījumus. Tas ļāva uzturēt esošo rīku stabilu darbību, pakāpeniski pārceļot sistēmas uz Pando. Pārceļot uz Pando vairāk darba slodžu, to nosūtīšanas piepildīja Pando kešatmiņu un uzlaboja iepriekšējās aizmugursistēmas uzticamību.
Lai optimizētu veiktspēju darbā ar Pando, sākām izplatīt savu publisko Git distribūciju izstrādātāju datoros un ChatGPT datora lietotnē. Klientu pakāpeniskai migrācijai uz Pando izmantojām iekšēju Git komandrindas saskarnes apvalku. Izveidojām daudzus citus rīkus izmaiņu pieprasījumu apstrādei, koda pārskatīšanai un API automatizācijai. Līdztekus Git datplūsmai migrējām simtiem integrāciju, kas bija atkarīgas no mantotām API, tīmekļa aizķerēm un repozitoriju lejupielādēm.
Pāreju izstrādātājiem un komandām palīdzēja veikt pats Codex. Izveidojām prasmes esošo darba kopiju sagatavošanai un aģentu vadīšanai darbā ar jauno sistēmu. Tādēļ izstrādātāji varēja vienkārši lūgt Codex migrēt viņu izstrādes vides un pakalpojumus.
Pāreja uz Pando uzlaboja apvienošanas uzticamību un samazināja nosūtīšanas aizkaves mediānu gandrīz par 80 %.
Pando spēj piegādāt petabaitu Git datu dienā, izmantojot tikai dažus CPU kodolus. Pando vienas stundas laikā ir piegādājis vairāk nekā 57 terabaitus Git pakotņu, turklāt vairāk nekā 99 % šo baitu — no lokālās diska kešatmiņas.
Pakotņu atkārtota izmantošana ļauj daudziem klientiem lejupielādēt vienu repozitorija vēsturi ar nelielu skaitļošanas slodzi apkalpojošajos mezglos. Šajā piemērā ir viens repozitorijs, taču Pando ir veidots daudz lielāka skaita atbalstam. Pieaugot pieprasījumam, varam neatkarīgi mērogot datu piegādi un Git saskaņošanu.
Pando izveide uz Git protokola un klienta pamata palīdzēja mums atklāt kļūdas un iespējas uzlabot paša Git veiktspēju.
Piemēram, Pando piegādā atkārtoti izmantojamas pakotnes tieši klientiem, tāpēc to lejupielāde un indeksēšana kļuva par būtisku priekšnoteikumu ātrai un uzticamai sistēmai. Šis darbs atklāja robežgadījumus vienlaicīgās lejupielādēs, uzkopšanā pēc pārtrauktām pārsūtīšanām un jau pabeigtu lejupielāžu atsākšanā. Izlabojām šo gadījumu apstrādi, pievienojām validācijas, pieņemot esošu pakotni izgūšanai, un iesniedzām šos uzlabojumus pamatprojektā.
Mums arī vajadzēja redzēt, kur tiek patērēts laiks un joslas platums, tāpēc pievienojām packfile-uri lejupielāžu izsekošanu un baitu uzskaiti pakotņu ģenerēšanā. Tas ļauj vieglāk noteikt, vai lēnā izgūšanā laiks tiek tērēts pakotņu ģenerēšanai vai pārsūtīšanai.
OpenAI Git būvējumā(atveras jaunā logā) klients var paralēli lejupielādēt un indeksēt neatkarīgas pakotnes. Pievienojām jēdzienu „skaidri norādīti esošie fiksējumi”, lai serveris varētu norādīt zara pašreizējo galu atsevišķi no vēstures, ko nosūtošais klients drīkst izlaist savā pakotnē. Pando tas ļauj klientiem izmantot --force-with-lease, lai pārbaudītu, vai funkcionalitātes zars nav mainījies, un veidot tā pakotni tikai pret galveno zaru. Pēc tam ikviens, kam ir šī galvenā zara vēsture, var izgūt zaru, izmantojot to pašu pakotni.
Vairāki no šiem uzlabojumiem jau ir Git pamatprojektā, un daudzi citi — mūsu publiskajā repozitorijā. Turpinām sadarboties ar Git kopienu, lai šie uzlabojumi noderētu arī ārpus Pando. Šim darbam var sekot mūsu publiskajā ielāpu izsekošanas rīkā(atveras jaunā logā).
Pārskatot ierastos priekšstatus par Git repozitoriju mērogošanu, Pando ļauj mums mērogot monorepozitoriju, nemainot Git darbplūsmas, ko mūsu inženieri un aģenti jau izmanto. Mūsu monorepozitorijā Pando ir ļāvis vairāk darbību veikt paralēli, uzlabojis apvienošanas uzticamību un saīsinājis koda izmaiņu publicēšanas laiku. Papildus monorepozitorijam pētām arī citus Pando lietojumus OpenAI iekšienē, tostarp darba slodzes, kurās lielam aģentu skaitam jāsadarbojas kopīgā Git repozitorijā.
Inženieriem un aģentiem radot arvien vairāk programmatūras, arvien vairāk komandu ārpus OpenAI saskarsies ar tiem pirmkoda kontroles ierobežojumiem, kurus sasniedzām mēs. Pašlaik pētām, kā mūsu lietotājiem darīt pieejamu tehnoloģiju, uz kuras balstās Pando.
Pando balstās uz Git repozitoriju lietotāju un uzturētāju divdesmit gadu pieredzi. Turpināsim attīstīt Pando un sadarboties ar Git atvērtā pirmkoda kopienu, lai dalītos ar uzlabojumiem, kas noder plašākam Git lietotāju lokam.


