OpenAI

2 नवंबर 2026

इंजीनियरिंग

OpenAI में Git की क्षमता बढ़ाना

Git पारिस्थितिकी तंत्र में निवेश के साथ एजेंटों के पैमाने पर काम संभालने वाला स्रोत नियंत्रण बनाना.

लेखक: एरन फ़्रिएल, टेलर ब्लाउ और टेड नाइमन, तकनीकी स्टाफ़ के सदस्य

लोड किया जा रहा है...

पिछले एक साल में हमारे मोनोरेपो का आकार और उस पर पड़ने वाला कार्यभार बेहद तेज़ी से बढ़ा है. यह स्पष्ट था कि Codex जितना समवर्ती काम संभव बनाता है, उसे संभालने के लिए हमें अपनी स्रोत नियंत्रण प्रणाली को नया रूप देना होगा.

हमने इंजीनियरिंग का कोई काम रोके बिना या टीम के Git इस्तेमाल करने का तरीका बदले बिना Git रिपॉज़िटरी के लिए नया बैकएंड, Pando बनाया. अब OpenAI के मोनोरेपो में सारा विकास Pando पर चलता है. Pando दो महत्वाकांक्षी लक्ष्य पूरे करने के लिए बनाया गया है. पहला: अधिक मशीनें जोड़कर राइट क्षमता बढ़ाना, खास तौर पर कई ब्रांचों पर एक साथ होने वाले पुश के लिए. दूसरा: रीड थ्रूपुट अधिकतम करना, ताकि क्लाइंट इतनी तेज़ी से डेटा डाउनलोड कर सकें कि उनकी उपलब्ध नेटवर्क बैंडविड्थ का पूरा उपयोग हो.

हमने Git प्रोटोकॉल और क्लाइंट के साथ अनुकूलता बनाए रखते हुए ये लक्ष्य पूरे किए. इससे हमारे इंजीनियर और एजेंट अपने मौजूदा कार्यप्रवाहों में आसानी से Pando अपना सके. वास्तविक संचालन में Pando ने पुश विलंबता की माध्यिका घटाकर लगभग पाँचवाँ हिस्सा कर दी. अब यह रोज़ाना लगभग एक पेटाबाइट Git डेटा पहुँचाता है.

यहाँ हम बताएँगे कि हमने नई स्रोत नियंत्रण प्रणाली क्यों बनाई और Git के साथ अनुकूलता बनाए रखने का निर्णय क्यों लिया. हम अपनी प्रणाली की तुलना Git की क्षमता बढ़ाने के प्रचलित तरीकों से करेंगे और बताएँगे कि OpenAI की बढ़ती ज़रूरतें पूरी करने में Pando खास तौर पर सक्षम क्यों है. हम आगे की योजनाओं पर भी चर्चा करेंगे और बताएँगे कि एजेंटों के पैमाने पर काम को संभव बनाने के लिए Git में अपना योगदान कैसे जारी रखेंगे.

हमें नई स्रोत नियंत्रण प्रणाली की ज़रूरत क्यों पड़ी

Codex ने OpenAI में विकास का पैमाना और गति बदल दी है. अब इंजीनियर कहीं अधिक काम समानांतर कर सकते हैं. इसका मतलब है अधिक ब्रांचें, पुश और मर्ज, तथा विकास परिवेशों, शोध कार्यों और सतत एकीकरण से अधिक फ़ेच और क्लोन.

ये माँगें मिलकर कार्यभार और बढ़ा देती हैं. अब एक इंजीनियर के कई बदलाव एक साथ सतत एकीकरण के लिए तैयार होते हैं, और हर पुश कई कार्यों को वही कमिट फ़ेच करने में लगा सकता है.

पिछले साल के अंत के आसपास से हमारे मोनोरेपो को चलाने वाली प्रणालियों के लिए इस गति से तालमेल रखना मुश्किल होने लगा. फ़ेच और पुश धीमे होने लगे, मर्ज विफल होने लगे, और कई बार विश्वसनीयता 90% से भी नीचे चली गई. क्या हम Git की अपनी सीमा तक पहुँच गए थे, या समस्या अपने मोनोरेपो को उपलब्ध कराने के हमारे तरीके में थी? Git की शुरुआत ऐसे समुदाय से हुई थी जो ईमेल के ज़रिए कर्नेल के पैच साझा करता था. दो दशकों से भी अधिक समय में, सॉफ़्टवेयर बनाने के तरीके बदलने के साथ डेवलपर अपने टूल को Git के अनुरूप ढालते रहे हैं. जब हमें अपने मोनोरेपो में अड़चनें आने लगीं, तो हमारे लिए उस काम को आगे बढ़ाते रहना महत्वपूर्ण था.

हमें परिचित कार्यप्रवाह बनाए रखते हुए बैकएंड को दोबारा बनाने का रास्ता दिखा, ताकि वह अलग-अलग ब्रांचों के पुश समानांतर संभाल सके और कई रीडर को एक ही इतिहास एक साथ दे सके. अपने स्रोत नियंत्रण कार्यप्रवाह की नींव Git पर रखने का मतलब था कि क्लाइंट में किए गए सुधार OpenAI के बाहर भी उपयोगी हो सकते थे. हम Git की अपनी प्रति⁠(एक नई विंडो में खुलेगा) में किए गए सुधार मूल परियोजना में योगदान के रूप में देना चाहते थे, ताकि व्यापक समुदाय भी उनका लाभ उठा सके.

बड़े पैमाने पर Git के लिए इंजीनियरिंग

स्रोत नियंत्रण प्रणाली की क्षमता बढ़ाने के दो ज़रूरी पहलू हैं: कई राइटर का अलग-अलग ब्रांचों पर पुश करना और कई रीडर का एक ही इतिहास फ़ेच करना. Pando दोनों के लिए अनुकूलित है.

पहला, Pando हर ब्रांच के अपडेट का समन्वय स्वतंत्र रूप से करता है. असंबंधित ब्रांचों के अपडेट समानांतर हो सकते हैं, और किसी ब्रांच को फ़ेच करने वाले रीडर को उस संशोधन के लिए ज़रूरी इतिहास मिलता है. इसके बदले यह सीमा स्वीकार करनी पड़ती है कि कई ब्रांचें देखने वाले रीडर को उनकी अलग-अलग समय की स्थितियाँ दिख सकती हैं.

दूसरा, Pando हर क्लाइंट के लिए अलग पैकफ़ाइल बनाने के बजाय फ़ेच अनुरोधों में पैकफ़ाइलों का पुनः उपयोग करता है. पैकफ़ाइल कई ऑब्जेक्ट को एक साथ संपीड़ित करने का Git का प्रारूप है. क्लाइंट कुछ ऐसे ऑब्जेक्ट डाउनलोड कर सकता है जो उसके पास पहले से हैं, लेकिन सर्वर बहुत कम गणना करके कई क्लाइंट को वही बाइट दे सकता है.

इन विकल्पों से हम अलग-अलग ब्रांचों पर राइट क्षमता बढ़ा सकते हैं और कैश से रीड अनुरोध पूरे कर सकते हैं. यह समझने के लिए कि ये तरीके साथ कैसे काम करते हैं, पहले देखते हैं कि Git इतिहास को कैसे सहेजता और स्थानांतरित करता है.

