स्थायी कर्मचारी

किसी समस्या की शिकायत करें सोर्स देखें Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

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

बेज़ल सर्वर, लंबे समय तक चलने वाली प्रोसेस होती है. यह प्रोसेस, आम तौर पर असल टूल (आम तौर पर, कंपाइलर) के आस-पास रैपर या टूल के तौर पर काम करती है. लगातार काम करने वाले लोगों का फ़ायदा उठाने के लिए, टूल को कंपाइलेशन का क्रम काम करना चाहिए. साथ ही, रैपर को टूल के एपीआई और नीचे बताए गए अनुरोध/जवाब फ़ॉर्मैट के बीच अनुवाद करना चाहिए. एक ही बिल्ड में --persistent_worker फ़्लैग के साथ और उसके बिना भी एक ही वर्कर को कॉल किया जा सकता है और वह टूल को सही तरीके से शुरू करने, उससे बात करने के साथ-साथ बाहर निकलने पर काम करने वाले लोगों को बंद करने के लिए ज़िम्मेदार होता है. हर वर्क इंस्टेंस को <outputBase>/bazel-workers के तहत एक अलग वर्किंग डायरेक्ट्री असाइन की जाती है. हालांकि, उसमें chroot नहीं किया जाता.

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

स्थायी कर्मचारियों को कई भाषाओं के लिए लागू किया जाता है. इनमें Java, Scala, Kotlin वगैरह शामिल हैं.

NodeJS रनटाइम का इस्तेमाल करने वाले प्रोग्राम, वर्कर प्रोटोकॉल को लागू करने के लिए, @baaz/worker हेल्पर लाइब्रेरी का इस्तेमाल कर सकते हैं.

स्थायी कर्मचारियों का इस्तेमाल करना

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

bazel build //my:target --strategy=Javac=worker,local

स्थानीय रणनीति के बजाय कर्मचारियों की रणनीति का इस्तेमाल करने से, कंपाइलेशन स्पीड काफ़ी तेज़ी से बढ़ सकती है. यह सुविधा लागू करने के तरीके पर निर्भर करती है. Java के लिए, बिल्ड 2 से 4 गुना तेज़ हो सकते हैं. कभी-कभी ज़्यादा तेज़ी से कंपाइलेशन करने के लिए ये काम कर सकते हैं. वर्कर्स की मदद से, Bazel को इकट्ठा करने में करीब 2.5 गुना कम समय लगता है. ज़्यादा जानकारी के लिए, "कर्मचारियों की संख्या चुनना" सेक्शन देखें.

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

कर्मचारियों की संख्या चुनना

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

