जब आपके पास बड़ा कोड बेस होता है, तो डिपेंडेंसी की चेन बहुत गहरी हो सकती है. आम तौर पर, आसान बाइनरी भी 10 हज़ार बिल्ड टारगेट पर निर्भर हो सकती हैं. इतने बड़े स्तर पर, एक मशीन पर तय समय में बिल्ड पूरा करना नामुमकिन है. कोई बिल्ड सिस्टम, मशीन के हार्डवेयर पर लगाए गए फ़िज़िक्स के बुनियादी नियमों से मेल नहीं खा सकता. यह काम सिर्फ़ एक बिल्ड सिस्टम के साथ किया जा सकता है जो डिस्ट्रिब्यूटेड बिल्ड के साथ काम करता है. इसमें सिस्टम की ओर से किए जा रहे काम की यूनिट, एक ऐसी मशीन पर होती हैं जिसे मनमुताबिक और बड़ा किया जा सकता है. मान लें कि हमने सिस्टम के काम को छोटी-छोटी यूनिट में बांट दिया है (इस बारे में बाद में ज़्यादा जानकारी दी जाएगी). इससे, हम किसी भी साइज़ का बिल्ड उतनी ही जल्दी पूरा कर पाएंगे जितना जल्दी हम इसके लिए पैसे चुकाने को तैयार हैं. हम आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम को तय करके, इस स्केलेबिलिटी पर काम कर रहे हैं.
रिमोट कैश मेमोरी
डिस्ट्रिब्यूटेड बिल्ड का सबसे आसान टाइप वह है जो सिर्फ़ रिमोट कैश मेमोरी का फ़ायदा उठाता है. इसे पहली इमेज में दिखाया गया है.
पहली इमेज. रिमोट कैश मेमोरी में सेव करने की सुविधा दिखाने वाला डिस्ट्रिब्यूट किया गया बिल्ड
डेवलपर वर्कस्टेशन और निरंतर इंटिग्रेशन सिस्टम, दोनों में मौजूद हर सिस्टम, एक ही रिमोट कैश मेमोरी सेवा का रेफ़रंस शेयर करता है. यह सेवा, Redis जैसा तेज़ और लोकल स्टोरेज सिस्टम हो सकता है या Google Cloud Storage जैसी क्लाउड सेवा हो सकती है. जब भी किसी उपयोगकर्ता को सीधे तौर पर या किसी डिपेंडेंसी के तौर पर कोई आर्टफ़ैक्ट बनाना होता है, तो सिस्टम सबसे पहले रिमोट कैश की मदद से यह देखता है कि वह आर्टफ़ैक्ट वहां पहले से मौजूद है या नहीं. अगर ऐसा है, तो वह आर्टफ़ैक्ट बनाने के बजाय, उसे डाउनलोड कर सकता है. अगर ऐसा नहीं होता है, तो सिस्टम खुद आर्टफ़ैक्ट बनाता है और नतीजे को कैश मेमोरी में वापस अपलोड करता है. इसका मतलब है कि अक्सर न बदलने वाली लो-लेवल डिपेंडेंसी को एक बार बनाया जा सकता है और सभी उपयोगकर्ताओं के साथ शेयर किया जा सकता है. इसके बजाय, हर उपयोगकर्ता को इसे फिर से बनाना पड़ता है. Google पर, कई आर्टफ़ैक्ट को फिर से बनाने के बजाय, कैश मेमोरी से दिखाया जाता है. इससे हमारे बिल्ड सिस्टम को चलाने की लागत काफ़ी कम हो जाती है.
रिमोट कैश मेमोरी सिस्टम के काम करने के लिए, बिल्ड सिस्टम को यह पक्का करना होगा कि बिल्ड को फिर से बनाया जा सकता है. इसका मतलब है कि किसी भी बिल्ड टारगेट के लिए, उस टारगेट के इनपुट सेट को तय करना संभव होना चाहिए, ताकि किसी भी मशीन पर एक ही इनपुट सेट से एक ही आउटपुट मिले. यह पक्का करने का सिर्फ़ एक तरीका है कि किसी आर्टफ़ैक्ट को डाउनलोड करने के नतीजे, उसे खुद बनाने के नतीजों से मेल खाते हैं. ध्यान दें कि इसके लिए यह ज़रूरी है कि कैश मेमोरी में मौजूद हर आर्टफ़ैक्ट को उसके टारगेट और उसके इनपुट हैश, दोनों पर रखा जाए. इस तरह, अलग-अलग इंजीनियर एक ही टारगेट में एक ही समय में अलग-अलग बदलाव कर सकते हैं. साथ ही, रिमोट कैश मेमोरी उन सभी आर्टफ़ैक्ट को सेव करेगी और उन्हें बिना किसी टकराव के सही तरीके से सेव करेगी.
बेशक, रिमोट कैश मेमोरी से कोई फ़ायदा पाने के लिए, आर्टफ़ैक्ट को बनाने के मुकाबले डाउनलोड करने में कम समय लगना चाहिए. हालांकि, ऐसा हमेशा नहीं होता. खास तौर पर, अगर कैश मेमोरी सर्वर, बिल्ड करने वाली मशीन से दूर है. Google के नेटवर्क और बिल्ड सिस्टम को ध्यान से ट्यून किया गया है, ताकि बिल्ड के नतीजे तुरंत शेयर किए जा सकें.
रिमोट से चलाना
रिमोट कैश मेमोरी, डिस्ट्रिब्यूटेड बिल्ड नहीं है. अगर कैश मेमोरी मिट जाती है या कोई ऐसा बदलाव किया जाता है जिसकी वजह से पूरी प्रोसेस को फिर से शुरू करना पड़ता है, तो भी आपको अपनी मशीन पर पूरी प्रोसेस को फिर से शुरू करना होगा. सही लक्ष्य रिमोट तरीके से काम करने की सुविधा देना है, जिसमें बिल्ड करने का काम किसी भी तरह के वर्कर के बीच फैलाया जा सकता है. दूसरी इमेज में रिमोट एक्ज़ीक्यूशन सिस्टम दिखाया गया है.
दूसरी इमेज. रिमोट एक्ज़ीक्यूशन सिस्टम
हर उपयोगकर्ता की मशीन पर चलने वाला बिल्ड टूल (जहां उपयोगकर्ता, इंजीनियर या ऑटोमेटेड बिल्ड सिस्टम होते हैं), एक सेंट्रल बिल्ड मास्टर को रिक्वेस्ट भेजता है. बिल्ड मास्टर, अनुरोधों को कॉम्पोनेंट कार्रवाइयों में बांटता है और उन कार्रवाइयों को, वर्कर के बढ़ाने लायक पूल पर शेड्यूल करता है. हर वर्कर्स, उपयोगकर्ता के दिए गए इनपुट के हिसाब से कार्रवाइयां करता है और नतीजे के तौर पर आर्टफ़ैक्ट लिखता है. ये आर्टफ़ैक्ट, उन सभी मशीनों के साथ शेयर किए जाते हैं जिन पर ऐसी कार्रवाइयां की जा रही हैं जिनमें इन आर्टफ़ैक्ट की ज़रूरत होती है. ऐसा तब तक किया जाता है, जब तक कि आखिरी आउटपुट तैयार नहीं हो जाता और उपयोगकर्ता को भेजा नहीं जाता.
इस तरह के सिस्टम को लागू करने में सबसे मुश्किल काम, वर्कर्स, मास्टर्स, और उपयोगकर्ता की लोकल मशीन के बीच कम्यूनिकेशन मैनेज करना होता है. हो सकता है कि वर्कर्स, दूसरे वर्कर्स के बनाए गए इंटरमीडिएट आर्टफ़ैक्ट पर निर्भर हों. साथ ही, फ़ाइनल आउटपुट को उपयोगकर्ता की लोकल मशीन पर वापस भेजना ज़रूरी हो. इसके लिए, हम पहले बताए गए डिस्ट्रिब्यूटेड कैश के ऊपर, एक नया कैश बना सकते हैं. इसके लिए, हर वर्कर्स को अपने नतीजे कैश में लिखने और अपनी डिपेंडेंसी पढ़ने की अनुमति देनी होगी. मास्टर उसे तब तक आगे बढ़ने से रोकता है, जब तक कि वह जिस चीज़ पर निर्भर है, वह पूरी नहीं हो जाती. इस स्थिति में वे कैश मेमोरी से अपने इनपुट पढ़ सकेंगे. फ़ाइनल प्रॉडक्ट को भी कैश मेमोरी में सेव किया जाता है, ताकि लोकल मशीन उसे डाउनलोड कर सके. ध्यान दें कि हमें उपयोगकर्ता के सोर्स ट्री में किए गए स्थानीय बदलावों को एक्सपोर्ट करने के लिए, एक अलग तरीके की भी ज़रूरत है, ताकि वर्कर्स, बिल्ड करने से पहले उन बदलावों को लागू कर सकें.
इसके लिए, पहले बताए गए आर्टफ़ैक्ट पर आधारित बिल्ड सिस्टम के सभी हिस्सों को एक साथ काम करना होगा. बिल्ड एनवायरमेंट के बारे में पूरी जानकारी होनी चाहिए, ताकि हम बिना किसी मानवीय हस्तक्षेप के वर्कर्स को स्पिन अप कर सकें. बिल्ड प्रोसेस पूरी तरह से अपने-आप काम करनी चाहिए, क्योंकि हर चरण को किसी अलग मशीन पर चलाया जा सकता है. आउटपुट पूरी तरह से तय होने चाहिए, ताकि हर वर्कर दूसरे वर्कर से मिले नतीजों पर भरोसा कर सके. टास्क पर आधारित सिस्टम के लिए, ऐसी गारंटी देना काफ़ी मुश्किल होता है. इसलिए, एक के ऊपर भरोसेमंद रिमोट एक्सीक्यूशन सिस्टम बनाना काफ़ी मुश्किल होता है.
Google पर डिस्ट्रिब्यूट किए गए बिल्ड
Google, साल 2008 से डिस्ट्रिब्यूटेड बिल्ड सिस्टम का इस्तेमाल कर रहा है. इसमें रिमोट कैश मेमोरी और रिमोट एक्ज़ीक्यूशन, दोनों का इस्तेमाल किया जा रहा है. इस सिस्टम की इमेज 3 में दी गई है.
तीसरी इमेज. Google का डिस्ट्रिब्यूटेड बिल्ड सिस्टम
Google के रिमोट कैश मेमोरी को ObjFS कहा जाता है. इसमें एक बैकएंड होता है, जो बिगटेबल में बिल्ड आउटपुट को सेव करता है. ये आउटपुट, हमारी सभी प्रोडक्शन मशीनों पर डिस्ट्रिब्यूट किए जाते हैं. साथ ही, इसमें एक फ़्रंटएंड FUSE डेमन होता है, जिसका नाम objfsd होता है. यह हर डेवलपर की मशीन पर चलता है. FUSE डेमन की मदद से, इंजीनियर, बिल्ड आउटपुट को ऐसे ब्राउज़ कर सकते हैं जैसे वे वर्कस्टेशन पर सेव की गई सामान्य फ़ाइलें हों. हालांकि, फ़ाइल का कॉन्टेंट सिर्फ़ उन कुछ फ़ाइलों के लिए मांग पर डाउनलोड किया जाता है जिनका अनुरोध उपयोगकर्ता ने सीधे तौर पर किया हो. मांग पर फ़ाइल का कॉन्टेंट दिखाने की सुविधा, नेटवर्क और डिस्क के इस्तेमाल की संख्या को काफ़ी कम कर देती है. साथ ही, डेवलपर की लोकल डिस्क में सेव किए गए सभी आउटपुट आउटपुट की तुलना में, सिस्टम दोगुनी तेज़ी से फ़ाइल बना पाता है.
Google के रिमोट एक्ज़ीक्यूशन सिस्टम को Forge कहा जाता है. ब्लेज़ में एक फ़ोर्ज क्लाइंट (Baज़ल का इंटरनल मिलता-जुलता), जिसे डिस्ट्रिब्यूटर कहते हैं वह हमारे डेटासेंटर में चल रही हर कार्रवाई के लिए अनुरोध भेजता है. इस काम को शेड्यूलर कहा जाता है. शेड्यूलर, कार्रवाई के नतीजों की कैश मेमोरी को बनाए रखता है. इससे, अगर कार्रवाई को सिस्टम के किसी दूसरे उपयोगकर्ता ने पहले ही किया जा चुका है, तो उसे तुरंत रिस्पॉन्स मिलने की सुविधा मिलती है. अगर नहीं, तो यह कार्रवाई को सूची में डाल देता है. एक्ज़िक्यूटर जॉब का एक बड़ा पूल इस सूची की कार्रवाइयों को लगातार पढ़ता है, उन्हें लागू करता है, और नतीजों को सीधे ObjFS Bigtables में सेव करता है. ये नतीजे, प्रोजेक्ट पर काम करने वाले लोगों के लिए उपलब्ध हैं. इन्हें आने वाले समय में की जाने वाली कार्रवाइयों के लिए इस्तेमाल किया जा सकता है या असली उपयोगकर्ता इन्हें objfsd की मदद से डाउनलोड भी कर सकता है.
इसका नतीजा एक ऐसा सिस्टम है जो Google पर किए जाने वाले सभी बिल्ड के साथ बेहतर तरीके से काम करता है. Google के बिल्ड का स्केल बहुत बड़ा है: Google, लाखों टेस्ट केस को पूरा करने के लिए लाखों बिल्ड चलाता है. साथ ही, हर दिन सोर्स कोड की अरबों लाइनों से, बिल्ड के पेटाबाइट आउटपुट जनरेट करता है. इस तरह के सिस्टम से न सिर्फ़ हमारे इंजीनियर, तेज़ी से कॉम्प्लेक्स कोड बेस बना पाते हैं, बल्कि हम बड़ी संख्या में ऑटोमेटेड टूल और सिस्टम भी बना पाते हैं. ये ऐसे टूल और सिस्टम होते हैं जो हमारे बिल्ड पर निर्भर होते हैं.