Git ऑब्जेक्ट भंडारण का परिचय

Git को रिपॉज़िटरी के दो हिस्सों में तालमेल बनाए रखना होता है: ऑब्जेक्ट और रेफ़रेंस.

Git रिपॉज़िटरी फ़ाइलों के स्नैपशॉट और उन्हें जोड़ने वाले इतिहास को ऑब्जेक्ट के ग्राफ़ के रूप में दर्ज करती है. ऑब्जेक्ट एक ब्लॉब, ट्री, कमिट या टैग हो सकता है. ब्लॉब में किसी एक फ़ाइल की सामग्री होती है. ट्री नामों को ब्लॉब या अन्य ट्री से जोड़कर डायरेक्टरी संरचना बनाते हैं. कमिट एक रूट ट्री और शून्य या अधिक पैरेंट कमिट की ओर संकेत करते हैं, जिससे आपकी रिपॉज़िटरी का इतिहास बनता है.

ऑब्जेक्ट की पहचान उनके प्रकार और सामग्री के हैश से होती है. ऑब्जेक्ट अपरिवर्तनीय भी होते हैं: बदली हुई फ़ाइल दर्ज करने पर नया ब्लॉब बनता है, जबकि अपरिवर्तित फ़ाइलें और डायरेक्टरी मौजूदा ऑब्जेक्ट का फिर से उपयोग कर सकती हैं.

ब्रांच और टैग ऐसे रेफ़रेंस, या “रेफ़”, हैं जो कमिट की ओर संकेत करते हैं. ब्रांच पर कमिट करने से नया कमिट बनता है और ब्रांच का रेफ़ उसकी ओर संकेत करने के लिए अपडेट हो जाता है.

ब्रांच refs/heads/main कमिट C2 की ओर संकेत करती है, जिसका पैरेंट C1 है. C1 रूट ट्री T1 की ओर संकेत करता है, जहाँ parser.py ब्लॉब B1 को संदर्भित करता है. C2 रूट ट्री T2 की ओर संकेत करता है, जहाँ parser.py ब्लॉब B2 को संदर्भित करता है. दोनों रूट ट्री में docs/ उसी ट्री T3 को संदर्भित करता है. उसकी README.md प्रविष्टि ब्लॉब B3 की ओर और usage.md ब्लॉब B4 की ओर संकेत करती है.

Git ऑब्जेक्ट अपनी आईडी से एक-दूसरे को संदर्भित करते हैं: कमिट ट्री को और ट्री अन्य ट्री तथा ब्लॉब को संदर्भित करते हैं. ब्रांच refs/heads/main कमिट C2 की ओर संकेत करती है, जिसका पैरेंट C1 है. C1 रूट ट्री T1 की ओर संकेत करता है, जहाँ parser.py ब्लॉब B1 को संदर्भित करता है. C2 रूट ट्री T2 की ओर संकेत करता है, जहाँ parser.py ब्लॉब B2 को संदर्भित करता है. दोनों रूट ट्री में docs/ उसी ट्री T3 को संदर्भित करता है. उसकी README.md प्रविष्टि ब्लॉब B3 की ओर और usage.md ब्लॉब B4 की ओर संकेत करती है.

Git ऑब्जेक्ट को “अलग-अलग” या “पैक किए हुए” रूप में सहेजता है. अलग-अलग ऑब्जेक्ट अपनी ऑब्जेक्ट आईडी से पहचानी जाने वाली अलग फ़ाइलों में सहेजे जाते हैं. पैक किए गए ऑब्जेक्ट एक पैकफ़ाइल में साथ सहेजे जाते हैं. इससे मिलते-जुलते ऑब्जेक्ट को एक-दूसरे के सापेक्ष केवल अंतर के रूप में सहेजा जा सकता है.

$GIT_DIR/objects के अंतर्गत parser.py के दो संस्करण दिखाई देते हैं. अलग-अलग ऑब्जेक्ट के रूप में ब्लॉब A में parse() है और ब्लॉब B में parse() तथा parse_file(), दोनों हैं. पैकफ़ाइल A को पूरा सहेजती है और B को ऐसे निर्देशों के रूप में दर्शाती है जो पूरा A कॉपी करके अंत में parse_file() जोड़ते हैं. साथ की *.idx फ़ाइल ऑब्जेक्ट आईडी से पैकफ़ाइल में दोनों ब्लॉब का स्थान ढूँढ़ती है.

Git ब्लॉब को अलग फ़ाइलों में सहेज सकता है या साथ पैक कर सकता है, जिसमें एक ब्लॉब को दूसरे से उसके अंतर के रूप में एन्कोड किया जाता है.

Git में कोई ऑब्जेक्ट किसी कमिट से पहुँच योग्य होता है, अगर Git उस कमिट से उसके पैरेंट, ट्री और ब्लॉब के लिंक का अनुसरण करके उसे ढूँढ़ सकता है. फ़ेच के दौरान क्लाइंट सर्वर को बताता है कि उसे कौन-से कमिट चाहिए और कौन-से उसके पास पहले से हैं. सर्वर वांछित कमिट से पहुँच योग्य ऑब्जेक्ट ढूँढ़ता है, वे ऑब्जेक्ट हटाता है जिनके क्लाइंट पर पहले से होने की उसे जानकारी है, और बाकी को पैकफ़ाइल में भेजता है. इसका प्रारूप वही होता है जो Git डिस्क पर इस्तेमाल करता है. पूर्ण क्लोन की शुरुआत बिना किसी ऑब्जेक्ट के होती है, इसलिए उसे क्लोन किए जा रहे इतिहास से पहुँच योग्य सभी ऑब्जेक्ट चाहिए.

पुश सर्वर से एक या अधिक रेफ़ अपडेट करने को कहकर ऑब्जेक्ट को उलटी दिशा में भेजता है. क्लाइंट सर्वर के घोषित रेफ़ के समूह का उपयोग करता है, ताकि सर्वर पर पहले से मौजूद ऑब्जेक्ट न भेजने पड़ें. इसलिए भेजा जा रहा पैक मौजूदा ऑब्जेक्ट पर निर्भर हो सकता है: नया इतिहास दोबारा बनाने के लिए केवल पैक मिलना पर्याप्त नहीं है.

Git रिपॉज़िटरी की प्रतिकृति बनाने का मतलब है ऑब्जेक्ट और रेफ़रेंस, दोनों को कई सर्वरों पर उपलब्ध रखना. किसी प्रतिकृति को रेफ़रेंस का नया मान उपलब्ध कराने से पहले उस मान से पहुँच योग्य ऑब्जेक्ट देने में सक्षम होना चाहिए. सेवा को प्रतिस्पर्धी रेफ़रेंस अपडेट का भी समन्वय करना होता है. ये ऐसे पुश हैं जो एक ही ब्रांच को उसी पुराने शीर्ष कमिट से अलग-अलग नए कमिट पर ले जाने की कोशिश करते हैं. रिपॉज़िटरी के सभी राइट पर एक ही क्रम लागू करने वाली प्रणालियों में असंबंधित ब्रांचों के पुश को भी एक-दूसरे का इंतज़ार करना पड़ सकता है.

वितरित Git सेवाओं के मौजूदा ढाँचे