इस ग्राफ़ में, 64 जीबी रैम वाले 6-कोर हाइपर-थ्रेडेड Intel Xeon 3.5 GHz Linux वर्कस्टेशन पर, Bazel (टारगेट//src:bazel) के लिए, शुरू से कंपाइल करने में लगने वाला समय दिखाया गया है. हर वर्कर कॉन्फ़िगरेशन के लिए, पांच क्लीन बिल चलाए जाते हैं और आखिरी चार का औसत लिया जाता है.

क्लीन बिल्ड की परफ़ॉर्मेंस में सुधार करने का ग्राफ़

पहली इमेज. क्लीन बिल्ड के परफ़ॉर्मेंस में सुधार का ग्राफ़.

इस कॉन्फ़िगरेशन के लिए, दो वर्कर्स सबसे तेज़ कंपाइल करते हैं. हालांकि, एक वर्कर्स की तुलना में इसमें सिर्फ़ 14% का सुधार होता है. अगर आपको कम मेमोरी का इस्तेमाल करना है, तो एक वर्कर्स का विकल्प चुनें.

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

AbstractContainerizingSandboxedSpawn.java में मौजूद किसी इंटरनल स्ट्रिंग कॉन्स्टेंट को बदलने के बाद, सिर्फ़ Java सोर्स को फिर से कॉम्पाइल करने (//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar) पर, प्रोसेस की स्पीड तीन गुना बढ़ जाती है. इसमें, एक वॉर्मअप बिल्ड को छोड़कर, औसतन 20 इंक्रीमेंटल बिल्ड होते हैं:

इंक्रीमेंटल बिल्ड की परफ़ॉर्मेंस में सुधार करने वाला ग्राफ़

दूसरी इमेज. इंक्रीमेंटल बिल्ड की परफ़ॉर्मेंस में हुए सुधारों का ग्राफ़.

स्पीड में होने वाली बढ़ोतरी, किए जा रहे बदलाव पर निर्भर करती है. ऊपर दी गई स्थिति में, आम तौर पर इस्तेमाल होने वाले कॉन्स्टेंट को बदलने पर, प्रोसेस की स्पीड में छह गुना की बढ़ोतरी होती है.

स्थायी कर्मचारियों में बदलाव करना

वर्कर्स को स्टार्ट-अप फ़्लैग की जानकारी देने के लिए, --worker_extra_flag फ़्लैग पास किया जा सकता है. उदाहरण के लिए, --worker_extra_flag=javac=--debug पास करना सिर्फ़ Javac के लिए डीबग करना चालू करता है. इस फ़्लैग के इस्तेमाल के लिए, सिर्फ़ एक वर्कफ़्लैग सेट किया जा सकता है. साथ ही, यह सिर्फ़ एक मेमोनिक के लिए सेट किया जा सकता है. वर्कर्स को हर मेमोनिक के लिए अलग से ही नहीं बनाया जाता, बल्कि उनके स्टार्ट-अप फ़्लैग में होने वाले बदलावों के लिए भी बनाया जाता है. स्मोनेनिक और स्टार्ट-अप फ़्लैग का हर कॉम्बिनेशन एक WorkerKey में जोड़ा जाता है. साथ ही, हर WorkerKey के लिए, ज़्यादा से ज़्यादा worker_max_instances वर्कर बनाए जा सकते हैं. अगला सेक्शन देखें और जानें कि ऐक्शन कॉन्फ़िगरेशन, सेट-अप फ़्लैग कैसे तय कर सकता है.

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

--worker_sandboxing फ़्लैग को पास करने से, हर वर्कर का अनुरोध, अपने सभी इनपुट के लिए एक अलग सैंडबॉक्स डायरेक्ट्री का इस्तेमाल करता है. सैंडबॉक्स सेट अप करने में, ज़्यादा समय लगता है. खास तौर पर, 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ज़ल, वर्कर कम्यूनिकेशन को डिफ़ॉल्ट रूप से प्रोटोबफ़ का इस्तेमाल करने का निर्देश देगा.

Bazel, मेनिमोन और शेयर किए गए फ़्लैग से WorkerKey का पता लगाता है. इसलिए, अगर इस कॉन्फ़िगरेशन में max_mem पैरामीटर को बदलने की अनुमति दी जाती है, तो इस्तेमाल की गई हर वैल्यू के लिए एक अलग वर्कर्स स्पॉन किया जाएगा. अगर बहुत ज़्यादा वैरिएशन इस्तेमाल किए जाते हैं, तो इससे ज़्यादा मेमोरी खर्च हो सकती है.

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

इस GitHub रिपॉज़िटरी में, आपको Java और Python, दोनों में लिखे गए वर्कर्स रैपर के उदाहरण दिख सकते हैं. अगर JavaScript या TypeScript में काम किया जा रहा है, तो @bazel/worker package और nodejs worker example मददगार हो सकते हैं.

वर्कर, सैंडबॉक्सिंग पर कैसे असर डालते हैं?

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

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

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

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

इसके बारे में और पढ़ें

लगातार काम करने वाले कर्मचारियों के बारे में ज़्यादा जानकारी के लिए, यह लेख देखें: