इस पेज पर बताया गया है कि लगातार काम करने वाले कर्मचारियों का इस्तेमाल कैसे करें, उनको मिलने वाले फ़ायदे कैसे, ज़रूरी शर्तें, और वे सैंडबॉक्सिंग पर किस तरह असर डालते हैं.
लगातार काम करने वाला कर्मचारी, बेज़ल सर्वर से शुरू की जाने वाली एक लंबे समय तक चलने वाली प्रोसेस है. यह असल टूल (आम तौर पर, कंपाइलर) के आस-पास रैपर के तौर पर काम करती है या खुद टूल होती है. लगातार काम करने वाले लोगों का फ़ायदा उठाने के लिए, टूल को
कंपाइलेशन का क्रम काम करना चाहिए. साथ ही, रैपर को टूल के एपीआई और नीचे बताए गए अनुरोध/जवाब फ़ॉर्मैट के बीच अनुवाद करना चाहिए. एक ही बिल्ड में --persistent_worker
फ़्लैग के साथ और उसके बिना भी एक ही वर्कर को कॉल किया जा सकता है और वह टूल को सही तरीके से शुरू करने, उससे बात करने के साथ-साथ बाहर निकलने पर काम करने वाले लोगों को बंद करने के लिए ज़िम्मेदार होता है. हर वर्कर इंस्टेंस को <outputBase>/bazel-workers
के तहत अलग से काम करने वाली डायरेक्ट्री असाइन की जाती है (हालांकि, इसमें बदलाव नहीं किया जाता).
लगातार काम करने वाले लोगों का इस्तेमाल करना, एक्ज़िक्यूशन की रणनीति है, जो स्टार्ट-अप ओवरहेड को कम करती है, ज़्यादा JIT कंपाइलेशन की अनुमति देती है, और ऐक्शन एक्ज़ीक्यूशन के दौरान ऐब्सट्रैक्ट सिंटैक्स ट्री को कैश मेमोरी में सेव करने की सुविधा देती है. इस रणनीति से, लंबे समय तक चलने वाली प्रोसेस के लिए कई अनुरोध भेजने पर, इन सुधारों को लागू किया जा सकता है.
स्थायी कर्मचारियों को कई भाषाओं के लिए लागू किया जाता है. इनमें Java, Scala, Kotlin वगैरह शामिल हैं.
NodeJS रनटाइम का इस्तेमाल करने वाले प्रोग्राम, वर्कर प्रोटोकॉल को लागू करने के लिए, @bazel/worker हेल्पर लाइब्रेरी का इस्तेमाल कर सकते हैं.
स्थायी कर्मचारियों का इस्तेमाल करना
Basel 0.27 और उसके बाद के वर्शन, बिल्ड को एक्ज़ीक्यूट करते समय डिफ़ॉल्ट रूप से परसिस्टेंट वर्कर का इस्तेमाल करते हैं. हालांकि, रिमोट एक्ज़ीक्यूशन को प्राथमिकता दी जाती है. जिन कार्रवाइयों के लिए लगातार काम करने वाले लोग काम नहीं करते उनके लिए,
बेज़ल हर कार्रवाई के लिए टूल इंस्टेंस शुरू कर देता है. स्थायी कर्मचारियों का इस्तेमाल करने के लिए, लागू टूल के लिए worker
रणनीति सेट करके, बिल्ड को साफ़ तौर पर सेट किया जा सकता है. सबसे सही तरीके के तौर पर, इस उदाहरण में worker
रणनीति के फ़ॉलबैक के तौर पर local
तय करना शामिल है:
bazel build //my:target --strategy=Javac=worker,local
स्थानीय रणनीति के बजाय कर्मचारियों की रणनीति का इस्तेमाल करने से, कंपाइलेशन स्पीड काफ़ी तेज़ी से बढ़ सकती है. यह सुविधा लागू करने के तरीके पर निर्भर करती है. Java के लिए, बिल्ड 2 से 4 गुना तेज़ हो सकते हैं. कभी-कभी ज़्यादा तेज़ी से कंपाइलेशन करने के लिए ये काम कर सकते हैं. बेज़ेल को कंपाइल करना श्रमों की तुलना में करीब 2.5 गुना तेज़ है. ज़्यादा जानकारी के लिए, "कर्मचारियों की संख्या चुनना" सेक्शन देखें.
अगर आपके पास ऐसा रिमोट बिल्ड एनवायरमेंट भी है जो आपके लोकल बिल्ड एनवायरमेंट से मेल खाता है, तो एक्सपेरिमेंट के तौर पर शुरू की गई डाइनैमिक रणनीति का इस्तेमाल किया जा सकता है. इससे, रिमोट तरीके से एक्ज़ीक्यूट करने और वर्कर को एक्ज़ीक्यूट करने की सुविधा मिल जाती है. डाइनैमिक रणनीति को चालू करने के लिए, --experimental_spawn_scheduler
फ़्लैग को पास करें. इस रणनीति से कर्मियों को अपने-आप चालू किया जाता है. इसलिए, worker
रणनीति बताने की ज़रूरत नहीं है. हालांकि, local
या sandboxed
का इस्तेमाल अब भी फ़ॉलबैक के तौर पर किया जा सकता है.
कर्मचारियों की संख्या चुनना
डिफ़ॉल्ट रूप से, हर याद में काम करने वाले व्यक्ति के इंस्टेंस की संख्या चार है, लेकिन worker_max_instances
फ़्लैग की मदद से इसे बदला जा सकता है. उपलब्ध सीपीयू (CPU) का सही इस्तेमाल करने और आपको मिलने वाले JIT कंपाइलेशन और कैश हिट
की संख्या के बीच एक समझौता है. ज़्यादा कर्मचारियों के होने पर,
ज़्यादा टारगेट को, गैर-JITed कोड को चलाने और कैश मेमोरी में सेव होने की लागत चुकानी होगी. अगर आपको कम संख्या में टारगेट बनाने हैं, तो एक ही कर्मचारी को कंपाइलेशन की स्पीड और रिसॉर्स के इस्तेमाल के बीच सबसे अच्छा विकल्प मिल सकता है. उदाहरण के लिए, समस्या #8586 देखें.
worker_max_instances
फ़्लैग हर स्मरण या फ़्लैग सेट (नीचे देखें) के लिए, वर्कर इंस्टेंस की ज़्यादा से ज़्यादा संख्या सेट करता है. इसलिए, अगर डिफ़ॉल्ट वैल्यू को रखा जाए, तो मिले-जुले सिस्टम में बहुत ज़्यादा मेमोरी का इस्तेमाल किया जा सकता है. इंक्रीमेंटल बिल्ड के लिए
कई कर्मचारियों के इंस्टेंस से मिलने वाला फ़ायदा, इससे भी कम होता है.
यह ग्राफ़ 64 जीबी रैम वाले 6-कोर हाइपर-थ्रेड वाले Intel Xeon 3.5 गीगाहर्ट्ज़ Linux वर्कस्टेशन पर, बेज़ल (टारगेट
//src:bazel
) के शुरू होने से शुरू होने वाले कंपाइलेशन समय को दिखाता है. हर वर्कर कॉन्फ़िगरेशन के लिए, पांच क्लीन बिल्ड चलाए जाते हैं और
आखिरी चार का औसत निकाला जाता है.
पहला डायग्राम. क्लीन बिल्ड के परफ़ॉर्मेंस में सुधार का ग्राफ़.
इस कॉन्फ़िगरेशन के लिए, दो वर्कर सबसे तेज़ कंपाइलेशन देते हैं. हालांकि, एक वर्कर की तुलना में सिर्फ़ 14% सुधार होता है. अगर आपको कम मेमोरी इस्तेमाल करनी है, तो एक कर्मचारी अच्छा विकल्प है.
आम तौर पर, इंक्रीमेंटल कंपाइलेशन के ज़्यादा फ़ायदे मिलते हैं. क्लीन बिल्ड बहुत कम ही होते हैं, लेकिन कंपाइलेशन के बीच एक फ़ाइल में बदलाव करना आम बात है. खास तौर पर, टेस्ट-ड्रिवन डेवलपमेंट में. ऊपर दिए गए उदाहरण में गैर-Java पैकेजिंग से जुड़ी कुछ कार्रवाइयां भी हैं जो बढ़ते हुए कंपाइल होने के समय को पीछे छोड़ सकती हैं.
AbstractContainerizingSandboxedSpawn.java में इंटरनल स्ट्रिंग को बदलने के बाद सिर्फ़ Java सोर्स को फिर से कंपाइल करने से स्पीड तीन गुना बढ़ जाती है (एक वॉर्मअप बिल्ड के बिना, औसतन 20 इंक्रीमेंटल बिल्ड
अस्वीकार किए गए)://src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar
दूसरा डायग्राम. इंक्रीमेंटल बिल्ड के परफ़ॉर्मेंस में सुधार का ग्राफ़.
स्पीड अप बदलाव, किए गए बदलाव पर निर्भर करता है. ऊपर दी गई स्थिति में, फ़ैक्टर 6 की स्पीड-अप का आकलन तब किया जाता है, जब आम तौर पर इस्तेमाल होने वाले कॉन्स्टेंट में बदलाव किया जाता है.
स्थायी कर्मचारियों में बदलाव करना
आप काम करने वाले लोगों को स्टार्ट-अप फ़्लैग बताने के लिए, --worker_extra_flag
फ़्लैग पास कर सकते हैं. इन फ़्लैग की पहचान याद रखने के लिए ज़रूरी होती है. उदाहरण के लिए,
--worker_extra_flag=javac=--debug
पास करना सिर्फ़ Javac के लिए डीबग करना चालू करता है.
इस झंडे के इस्तेमाल के लिए सिर्फ़ एक वर्कर फ़्लैग सेट किया जा सकता है.
हर याद के लिए काम करने वाले लोगों को न सिर्फ़ अलग-अलग बनाया जाता है, बल्कि उनके स्टार्ट-अप फ़्लैग की अलग-अलग चीज़ों के लिए भी बनाया जाता है. स्मोनेनिक और स्टार्ट-अप फ़्लैग का हर कॉम्बिनेशन एक WorkerKey
में जोड़ा जाता है. साथ ही, हर WorkerKey
के लिए, ज़्यादा से ज़्यादा worker_max_instances
वर्कर बनाए जा सकते हैं. अगला सेक्शन देखें और जानें कि ऐक्शन
कॉन्फ़िगरेशन, सेट-अप फ़्लैग कैसे तय कर सकता है.
--high_priority_workers
फ़्लैग का इस्तेमाल करके, याद रखने के लिए इस्तेमाल किए जाने वाले ऐसे नोट के बारे में बताया जा सकता है जिसे आम तौर पर इस्तेमाल की जाने वाली याददाश्त के मुकाबले प्राथमिकता से चलाया जाना चाहिए. इससे उन कार्रवाइयों को प्राथमिकता देने में मदद मिल सकती है
जो हमेशा क्रिटिकल पाथ में होती हैं. अगर ज़्यादा प्राथमिकता वाले दो या उससे ज़्यादा वर्कर अनुरोधों पर कार्रवाई करते हैं, तो दूसरे सभी वर्कर को चलने से रोक दिया जाता है. इस फ़्लैग का इस्तेमाल एक से ज़्यादा बार किया जा सकता है.
--worker_sandboxing
फ़्लैग को पास करने से, हर वर्कर का अनुरोध, अपने सभी इनपुट के लिए एक अलग सैंडबॉक्स डायरेक्ट्री का
इस्तेमाल करता है. sandbox सेट अप करने में, ज़्यादा समय लगता है. खास तौर पर, macOS पर इससे समय लगता है. हालांकि, इससे गेम के सही होने की गारंटी ज़्यादा मिलती है.
--worker_quit_after_build
फ़्लैग का इस्तेमाल मुख्य रूप से, डीबग करने और प्रोफ़ाइल बनाने के लिए किया जाता है. बिल्ड पूरा होने के बाद, यह फ़्लैग सभी कामगारों को बंद करने के लिए मजबूर करता है. कर्मचारी क्या कर रहे हैं, इस बारे में ज़्यादा आउटपुट पाने के लिए --worker_verbose
पास करें. यह फ़्लैग, WorkRequest
में verbosity
फ़ील्ड में दिखता है. इससे वर्कर को लागू करने के बारे में ज़्यादा जानकारी मिलती है.
वर्कर, अपने लॉग <outputBase>/bazel-workers
डायरेक्ट्री में सेव करते हैं, जैसे कि /tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log
.
फ़ाइल के नाम में वर्कर आईडी और मेनेमोनिक, दोनों शामिल हैं. हर याद में एक से ज़्यादा WorkerKey
हो सकते हैं. इसलिए, आपको किसी स्मरणिक याद के लिए worker_max_instances
से ज़्यादा लॉग फ़ाइलें दिख सकती हैं.
Android बिल्ड के बारे में जानकारी के लिए, Android बिल्ड परफ़ॉर्मेंस पेज पर जाएं.
स्थायी कर्मचारियों को लागू करना
कर्मचारी बनाने के तरीके के बारे में ज़्यादा जानकारी के लिए, परसिस्टेंट वर्कर बनाना पेज देखें.
यह उदाहरण, JSON का इस्तेमाल करने वाले वर्कर के लिए Starlark कॉन्फ़िगरेशन दिखाता है:
args_file = ctx.actions.declare_file(ctx.label.name + "_args_file")
ctx.actions.write(
output = args_file,
content = "\n".join(["-g", "-source", "1.5"] + ctx.files.srcs),
)
ctx.actions.run(
mnemonic = "SomeCompiler",
executable = "bin/some_compiler_wrapper",
inputs = inputs,
outputs = outputs,
arguments = [ "-max_mem=4G", "@%s" % args_file.path],
execution_requirements = {
"supports-workers" : "1", "requires-worker-protocol" : "json" }
)
इस परिभाषा के बाद, पहली बार इस कार्रवाई का इस्तेमाल कमांड लाइन /bin/some_compiler -max_mem=4G --persistent_worker
को लागू करने से होगा. इसके बाद, Foo.java
को कंपाइल करने का अनुरोध कुछ ऐसा दिखेगा:
ध्यान दें: प्रोटोकॉल बफ़र स्पेसिफ़िकेशन में "स्नेक केस" (request_id
) का इस्तेमाल किया जाता है. हालांकि, JSON प्रोटोकॉल में "कैमल केस" (requestId
) का इस्तेमाल किया जाता है. इस दस्तावेज़ में, हम JSON के उदाहरणों में कैमल केस का इस्तेमाल करेंगे. हालांकि, फ़ील्ड के बारे में बात करते समय स्नेक केस का इस्तेमाल किया जाएगा, भले ही प्रोटोकॉल कोई भी हो.
{
"arguments": [ "-g", "-source", "1.5", "Foo.java" ]
"inputs": [
{ "path": "symlinkfarm/input1", "digest": "d49a..." },
{ "path": "symlinkfarm/input2", "digest": "093d..." },
],
}
वर्कर को यह stdin
पर, न्यूलाइन-डीलिमिटेड JSON फ़ॉर्मैट में मिलता है (क्योंकि
requires-worker-protocol
को JSON पर सेट किया गया है). इसके बाद, वर्कर ऐक्शन को पूरा करता है और अपने stdout पर बेज़ल को JSON फ़ॉर्मैट में, WorkResponse
भेजता है. इसके बाद, Basel इस जवाब को पार्स करता है और मैन्युअल तरीके से इसे WorkResponse
प्रोटो में बदल देता है. JSON के बजाय, बाइनरी कोड में बदले गए प्रोटोबफ़ का इस्तेमाल करके जुड़े कर्मचारी से संपर्क करने के लिए, requires-worker-protocol
को proto
पर सेट किया जाएगा. उदाहरण के लिए:
execution_requirements = {
"supports-workers" : "1" ,
"requires-worker-protocol" : "proto"
}
अगर एक्ज़ीक्यूशन की ज़रूरी शर्तों में requires-worker-protocol
को शामिल नहीं किया जाता है,
तो Baज़ल, वर्कर कम्यूनिकेशन को डिफ़ॉल्ट रूप से प्रोटोबफ़ का इस्तेमाल करने देगा.
बेज़ल, मेनेमोनिक और शेयर किए गए फ़्लैग से WorkerKey
को लेता है. इसलिए, अगर यह कॉन्फ़िगरेशन
max_mem
पैरामीटर में बदलाव करने की अनुमति देता है, तो इस्तेमाल की जाने वाली हर वैल्यू के लिए एक अलग वर्कर जनरेट होगा. बहुत ज़्यादा वैरिएशन का इस्तेमाल करने से, मेमोरी
बहुत ज़्यादा खर्च हो सकती है.
फ़िलहाल, हर वर्कर एक बार में सिर्फ़ एक अनुरोध पर कार्रवाई कर सकता है. अगर दिया गया टूल एक से ज़्यादा थ्रेड वाला है और रैपर इस समस्या को समझने के लिए सेट अप किया गया है, तो प्रयोग के तौर पर शुरू की गई मल्टीप्लेक्स वर्कर सुविधा एक से ज़्यादा थ्रेड का इस्तेमाल करने की अनुमति देती है.
GitHub के इस रेपो में, Java के साथ-साथ Python में लिखे गए वर्कर रैपर के उदाहरण देखे जा सकते हैं. अगर JavaScript या TypeScript में काम किया जा रहा है, तो @bagel/worker पैकेज और nodejs वर्कर उदाहरण से आपको मदद मिल सकती है.
वर्कर, सैंडबॉक्सिंग पर कैसे असर डालते हैं?
डिफ़ॉल्ट रूप से, worker
रणनीति का इस्तेमाल करने पर, कार्रवाई local
रणनीति की तरह sandbox में नहीं चलती. सभी कर्मियों को सैंडबॉक्स में चलाने के लिए, --worker_sandboxing
फ़्लैग को सेट किया जा सकता है. इससे यह पक्का किया जा सकता है कि टूल के हर काम में सिर्फ़ वही इनपुट फ़ाइलें दिखें जो उसे चाहिए. यह टूल अब भी अंदरूनी तौर पर अनुरोधों के बीच जानकारी लीक कर सकता है, जैसे कि कैश मेमोरी के ज़रिए. dynamic
रणनीति का इस्तेमाल करने
के लिए, कर्मचारियों को सैंडबॉक्स करना ज़रूरी है.
वर्कर के साथ कंपाइलर कैश मेमोरी का सही इस्तेमाल करने की अनुमति देने के लिए, हर इनपुट फ़ाइल के साथ एक डाइजेस्ट पास किया जाता है. इसलिए, कंपाइलर या रैपर यह जांच कर सकता है कि फ़ाइल को पढ़े बिना इनपुट अब भी मान्य है या नहीं.
अनचाहे कैशिंग से बचने के लिए, इनपुट डाइजेस्ट का इस्तेमाल करने के दौरान भी, सैंडबॉक्स में काम करने वाले लोग, सैंडबॉक्स के मुकाबले कम सख्त सैंडबॉक्सिंग की सुविधा देते हैं. ऐसा इसलिए होता है, क्योंकि टूल ऐसी दूसरी अंदरूनी स्थिति को बनाए रख सकता है जो पिछले अनुरोधों की वजह से प्रभावित हुई है.
मल्टीप्लेक्स वर्कर को सिर्फ़ तब सैंडबॉक्स किया जा सकता है, जब वर्कर को लागू करने पर यह सुविधा काम करती हो. साथ ही, इस सैंडबॉक्सिंग को --experimental_worker_multiplex_sandboxing
फ़्लैग की मदद से अलग से चालू किया जाना चाहिए. डिज़ाइन दस्तावेज़ में ज़्यादा जानकारी देखें).
इसके बारे में और पढ़ें
लगातार काम करने वाले कर्मचारियों के बारे में ज़्यादा जानकारी के लिए, यह लेख देखें:
- परसिस्टेंट वर्कर के लिए बनाई गई ओरिजनल ब्लॉग पोस्ट
- हैस्केल लागू करने के बारे में जानकारी
- माइक मोरार्टी की ब्लॉग पोस्ट
- Bze> के साथ फ़्रंट एंड डेवलपमेंट: Asana के साथ Angular/TypeScript और लगातार काम करने वाले लोग
- Basel से जुड़ी रणनीतियों के बारे में जानकारी
- baज़ल-चर्चा के लिए ईमेल पाने वाले लोगों की सूची के बारे में, कर्मचारियों की रणनीति के बारे में जानकारी