Pando का डिज़ाइन बनाते समय हमने Git से स्रोत नियंत्रण की क्षमता बढ़ाने के पारंपरिक तरीके परखे. एक तरीका रिपॉज़िटरी की प्रतिकृतियों में रेफ़ अपडेट के समन्वय के लिए तीन-चरणीय कमिट (3PC, कई नोड पर कमिट का समन्वय करने वाला प्रोटोकॉल) इस्तेमाल करता है. दूसरा ब्लॉब भंडारण में साझा अग्रिम लेखन लॉग (WAL, बदलाव लागू होने से पहले उनका लिखित रिकॉर्ड) के ज़रिए अपडेट का क्रम तय करता है.

तीन-चरणीय कमिट (3PC)

हमने जिस तीन-चरणीय कमिट डिज़ाइन का अनुकरण किया, उसमें Git सेवा कई प्रतिकृतियों पर रिपॉज़िटरी की पूरी प्रति रखती है. किसी भी सर्वर को पुश मिलने पर आने वाली पैकफ़ाइल की प्रतियाँ सभी प्रतिकृतियों को समानांतर भेजी जाती हैं. पुश प्रकाशित करने के लिए अधिकांश प्रतिकृतियों को रेफ़ अपडेट स्वीकार करना होता है. इसे संभालने वाला सर्वर समन्वयक होता है. इस प्रक्रिया में समन्वयक और हर दूसरी प्रतिकृति के बीच कई दौर का संचार ज़रूरी होता है.

रेफ़रेंस अपडेट स्वीकार करने के लिए हर प्रतिकृति रेफ़ की अपनी प्रति को लॉक करती है और जाँचती है कि वह अब भी क्लाइंट के अपेक्षित कमिट की ओर संकेत करती है. फिर समन्वयक स्वीकार करने वाली प्रतिकृतियों को पूर्व-कमिट संदेश भेजता है. जब अधिकांश प्रतिकृतियाँ पूर्व-कमिट संदेश की पुष्टि कर देती हैं, तो समन्वयक उन्हें अपडेट लागू करने को कहता है. इसके बाद कोई भी नवीनतम प्रतिकृति रिपॉज़िटरी की अपनी स्थानीय प्रति से ब्रांच का नया शीर्ष कमिट घोषित कर सकती है.

पूरी प्रतिकृतियाँ रखने से रीड अनुरोध स्थानीय रूप से पूरे किए जा सकते हैं. इससे यह भी सुनिश्चित होता है कि क्लाइंट चाहे कोई भी प्रतिकृति चुने, उसे सभी रेफ़रेंस की संगत स्थिति मिले. नतीजतन, रेफ़रेंस एक-एक करके अपडेट होते हैं और हर पुश में प्रतिकृतियों के बीच रेफ़ अपडेट का समन्वय करने के लिए कई बार संदेश आने-जाने पड़ते हैं.

आवश्यक बहुमत का इंतज़ार करने से पुश का समय प्रतिकृतियों की डिस्क के प्रदर्शन और संचार विलंबता पर निर्भर हो जाता है. राइट की मात्रा बढ़ने पर प्रतिकृतियों को आने वाले पैक के साथ रीड अनुरोध भी उसी गति से संभालने होते हैं.

अग्रिम लेखन लॉग (WAL)

हमने जिस WAL-आधारित डिज़ाइन का अनुकरण किया, उसमें Git सेवा पूरी रिपॉज़िटरी के अपडेट का क्रम तय करने के लिए ब्लॉब भंडारण में साझा मैनिफेस्ट इस्तेमाल करती है. सर्वर को पुश मिलने पर वह आने वाली पैकफ़ाइल ब्लॉब स्टोर में अपलोड करता है और रिपॉज़िटरी की अपनी स्थानीय प्रति में रेफ़ अपडेट तैयार करता है. पुश प्रकाशित करने के लिए वह ब्लॉब स्टोर में सहेजे साझा मैनिफेस्ट में एक प्रविष्टि जोड़ता है, जो रेफ़ अपडेट दर्ज करती है और पैकफ़ाइल की ओर संकेत करती है. फिर Git सर्वर तुलना-और-बदलाव क्रिया से मैनिफेस्ट अपडेट करता है. यह मैनिफेस्ट को एक अविभाज्य क्रिया में बदलता है या बदलाव अस्वीकार कर देता है. अगर इस बीच किसी दूसरे राइटर ने उसे अपडेट कर दिया हो, तो सर्वर बीच में जुड़ी प्रविष्टियाँ पढ़ता है, जाँचता है कि उसका रेफ़ अपडेट अब भी मान्य है और पहले से अपलोड की गई पैकफ़ाइल से दोबारा कोशिश करता है.

राइटर अपनी पैकफ़ाइलें समानांतर अपलोड कर सकते हैं, लेकिन असंबंधित ब्रांचों के पुश में भी उसी मैनिफेस्ट को अपडेट करना पड़ता है. सफल तुलना-और-बदलाव के लिए संदेश आने-जाने में लगने वाला समय तय करता है कि रिपॉज़िटरी कितनी बार नया मैनिफेस्ट प्रकाशित कर सकती है. कम विलंबता वाला ब्लॉब स्टोर इस चरण को तेज़ बनाता है. समूह बनाकर काम करने से एक मैनिफेस्ट कई रेफ़ एक साथ अपडेट कर सकता है, लेकिन इसके लिए अपडेट कतार में रखने पड़ते हैं और विलंबता बढ़ती है.

ब्लॉब स्टोर पैकफ़ाइलें समानांतर प्राप्त कर सकता है, लेकिन साझा मैनिफेस्ट के अपडेट फिर भी एक-दूसरे से प्रतिस्पर्धा करते हैं. केवल ब्लॉब स्टोर की क्षमता बढ़ाने से यह अड़चन दूर नहीं होती. हर प्रतिकृति को पैक स्थानीय रूप से उपलब्ध कराने से पहले उन्हें ब्लॉब स्टोर से पढ़ना और अनुक्रमित करना अब भी ज़रूरी होता है. अगर आने वाले राइट की गति इस काम से तेज़ हो, तो प्रतिकृतियाँ पीछे रह जाती हैं और नए पुश किए गए कमिट फ़ेच करने के लिए क्लाइंट को अधिक इंतज़ार करना पड़ता है.

Pando की संरचना तैयार करना

अब बात करते हैं Pando की. Pando Git रिपॉज़िटरी उपलब्ध कराने की नई संरचना है, जिसका लक्ष्य एक साथ पुश करने वाले बहुत-से क्लाइंट को संभालने की क्षमता बढ़ाना है. यह इस तरह काम करता है:

सीमाओं पर नए सिरे से विचार

Pando विकसित करने से पहले हमें लगता था कि हम Git से समझौता किए बिना अपनी ज़रूरतें पूरी कर सकते हैं. लेकिन हमें कुछ ऐसी चीज़ों से समझौता करना पड़ा जिन्हें अधिकांश Git प्रणालियाँ अनिवार्य मानती हैं:

  • पूरी रिपॉज़िटरी में संगति: सभी रेफ़ का एक निश्चित समय का संगत स्नैपशॉट देने के लिए पूरी रिपॉज़िटरी में समन्वय ज़रूरी है. सभी रेफ़ अपडेट का एक साझा क्रम तय करने वाली प्रणाली में असंबंधित ब्रांचों पर होने वाले पुश एक ही समन्वय बिंदु के लिए प्रतिस्पर्धा करते हैं.

  • हर क्लाइंट के लिए अलग पैकफ़ाइल: अगर अलग-अलग स्थानीय इतिहास वाले दो क्लाइंट एक ही ब्रांच फ़ेच करते हैं, तो सर्वर को दोनों के लिए अलग पैक बनाना पड़ सकता है, ताकि उनके पास पहले से मौजूद ऑब्जेक्ट दोबारा न भेजे जाएँ. ये प्रतिक्रियाएँ तैयार करने में सीपीयू और डिस्क इनपुट/आउटपुट संसाधन लगते हैं, जिससे बड़ी संख्या में रीडर को सेवा देने के लिए क्षमता बढ़ाना मुश्किल होता है.

इसके बजाय, Pando राइट क्षमता बढ़ाने के लिए कम सख्त संगति व्यवस्था (कारणात्मक संगति) देता है और रीड क्षमता बढ़ाने के लिए पैकफ़ाइलों का दोबारा उपयोग करता है.

कारणात्मक संगति (सीसी)

जब कोई क्लाइंट किसी ब्रांच पर पुश करता है, तो Pando आने वाली पैकफ़ाइल को ब्लॉब स्टोर में अपरिवर्तनीय ब्लॉब के रूप में सहेजता है. ब्रांच के हर बार आगे बढ़ने पर Pando मेटाडेटा स्टोर में एक रेफ़ संस्करण दर्ज करता है. इसमें नया शीर्ष कमिट, उसे देने वाला पैक और वे पुराने रेफ़ संस्करण होते हैं जिन पर पैक निर्भर है. ब्लॉब स्टोर और मेटाडेटा स्टोर, दोनों की क्षमता अधिक मशीनें जोड़कर बढ़ाई जा सकती है.

Pando से कमिट या रेफ़रेंस फ़ेच करने के लिए क्लाइंट को रेफ़ संस्करणों (पैकफ़ाइलों) का एक समूह क्रम से देना पड़ता है. इससे उस क्लाइंट की स्थिति दोबारा बनती है जिसने फ़ेच किया जा रहा रेफ़ संस्करण बनाया था. इससे पूरी रिपॉज़िटरी में कम सख्त संगति मिलती है, जबकि अलग-अलग रेफ़ के अपडेट ऐसे होते हैं मानो उन्हें क्रमवार लागू किया गया हो. क्लाइंट के बीच टकराव केवल तब होता है जब वे एक ही रेफ़ पर एक साथ पुश करते हैं. कई ब्रांचें पढ़ने वाला क्लाइंट यह नहीं मान सकता कि वे सभी रीड पूरी रिपॉज़िटरी के एक ही समय की स्थिति दर्शाते हैं.

बाईं ओर, ट्रंक के लगातार तीन पैक में क्रमशः कमिट A, B और C; D और E; तथा F हैं. दाईं ओर, ट्रंक और टॉपिक C पर अलग होते हैं. ट्रंक G तक बढ़ता है, जबकि टॉपिक D, E और F से होकर आगे बढ़ता है. नवीनतम टॉपिक पैक में D, E और F हैं. टूटी रेखाओं वाली रूपरेखा दिखाती है कि D और E पिछले टॉपिक पैक में भी मौजूद हैं. नीला तीर दिखाता है कि नया पैक G पर ट्रंक पर निर्भर है. F का Git पैरेंट E है.

ट्रंक पर पुश करने से एक वृद्धिशील पैक जुड़ता है, जिसमें एक या अधिक कमिट होते हैं. साइड ब्रांच पर हर पुश में उस विषय के पिछले कमिट फिर से शामिल होते हैं, ताकि घोषित ट्रंक संस्करण वाला क्लाइंट उस विषय को एक ही पैक में फ़ेच कर सके.

यह कारणात्मक संगति का एक रूप है. किसी रेफ़रेंस को फ़ेच करने के लिए रीडर उसे बनाने वाले राइटर का इतिहास देखता है. पुश के दौरान Pando तय करता है कि क्लाइंट और सर्वर किस साझा इतिहास पर सहमत होंगे, ताकि क्लाइंट ऐसी पैकफ़ाइलें बनाएँ जिन्हें साझा करना आसान हो.

नतीजतन, Pando Git संचालन के दौरान सभी रेफ़रेंस की एक निश्चित समय की स्थिति या क्लोन अथवा फ़ेच के भीतर रेफ़ अपडेट का कोई क्रम नहीं देता. मिसाल के लिए, मान लें कि पूर्ण क्लोन के लिए आपसी जानकारी के आदान-प्रदान के दौरान foo और bar दोनों ब्रांचें अपडेट होती हैं. इस आदान-प्रदान के दौरान एक क्लाइंट को foo का संस्करण 1 और bar का संस्करण 2 दिख सकता है, जबकि दूसरे को foo का संस्करण 2 और bar का संस्करण 1 दिखे. व्यवहार में, उपयोगकर्ता और एजेंट रेफ़ अपडेट के वैश्विक क्रम पर निर्भर नहीं होते; वे एक ही रेफ़रेंस के अपडेट क्रम पर निर्भर होते हैं.

तरीकों की तुलना

तीन संगति व्यवस्थाओं के इस अनुकरण में हम 1,000 क्लाइंट कॉन्फ़िगर करते हैं. हर क्लाइंट एक अलग ब्रांच चुनकर बार-बार अनूठे कमिट पुश करता है. हम बीता हुआ कुल वास्तविक समय और पुश से फ़ेच तक की विलंबता मापते हैं. पुश से फ़ेच तक की विलंबता कार्यभार के लिए अहम माप है, क्योंकि यह उपयोगकर्ताओं और एजेंटों के सहयोग करने या संस्करण नियंत्रण पर निर्भर अन्य प्रणालियाँ इस्तेमाल करने में लगने वाला आने-जाने का समय मापती है. यह अनुकरण सामान्य से लेकर उच्च श्रेणी की वर्चुअल मशीनों और ब्लॉब भंडारण प्रणालियों तक के हार्डवेयर को दर्शाता है. इस अनुकरण में हमने तीन-चरणीय कमिट के लिए पूरी रिपॉज़िटरी में संगति की शर्त को ढीला किया है.

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.

Pando की दो अन्य तरीकों से तुलना करने वाला यह अनुकरण चलाएँ. तुलना देखने के लिए सामान्य से लेकर उच्च श्रेणी के हार्डवेयर तक की अवसंरचना, क्लाइंट की संख्या और अन्य सेटिंग चुनें.

अनुकरण की गई तीन-चरणीय कमिट प्रणाली में लोड के दौरान डिस्क की पूरी क्षमता इस्तेमाल होने पर राइट विलंबता काफ़ी बढ़ जाती है. वहीं, अग्रिम लेखन लॉग प्रणालियों में इसी कारण रीड विलंबता काफ़ी बढ़ती है, क्योंकि सर्वर जर्नल पढ़ने की गति बनाए नहीं रख पाते. हमारे मोनोरेपो पर वास्तविक परीक्षण और इस अनुकरण, दोनों में Pando कई हज़ार क्लाइंट को एक साथ पुश करने देता है, और लोड के दौरान भी प्रदर्शन प्रभावित नहीं होता.

