डिस्ट्रिब्यूट किए गए बिल्ड

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

रिमोट कैशिंग

डिस्ट्रिब्यूटेड बिल्ड का सबसे आसान तरीका वह है जो सिर्फ़ रिमोट कैश मेमोरी का इस्तेमाल करता है, जैसा कि पहली इमेज में दिखाया गया है.

रिमोट कैशिंग के साथ डिस्ट्रिब्यूट किया गया बिल्ड

पहला डायग्राम. डिस्ट्रिब्यूटेड बिल्ड, जिसमें रिमोट कैश मेमोरी को दिखाया गया है

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

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

बेशक, रिमोट कैश से फ़ायदा पाने के लिए ज़रूरी है कि आर्टफ़ैक्ट डाउनलोड करने की प्रोसेस उसे बनाने से ज़्यादा तेज़ हो. हमेशा ऐसा नहीं होता, खास तौर पर तब, जब कैश सर्वर उस मशीन से दूर हो जो बिल्ड कर रहा हो. बिल्ड के नतीजों को तेज़ी से शेयर करने के लिए, Google के नेटवर्क और बिल्ड सिस्टम को ध्यान से तैयार किया जाता है.

रिमोट तरीके से एक्ज़ीक्यूशन

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

रिमोट एक्ज़ीक्यूशन सिस्टम

दूसरा डायग्राम. रिमोट एक्ज़ीक्यूशन सिस्टम

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

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

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

Google पर डिस्ट्रिब्यूट किए गए बिल्ड

साल 2008 से, Google एक डिस्ट्रिब्यूटेड बिल्ड सिस्टम का इस्तेमाल कर रहा है, जिसमें रिमोट कैशिंग और रिमोट एक्ज़ीक्यूशन, दोनों का इस्तेमाल किया जाता है. इसे तीसरी इमेज में दिखाया गया है.

हाई-लेवल बिल्ड सिस्टम

तीसरी इमेज. Google का डिस्ट्रिब्यूटेड बिल्ड सिस्टम

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

Google के रिमोट तौर पर एक्ज़ीक्यूशन सिस्टम को Forge कहा जाता है. ब्लेज़ में एक फ़ॉर्ज क्लाइंट (Bazel की अंदरूनी क्षमता) जिसे डिस्ट्रिब्यूटर कहते हैं, हर कार्रवाई के लिए अनुरोध हमारे डेटासेंटर में चल रहे शेड्यूलर को भेजता है. शेड्यूलर, कार्रवाई के नतीजों को कैश मेमोरी में सेव रखता है. इससे, अगर सिस्टम के किसी दूसरे उपयोगकर्ता ने कार्रवाई पहले ही बना ली है, तो यह तुरंत जवाब दे सकता है. अगर नहीं, तो यह कार्रवाई को सूची में बना देता है. एक्ज़ीक्यूटर जॉब का एक बड़ा पूल इस सूची से कार्रवाइयों को लगातार पढ़ता है, उन्हें एक्ज़ीक्यूट करता है, और नतीजों को सीधेobjFS Bigtables में सेव करता है. ये नतीजे, एक्ज़ीक्यूटर को आगे की कार्रवाइयों के लिए दिख सकते हैं या इन्हें असली उपयोगकर्ता, objfsd से डाउनलोड कर सकता है.

आखिरी नतीजा एक ऐसा सिस्टम है जो Google में काम करने वाले सभी बिल्ड के साथ बेहतर तरीके से काम करता है. Google के बिल्ड का पैमाना बहुत बड़ा है: Google हर दिन करोड़ों टेस्ट केस का इस्तेमाल करके लाखों टेस्ट केस अंजाम देता है और सोर्स कोड की करोड़ों लाइन से आउटपुट के रूप में पेटाबाइट बनाता है. इस तरह के सिस्टम से, हमारे इंजीनियर न सिर्फ़ तेज़ी से कॉम्प्लेक्स कोडबेस बना पाते हैं, बल्कि बड़ी संख्या में ऑटोमेटेड टूल और सिस्टम लागू भी कर पाते हैं, जो हमारे बिल्ड पर निर्भर होते हैं.