पुश संभालते समय Pando आने वाली पैकफ़ाइल को ब्लॉब भंडारण में स्ट्रीम करते हुए सत्यापित करता है. उसे स्थानीय रिपॉज़िटरी में अनपैक करने की ज़रूरत नहीं होती. जब कोई क्लाइंट फ़ेच शुरू करता है, तो Pando रीडर के लिए ज़रूरी सहेजे गए पैक चुनता है और रीडर उन्हें डाउनलोड करता है. किसी भी सर्वर को स्थानीय रिपॉज़िटरी में पैकफ़ाइलें लागू करने या संसाधन-खर्चीली अनपैकिंग और पैकिंग करने की ज़रूरत नहीं होती. चूँकि ये सर्वर मुख्य रूप से आपसी जानकारी का आदान-प्रदान और पैकफ़ाइलों का चयन करते हैं, इसलिए Pando सर्वर सामान्य हार्डवेयर पर चल सकते हैं.

इससे Pando की क्षमता क्लाइंट, क्लाइंट और Pando के बीच के नेटवर्क तथा ब्लॉब भंडारण सेवा की सीमाओं तक बढ़ सकती है. पर्याप्त क्षमता होने पर स्वतंत्र ब्रांचों पर काम करने वाला हर क्लाइंट अपने कनेक्शन की अधिकतम गति से पैक भेज या प्राप्त कर सकता है. उसी गति से अधिक क्लाइंट को सेवा देने के लिए हम Pando सर्वर जोड़ सकते हैं और साथ ही मेटाडेटा स्टोर तथा ब्लॉब स्टोर की क्षमता बढ़ा सकते हैं.

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

एजेंट फ़ाइलें संपादित करके स्थानीय रूप से कमिट बनाता है और git push चलाता है. इससे ब्रांच अपडेट करने के लिए उन बदलावों की पैकफ़ाइल बनती है. Pando पैक प्राप्त करके उसे ब्लॉब भंडारण में स्ट्रीम करता है. आने वाले पुश को एक बार डिकोड करके सत्यापित करने के बाद, Pando बहु-कुंजी लेनदेन से हमारे मेटाडेटा स्टोर में रेफ़ संस्करण दर्ज करता है और रेफ़ पॉइंटर को एक अविभाज्य क्रिया में अपडेट करता है. इससे Pando “अपना लिखा हुआ तुरंत पढ़ सकने” की संगति देता है. इस पूरे राइट संचालन के लिए O(1)O(1) मेटाडेटा रीड और राइट चाहिए.

जब दूसरा क्लाइंट ब्रांच फ़ेच करता है, तो Pando उसके पास पहले से मौजूद इतिहास के आधार पर सहेजे गए पैक का समूह चुनता है. इस संचालन के लिए O(log⁡Δ)O(\log \Delta) मेटाडेटा रीड चाहिए. यहाँ Δ\Delta क्लाइंट के पास मौजूद और उसके वांछित संस्करणों के बीच रेफ़ संस्करणों में सबसे छोटी दूरी है. सर्वर पैकफ़ाइल यूआरआई लौटाता है और क्लाइंट Express सेवा के ज़रिए उन्हें डाउनलोड करता है. यह सेवा पैकफ़ाइलों को क्षेत्रीय कैश में रखती है.

यह डिज़ाइन Pando की संरचना की तीन मुख्य सेवाओं पर निर्भर है: पुश, फ़ेच और समेकन.

पुश क्षमता बढ़ाना

जब क्लाइंट पुश करता है, तो पारंपरिक Git सर्वर पोकर के उस खिलाड़ी जैसा होता है जो अपने सारे पत्ते खोल देता है: वह क्लाइंट को अपनी हर ब्रांच बता देता है. इसके बाद क्लाइंट कमिट, ट्री और ब्लॉब इकट्ठा करके ऐसी पैकफ़ाइल बनाता है जो उन ऑब्जेक्ट को बाहर रखती है जिनके बारे में उसे पता है कि वे सर्वर पर पहले से हैं.

अधिक रेफ़ घोषित करने से पुश छोटा हो सकता है. इससे पैक का पुनः उपयोग मुश्किल भी हो सकता है, क्योंकि दूसरे क्लाइंट के पास वे ऑब्जेक्ट शायद न हों जिन्हें राइटर ने छोड़ दिया था.

Pando अलग तरीका अपनाता है. अपने सारे पत्ते खोलने के बजाय वह क्लाइंट को केवल चुनिंदा ब्रांचें बताता है. इसके दो कारण हैं:

  1. हर रेफ़ की संगत स्थिति देना खर्चीला है. लाखों ब्रांचें होने पर केवल रेफ़ घोषणा का आकार 100 MiB से अधिक हो सकता है. इसे देने के लिए हर सर्वर को या तो नवीनतम मैपिंग बनाए रखनी होती है, जिसमें समन्वय का काफ़ी अतिरिक्त खर्च आता है, या ऐसी डेटाबेस क्वेरी करनी होती है जिसका काम रेफ़ की संख्या के साथ बढ़ता है.

  2. क्लाइंट को केवल कुछ रेफ़ देने पर वह ऐसा पैक बनाता है जो सिर्फ़ उन्हीं ऑब्जेक्ट पर निर्भर होता है जिन्हें बाहर रखने की सर्वर ने स्पष्ट अनुमति दी है. निर्भरताओं पर नज़र रखने से Pando किसी पुश में क्लाइंट की बनाई पैकफ़ाइल को बाद के फ़ेच की प्रतिक्रिया के रूप में देकर दोबारा उपयोग कर सकता है.

Git सर्वर जितने अधिक रेफ़ घोषित करता है, पुश करने वाले क्लाइंट को ऑब्जेक्ट बाहर रखने के उतने अधिक आधार मिलते हैं, जिससे वे छोटे पैक बना सकते हैं. लेकिन इन पैकफ़ाइलों का पुनः उपयोग करने के लिए सर्वर को साबित करना होता है कि फ़ेच करने वाले क्लाइंट के पास हर निर्भरता मौजूद है. वरना पैकफ़ाइल में क्लाइंट के लिए ज़रूरी ऑब्जेक्ट छूट सकते हैं.

दूसरी ओर, अगर Git सर्वर कोई रेफ़ घोषित ही न करे, तो क्लाइंट रिपॉज़िटरी का पूरा इतिहास समेटने वाली पैकफ़ाइल बनाएगा. उस पैकफ़ाइल को कोई भी दूसरा क्लाइंट इस्तेमाल कर सकता है. लेकिन इसकी भारी कीमत यह है कि किसी भी ब्रांच को फ़ेच करना व्यवहार में पूर्ण क्लोन बन जाता है.

वक्र दिखाता है कि घोषित रेफ़रेंस पैकफ़ाइल के आकार को कैसे प्रभावित करते हैं: कोई रेफ़रेंस घोषित न होने पर पूरे इतिहास से शुरू होकर, ट्रंक की घोषणा के चरण से गुजरते हुए, सभी रेफ़रेंस घोषित होने पर केवल नए ऑब्जेक्ट तक.

अधिक रेफ़ घोषित करने से पैकफ़ाइलें छोटी होती हैं. आकार में अधिकांश कमी केवल एक रेफ़ घोषित करने से आ सकती है.

डिफ़ॉल्ट रूप से, जब क्लाइंट नई फ़ीचर ब्रांच पुश करता है, तो Pando आधार के रूप में केवल एक निर्धारित ट्रंक ब्रांच घोषित करता है. इससे रिपॉज़िटरी में ब्रांचें बढ़ने पर भी घोषणा का आकार समान रहता है, लेकिन कुछ सीमाएँ स्वीकार करनी पड़ती हैं. जब इंजीनियर एक ही ब्रांच पर बार-बार पुश करता है या एक फ़ीचर ब्रांच के ऊपर दूसरी बनाता है, तो क्लाइंट को ट्रंक से बाहर की हर चीज़ दोबारा भेजनी पड़ती है.

इससे ब्रांच के अगले पुश बड़े होते जाते हैं, उनमें संभवतः दोहराए गए ऑब्जेक्ट होते हैं और क्लाइंट की अतिरिक्त बैंडविड्थ इस्तेमाल होती है. हमारे मोनोरेपो में इस तरह बनी पैकफ़ाइल के आकार की माध्यिका 20 KiB से कम थी और 99वाँ प्रतिशतक 3 MiB से कम था. हमारे लिए यह उचित समझौता था, क्योंकि घोषित ट्रंक इतिहास पहले से रखने वाला रीडर उसी एक पैकफ़ाइल से ब्रांच फ़ेच कर सकता है.

क्लाइंट को घोषित किए जाने वाले रेफ़ चुनने के बाद Pando पुश स्वीकार करता है और अपना मेटाडेटा स्टोर अपडेट करता है. Pando मेटाडेटा अपडेट को समकालिक और अतुल्यकालिक हिस्सों में बाँटता है. समकालिक मेटाडेटा अपडेट सुनिश्चित करता है कि क्लाइंट नया अपडेट किया गया कमिट तुरंत फ़ेच कर सकें. यह नया रेफ़ संस्करण लिखता है और रेफ़ पॉइंटर की मैपिंग उस संस्करण पर अपडेट करता है. इसमें नया शीर्ष कमिट, पैकफ़ाइल तय करने में इस्तेमाल हुई निर्भरताएँ और पुश की गई पैकफ़ाइल का लिंक सहेजा जाता है.

उसी समय, समेकन निर्धारित करने जैसे अतुल्यकालिक काम भी उसी लेनदेन में दर्ज होते हैं. बहुत बड़े पुश में केवल कुछ कमिट समकालिक रूप से लिखे जाते हैं. इससे पुश के आकार की परवाह किए बिना मेटाडेटा स्टोर में रीड और राइट की संख्या स्थिर रहती है.

खास बात यह है कि Pando सर्वर असंबंधित रेफ़ के पुश स्वतंत्र रूप से स्वीकार कर सकते हैं. टकराव केवल रेफ़ पॉइंटर कुंजी पर होता है, जिसे हम तुलना-और-बदलाव जैसी अविभाज्य क्रिया से सुरक्षित रखते हैं. हम Pando सर्वर, मेटाडेटा स्टोर की क्षमता इकाइयाँ या ब्लॉब स्टोर जोड़कर राइट थ्रूपुट बढ़ा सकते हैं.

नेटवर्क की पूरी गति पर फ़ेच और क्लोन का प्रदर्शन

फ़ेच करते समय क्लाइंट सर्वर को कमिट आईडी के दो समूह देता है, जिन्हें प्रोटोकॉल में have और want कहा जाता है. पारंपरिक Git सर्वर में, सर्वर मौजूद कमिट से पहुँच योग्य और वांछित कमिट से पहुँच योग्य ऑब्जेक्ट के समूहों का अंतर निकालता है, उन्हें संपीड़ित करता है और परिणाम क्लाइंट को भेजता है. इस काम को तेज़ करने के लिए मुक्त-स्रोत Git सर्वर पर कई तरह की स्थानीय अनुक्रमणिकाएँ होती हैं. फिर भी ये पैकफ़ाइलें बनाना गणना की दृष्टि से खर्चीला हो सकता है और आम तौर पर इन्हें कैश करना मुश्किल होता है.

इसके बजाय Pando पुश के समय दर्ज कमिट मैपिंग से क्लाइंट के have और want ढूँढ़ता है और उन्हें उन कमिट वाले रेफ़ संस्करणों के समूह से जोड़ता है. इनमें से हर रेफ़ संस्करण Pando को पहले मिली पैकफ़ाइल से जुड़ा होता है. सर्वर इस जानकारी से क्लाइंट की ज़रूरत तय करता है और वे पैकफ़ाइलें चुनता है जिनमें उसके सभी ज़रूरी ऑब्जेक्ट शामिल हों.

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 Git प्रोटोकॉल में मौजूद और वांछित कमिट को रेफ़ संस्करणों के एक क्रम से जोड़ता है. साइड ब्रांच की माँग करने का अर्थ ट्रंक पर उसकी निर्भरताओं तक के इतिहास की माँग करना भी है.

Git प्रोटोकॉल क्लोन या फ़ेच की एचटीटीपी प्रतिक्रिया में केवल एक पैकफ़ाइल भेजने देता है. लेकिन Git प्रोटोकॉल की एक कम पहचानी गई सुविधा, packfile-uri, सर्वर को अतिरिक्त पैक अलग से डाउनलोड करने के लिंक लौटाने देती है. Pando केवल इसी तरीके का उपयोग करता है और प्रतिक्रिया के भीतर एक खाली पैकफ़ाइल भेजता है. इस सुविधा को बेहतर समर्थन देने के लिए OpenAI ने मूल परियोजना में packfile-uri के कई सुधारों का योगदान दिया.

OpenAI की प्रणालियाँ कई भौगोलिक क्षेत्रों में चलती हैं, इसलिए हम हर क्षेत्र में स्थानीय कैश वाले Pando क्लस्टर रखते हैं. पैक पहुँचाने वाली Express सेवा हमारे ब्लॉब स्टोर को कैश करती है और एक अलग सेवा मेटाडेटा स्टोर को कैश करती है. इन कैश की मदद से Pando किसी कमिट आईडी के अनुरोध या किसी रेफ़ के विशेष रीड को पूरी तरह उस क्लस्टर की कैश की गई स्थिति से पूरा कर सकता है. हम पैकफ़ाइल के अनुरोध Express सर्वरों तक भेजने के लिए संगत हैशिंग का उपयोग करते हैं. कैश में डेटा मिलने की दर 99% से अधिक है.

यह कैश व्यवस्था बेहद ऊँचा थ्रूपुट देती है और क्लाइंट तथा Pando के बीच नेटवर्क की पूरी क्षमता इस्तेमाल कर सकती है. इन पैकफ़ाइल यूआरआई और स्थानीय कैश के साथ हमने पुष्टि की है कि केवल क्लाउड प्रदाता की मानक वर्चुअल मशीनों का उपयोग करके भी क्लोन और फ़ेच संचालन 10 गीगाबिट प्रति सेकंड के नेटवर्क लिंक की पूरी क्षमता इस्तेमाल करते हैं.

समेकन और पहला बाइट मिलने तक का समय

अधिकांश Git सर्वरों में बढ़ती रिपॉज़िटरी का प्रदर्शन बनाए रखने के लिए दोबारा पैकिंग और अनुपयोगी डेटा की सफ़ाई ज़रूरी होती है. इन दोनों चरणों से जगह खाली होती है, लेकिन इनमें बहुत अधिक गणना और इनपुट/आउटपुट संसाधन लगते हैं.

OpenAI के मोनोरेपो जैसी तेज़ी से बदलती रिपॉज़िटरी में पिछले फ़ेच के बाद हुए हर पुश के लिए अलग पैकफ़ाइल यूआरआई भेजना व्यावहारिक नहीं है. ऐसा करने पर क्लाइंट को अपना ट्रंक नवीनतम स्थिति में लाने के लिए रोज़ाना दसियों हज़ार पैकफ़ाइलें डाउनलोड करनी पड़ेंगी.

इसके बजाय, अतिरिक्त काम घटाने के लिए Pando पृष्ठभूमि में पैक जोड़ता है. इसका डिज़ाइन लॉग-संरचित मर्ज-ट्री में समेकन जैसा है. हर पुश एक पैकफ़ाइल बनाता है जिसे Pando “L0” कहता है. यह Pando द्वारा भेजे जा सकने वाले डेटा की सबसे छोटी इकाई है. समय के साथ पृष्ठभूमि वर्कर इन पैकफ़ाइलों को ऐसे कवर समूहों में जोड़ते हैं जो रेफ़ संस्करणों की एक श्रृंखला समेटते हैं और L0 से ज्यामितीय अनुपात में बढ़ते हैं. आज हमारा मोनोरेपो L4 तक के पैकफ़ाइल कवर समूह इस्तेमाल करता है.

ये कवर समूह दो काम करते हैं. कवर समूह पर्याप्त भर जाने पर समेकन वर्कर उसकी ज़िम्मेदारी लेता है और एक ही पैकफ़ाइल बनाता है. इससे पैकफ़ाइल के भीतर ऑब्जेक्ट को दोबारा व्यवस्थित करके संपीड़न अनुपात बेहतर होता है. साथ ही, रेफ़ संस्करणों पर स्किप लिस्ट की तरह काम करके यह फ़ेच के लिए आपसी जानकारी के आदान-प्रदान का प्रदर्शन भी बेहतर करता है. हर स्तर की अनुक्रमणिकाएँ एक साथ जाँचकर Pando क्लाइंट को भेजने के लिए पैक का समूह लघुगणकीय समय में चुन सकता है. ये पैकफ़ाइल कवर समूह, दोबारा पैक किए गए हों या नहीं, फ़ेच की योजना अधिक कुशलता से बनाने देते हैं. इससे Pando के लिए थ्रूपुट और विलंबता, दोनों की आवश्यकताएँ घटती हैं.

Compaction in Pando

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

Compaction in progressPublished cover

समेकन पृष्ठभूमि में कई रेफ़ संस्करणों की पैकफ़ाइलों को जोड़ता है, जिससे कम फ़ाइलों के साथ अधिक कुशल फ़ेच संभव होते हैं.

कई Git सर्वरों के विपरीत, पैकफ़ाइलें हर स्तर पर रखी जाती हैं; उन्हें न हटाया जाता है, न अनुपयोगी मानकर साफ़ किया जाता है. क्लाइंट फ़ेच में जो have और want भेजते हैं, उनके आधार पर हर स्तर के पैक लगातार उन्हें सेवा देने के लिए इस्तेमाल होते हैं. Pando को एपीआई के रूप में इस्तेमाल करने वाले क्लाइंट के लिए पैकफ़ाइल से कोई भी ऑब्जेक्ट पढ़ने में आम तौर पर L4 की तुलना में L0 से कम डेटा पढ़ना पड़ता है, क्योंकि उसके संपीड़ित होने की संभावना कम होती है.

Pando में समेकन क्लाइंट को भेजे जाने वाले कुल डेटा का आकार काफ़ी घटाता है. साथ ही, क्लाइंट जितना पीछे होता है, पैक की योजना बनाने का काम उससे धीमी, उप-रैखिक दर से बढ़ता है. यह खास तौर पर बड़ी और तेज़ी से बदलती रिपॉज़िटरी के लिए अहम है, जिनके सॉफ़्टवेयर विकास में आम हो जाने की हमें उम्मीद है.

Pando का निर्माण

हमने Codex के साथ Pando बनाया और शुरुआत से वास्तविक संचालन तक का सफ़र सिर्फ़ 10 हफ़्तों में पूरा किया. Pando का मूल डिज़ाइन एक ही इंजीनियर ने तैयार किया, एजेंटों की टीमों ने उसे लागू किया और कुछ इंजीनियरों ने उसे तैनात किया. Pando ने इस साल अप्रैल में वास्तविक संचालन के अनुरोध संभालने शुरू किए. यह OpenAI में इस्तेमाल होने वाले स्रोत नियंत्रण प्रबंधन टूल की बड़ी व्यवस्था का एक हिस्सा है.

Pando का डिज़ाइन सत्यापित करने के लिए हमने कई तरह के तरीके अपनाए. हमने सॉफ़्टवेयर की अधिक सुरक्षित नींव बनाने⁠ के अपने सिद्धांत लागू किए. यह पूरी तरह नई परियोजना थी, इसलिए हमने Pando को Rust में और पुरानी निर्भरताओं के बिना बनाने का निर्णय लिया. हमने अनुरूपता जाँचने वाला परीक्षण समूह लिखा, ताकि एजेंट अपने बदलावों को Git के मानक व्यवहार के विरुद्ध जाँच सकें. हमने नियतात्मक अनुकरण परीक्षण हार्नेस भी बनाए, जिनसे प्रणाली के अपरिवर्तनीय नियम और गुण जाँचे जा सकें. इससे आपसी जानकारी के आदान-प्रदान और पैक योजना में सूक्ष्म समवर्ती टकराव तथा पुराने व्यवहार में आई खराबियाँ ढूँढ़ने और कम करने में मदद मिली.

कई मॉडलों ने इस प्रणाली में योगदान दिया. जैसे-जैसे नए मॉडल उपलब्ध हुए, हमने उनसे Pando का प्रदर्शन और विश्वसनीयता बेहतर की. GPT‑6 Astra का उपयोग करके एजेंटों ने Lean और TLA+ में “Pando का सिद्धांत” औपचारिक रूप दिया. इससे हमने कार्यान्वयन की त्रुटियाँ ढूँढ़ीं और ठीक कीं तथा प्रणाली के गुण साबित किए. कई सत्र सैकड़ों घंटों तक लगातार चले और Pando में दुर्लभ सीमांत स्थितियों की समस्याएँ ढूँढ़कर ठीक कीं. हम Daybreak-सक्षम मॉडलों से चौबीसों घंटे एजेंट भी चलाते हैं, जो आक्रामक परीक्षण करके Git और Pando की कमज़ोरियाँ तलाशते हैं.

Pando की तैनाती

शुरुआत में हमने Pando को अपनी मौजूदा स्रोत नियंत्रण प्रणाली के लिए रीड और राइट आगे पहुँचाने वाली प्रॉक्सी के रूप में तैनात किया. इससे Pando और पुरानी प्रणाली में तालमेल बना रहा, और हम बिना सेवा रोके सुरक्षित ढंग से अनुरोध Pando पर ले जा सके.

अपने कैशिंग डिज़ाइन के तहत Pando अनुरोध आगे भेजने से पहले दोहराव हटाकर उन्हें जोड़ भी सकता है. इससे हम एक-एक करके प्रणालियाँ Pando पर लाते समय अपने मौजूदा टूल को सुचारु रख सके. जैसे-जैसे हमने और कार्यभार Pando पर स्थानांतरित किए, उनके पुश ने Pando के कैश को भरा और हमारे पुराने बैकएंड की विश्वसनीयता बेहतर की.

Pando इस्तेमाल करते समय प्रदर्शन बेहतर करने के लिए हमने डेवलपर मशीनों और ChatGPT डेस्कटॉप ऐप में Git का अपना सार्वजनिक वितरण देना शुरू किया. क्लाइंट को चरणों में Pando पर स्थानांतरित करने के लिए हमने Git के कमांड-लाइन इंटरफ़ेस के ऊपर एक आंतरिक रैपर इस्तेमाल किया. हमने बदलाव के अनुरोध और कोड समीक्षा संभालने के लिए कई अन्य टूल तथा स्वचालन के लिए एपीआई बनाए. Git अनुरोधों के साथ हमने पुराने एपीआई, वेबहुक और रिपॉज़िटरी डाउनलोड पर निर्भर सैकड़ों एकीकरण भी स्थानांतरित किए.

Codex ने खुद डेवलपरों और टीमों को यह बदलाव करने में मदद की. हमने मौजूदा चेकआउट तैयार करने और एजेंटों को नई प्रणाली इस्तेमाल करने का मार्गदर्शन देने के लिए कौशल बनाए. इससे डेवलपर केवल Codex से कहकर अपने विकास परिवेश और सेवाएँ स्थानांतरित करा सकते थे.

Pando अपनाने से मर्ज की विश्वसनीयता बढ़ी और पुश विलंबता की माध्यिका लगभग 80% घट गई.

Pando केवल कुछ सीपीयू कोर से रोज़ाना एक पेटाबाइट Git डेटा पहुँचा सकता है. Pando ने एक ही घंटे में 57 टेराबाइट से अधिक Git पैक पहुँचाए हैं, जिनके 99% से अधिक बाइट स्थानीय डिस्क कैश से आए.

पैक का पुनः उपयोग करने से कई क्लाइंट रिपॉज़िटरी का एक ही इतिहास डाउनलोड कर सकते हैं, जबकि सेवा देने वाले नोड पर बहुत कम गणना होती है. यह उदाहरण एक रिपॉज़िटरी का है, लेकिन Pando कई और रिपॉज़िटरी संभालने के लिए बनाया गया है. माँग बढ़ने पर हम डेटा पहुँचाने और Git की आपसी जानकारी के आदान-प्रदान की क्षमता अलग-अलग बढ़ा सकते हैं.

Git परियोजना को योगदान देना

Git प्रोटोकॉल और क्लाइंट पर Pando बनाने से हमें Git की अपनी त्रुटियाँ और उसका प्रदर्शन सुधारने के अवसर पहचानने में मदद मिली.

मिसाल के लिए, Pando पुनः उपयोग योग्य पैक सीधे क्लाइंट को देता है. इसलिए उन पैक को डाउनलोड करना और अनुक्रमित करना प्रणाली को तेज़ और विश्वसनीय बनाने का अहम हिस्सा बन गया. इस काम से समवर्ती डाउनलोड, बीच में रुके स्थानांतरण के बाद सफ़ाई और पहले ही पूरे हो चुके डाउनलोड दोबारा शुरू करने की सीमांत स्थितियाँ सामने आईं. हमने उन प्रक्रियाओं को ठीक किया, फ़ेच के लिए मौजूदा पैक स्वीकार करते समय सत्यापन जोड़े और यह काम मूल परियोजना में योगदान के रूप में दिया.

हमें यह भी देखना था कि समय और बैंडविड्थ कहाँ खर्च हो रहे हैं. इसलिए हमने packfile-uri डाउनलोड की ट्रेसिंग और पैक निर्माण के बाइट की गिनती जोड़ी. इससे पता लगाना आसान हुआ कि धीमे फ़ेच में समय पैक बनाने में लग रहा है या उन्हें भेजने में.

OpenAI के Git बिल्ड⁠(एक नई विंडो में खुलेगा) में क्लाइंट स्वतंत्र पैक समानांतर डाउनलोड और अनुक्रमित कर सकता है. हमने “स्पष्ट रूप से बताए गए मौजूद कमिट” की अवधारणा जोड़ी, ताकि सर्वर ब्रांच का वर्तमान शीर्ष कमिट उस इतिहास से अलग घोषित कर सके जिसे पुश करने वाला क्लाइंट अपने पैक से बाहर रख सकता है. Pando पर इससे क्लाइंट --force-with-lease का उपयोग करके जाँच सकते हैं कि फ़ीचर ब्रांच बदली नहीं है और केवल ट्रंक के आधार पर उसका पैक बना सकते हैं. फिर उस ट्रंक इतिहास वाला कोई भी क्लाइंट उसी पैक से ब्रांच फ़ेच कर सकता है.

इनमें से कई सुधार मूल Git में पहले से शामिल हैं और कई अन्य हमारी सार्वजनिक रिपॉज़िटरी में हैं. हम Git समुदाय के साथ काम जारी रखे हुए हैं, ताकि ये सुधार Pando के बाहर भी उपयोगी हों. आप हमारे सार्वजनिक पैच ट्रैकर⁠(एक नई विंडो में खुलेगा) में इस काम की प्रगति देख सकते हैं.

आगे की राह

Git रिपॉज़िटरी की क्षमता बढ़ाने की पारंपरिक सोच पर नए सिरे से विचार करके, Pando हमें अपने मोनोरेपो की क्षमता बढ़ाने देता है. इसके लिए हमारे इंजीनियरों और एजेंटों के मौजूदा Git कार्यप्रवाह बदलने की ज़रूरत नहीं पड़ती. हमारे मोनोरेपो में Pando ने अधिक काम समानांतर करना संभव बनाया है, मर्ज की विश्वसनीयता बढ़ाई है और कोड बदलाव प्रकाशित करने में लगने वाला समय घटाया है. मोनोरेपो के अलावा हम OpenAI में Pando के अन्य उपयोग भी तलाश रहे हैं. इनमें ऐसे कार्यभार शामिल हैं जहाँ बड़ी संख्या में एजेंटों को साझा Git रिपॉज़िटरी पर सहयोग करना होता है.

जैसे-जैसे इंजीनियर और एजेंट अधिक सॉफ़्टवेयर बनाएँगे, OpenAI के बाहर भी अधिक टीमें स्रोत नियंत्रण की उन सीमाओं से टकराएँगी जिनका हमने सामना किया. हम फ़िलहाल Pando को संभव बनाने वाली तकनीक अपने उपयोगकर्ताओं के साथ साझा करने के तरीके तलाश रहे हैं.

Pando Git रिपॉज़िटरी के उपयोगकर्ताओं और संचालकों के दो दशकों के अनुभव पर आधारित है. हम Pando का विकास जारी रखेंगे और मुक्त-स्रोत Git समुदाय के साथ मिलकर ऐसे सुधार साझा करेंगे जिनसे व्यापक रूप से Git उपयोगकर्ताओं को लाभ हो.

लेखक

OpenAI