หน้านี้จะอธิบายวิธีใช้เวิร์กเกอร์แบบถาวร ประโยชน์ ข้อกําหนด และผลกระทบที่เวิร์กเกอร์มีต่อแซนด์บ็อกซ์
ผู้ปฏิบัติงานถาวรเป็นกระบวนการที่ใช้เวลานานซึ่งเริ่มต้นโดยเซิร์ฟเวอร์ Bazel
ทำหน้าที่เป็น Wrapper ของเครื่องมือจริง (ปกติแล้วคือคอมไพเลอร์) หรือ
เครื่องมือด้วยตนเอง เครื่องมือต้องรองรับการคอมไพล์ตามลําดับ และรัปเปอร์ต้องแปลระหว่าง API ของเครื่องมือกับรูปแบบคําขอ/การตอบกลับที่อธิบายไว้ด้านล่าง เพื่อให้ได้รับประโยชน์จากเวิร์กเกอร์แบบถาวร อาจมีเรียกใช้ Worker เดียวกันโดยใส่หรือไม่ใส่ Flag --persistent_worker
ในบิลด์เดียวกัน และมีหน้าที่รับผิดชอบในการเริ่มต้นและพูดคุยกับเครื่องมืออย่างเหมาะสม รวมถึงปิด Worker เมื่อออก มีการกำหนดอินสแตนซ์ของผู้ปฏิบัติงานแต่ละรายการแล้ว
(แต่ไม่ได้ถูกแบ่งตาม) ไดเรกทอรีการทำงานที่แยกต่างหากภายใต้
<outputBase>/bazel-workers
การใช้ผู้ปฏิบัติงานถาวร กลยุทธ์การดำเนินการที่ลดลง โอเวอร์เฮดการเริ่มต้น ทำให้สามารถคอมไพล์ JIT ได้มากขึ้น และเปิดใช้การแคชสำหรับ ตัวอย่างโครงสร้างไวยากรณ์นามธรรมในการดำเนินการ กลยุทธ์นี้ ได้รับการปรับปรุงเหล่านี้โดยการส่งคำขอหลายรายการไปยัง ขั้นตอนได้
มีการใช้งานผู้ปฏิบัติงานถาวรสำหรับหลายภาษา รวมถึง Java สกาลา Kotlin และอื่นๆ
โปรแกรมที่ใช้รันไทม์ NodeJS สามารถใช้ @bazel/worker ไลบรารีตัวช่วยไปยัง ใช้โปรโตคอลผู้ปฏิบัติงาน
การใช้ผู้ปฏิบัติงานแบบถาวร
Bazel 0.27 ขึ้นไป
ใช้ผู้ปฏิบัติงานถาวรโดยค่าเริ่มต้นเมื่อดำเนินการบิลด์ แต่ดำเนินการจากระยะไกล
การดำเนินการจะมีความสำคัญเหนือกว่า สำหรับการดำเนินการที่ไม่รองรับผู้ปฏิบัติงานถาวร
Bazel ย้อนกลับไปที่การเริ่มอินสแตนซ์เครื่องมือสำหรับการดำเนินการแต่ละรายการ คุณสามารถตั้งค่าบิลด์ให้ใช้ผู้ปฏิบัติงานแบบถาวรได้อย่างชัดเจนโดยการตั้งค่าworker
strategy สำหรับคําช่วยจําของเครื่องมือที่เกี่ยวข้อง แนวทางปฏิบัติแนะนำคือให้ระบุ local
เป็นกลยุทธ์สำรองสำหรับกลยุทธ์ worker
ดังตัวอย่างต่อไปนี้
bazel build //my:target --strategy=Javac=worker,local
การใช้กลยุทธ์สำหรับโหนดทำงานแทนกลยุทธ์ในเครื่องสามารถเพิ่มความเร็วในการคอมไพล์ได้อย่างมาก ทั้งนี้ขึ้นอยู่กับการใช้งาน สำหรับ Java การสร้างจะเร็วขึ้น 2-4 เท่า และบางครั้งอาจเร็วกว่านั้นสำหรับการคอมไพล์แบบเพิ่ม รวม Bazel เร็วขึ้นประมาณ 2.5 เท่าสำหรับผู้ปฏิบัติงาน ดูรายละเอียดเพิ่มเติมได้ที่ส่วน "การเลือกจํานวนคนงาน"
หากคุณมีสภาพแวดล้อมบิลด์ระยะไกลที่ตรงกับบิลด์ในเครื่องด้วย
คุณสามารถใช้การทดสอบ
กลยุทธ์ไดนามิก
ซึ่งจะแข่งกับการดำเนินการจากระยะไกลและการดำเนินการของผู้ปฏิบัติงาน หากต้องการเปิดใช้โฆษณาแบบไดนามิก
ให้ส่งต่อ
--experimental_spawn_scheduler
แจ้ง กลยุทธ์นี้จะเปิดใช้แรงงานโดยอัตโนมัติ คุณจึงไม่ต้องระบุกลยุทธ์ worker
แต่ยังคงใช้ local
หรือ sandboxed
เป็นกลยุทธ์สำรองได้
การเลือกจํานวนผู้ปฏิบัติงาน
จำนวนอินสแตนซ์เริ่มต้นของผู้ปฏิบัติงานต่อความทรงจำคือ 4 แต่สามารถปรับเปลี่ยนได้
พร้อมด้วย
worker_max_instances
แจ้ง การใช้ CPU ที่มีอยู่อย่างคุ้มค่าและจำนวนการคอมไพล์ JIT และการตีคู่แคชที่คุณได้รับนั้นมีความเกี่ยวข้องกัน เมื่อมีผู้ปฏิบัติงานมากขึ้น เป้าหมายจำนวนมากขึ้นจะต้องจ่ายค่าเริ่มต้นของการทำงานโค้ดที่ไม่ใช่ JIT และการใช้แคชเย็น หากคุณมีเป้าหมายที่จะสร้างจำนวนน้อย ผู้ปฏิบัติงานคนเดียวอาจให้
ตัวเลือกที่ดีที่สุดระหว่างความเร็วในการคอมไพล์และการใช้ทรัพยากร (เช่น
ดูปัญหา #8586
Flag worker_max_instances
จะกำหนดจำนวนอินสแตนซ์ที่ทำงานสูงสุดต่อชุดคำสั่งสั้นๆ และ Flag (ดูด้านล่าง) ดังนั้นในระบบแบบผสม คุณอาจต้องใช้หน่วยความจำค่อนข้างมากหากใช้ค่าเริ่มต้น สำหรับบิลด์ส่วนเพิ่ม
ของอินสแตนซ์ผู้ปฏิบัติงานจำนวนมากมีขนาดเล็กลง
กราฟนี้แสดงเวลาคอมไพล์จากรอยขีดข่วนสำหรับ Bazel (target
//src:bazel
) ในเวิร์กสเตชัน Intel Xeon 3.5 GHz Linux แบบไฮเปอร์เทรด 6 แกน
RAM ขนาด 64 GB สําหรับการกําหนดค่าผู้ปฏิบัติงานแต่ละรายการ ระบบจะเรียกใช้บิลด์ที่สะอาด 5 ครั้งและนําค่าเฉลี่ยของ 4 ครั้งล่าสุด
รูปที่ 1 กราฟการปรับปรุงประสิทธิภาพของบิลด์ที่สะอาด
สําหรับการกําหนดค่านี้ 2 เวิร์กเกอร์จะคอมไพล์ได้เร็วที่สุด แต่มีประสิทธิภาพเพิ่มขึ้นเพียง 14% เมื่อเทียบกับ 1 เวิร์กเกอร์ เวิร์กเกอร์ 1 คนเป็นตัวเลือกที่ดีหากคุณต้องการใช้หน่วยความจำน้อยลง
โดยทั่วไปแล้วการคอมไพล์แบบเพิ่มมักจะให้ประโยชน์มากกว่า บิลด์ที่สะอาดคือ ค่อนข้างเกิดขึ้นไม่บ่อยนัก แต่การเปลี่ยนไฟล์เดียวระหว่างคอมไพล์เหล่านี้เป็นเรื่องปกติ ดังนี้ โดยเฉพาะในการพัฒนาที่เน้นทดสอบ ตัวอย่างข้างต้นยังมีบางผลิตภัณฑ์ที่ไม่ใช่ Java การสร้างแพ็กเกจใหม่ซึ่งสามารถลดเวลาการคอมไพล์ที่เพิ่มขึ้นได้
การคอมไพล์เฉพาะซอร์สของ Java ใหม่เท่านั้น
(//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar
)
หลังจากเปลี่ยนแปลงค่าคงที่สตริงภายในใน
AbstractContainerizingSandboxedSpawn.java
ทำให้เร่งความเร็วได้ 3 เท่า (เพิ่มขึ้นเฉลี่ย 20 บิลด์สำหรับอุ่นเครื่อง 1 บิลด์
ทิ้ง):
รูปที่ 2 กราฟการปรับปรุงประสิทธิภาพของบิลด์ที่เพิ่มขึ้น
การเร่งความเร็วจะขึ้นอยู่กับการเปลี่ยนแปลงที่เกิดขึ้น การเพิ่มความเร็วของปัจจัย 6 คือ วัดในสถานการณ์ข้างต้นเมื่อมีการเปลี่ยนแปลงค่าคงที่ที่ใช้กันทั่วไป
การแก้ไขผู้ปฏิบัติงานถาวร
คุณสามารถส่ง Flag --worker_extra_flag
เพื่อระบุ Flag เริ่มต้นให้กับ Worker โดยกำหนดคีย์เป็นคําช่วยจำ เช่น การใส่ --worker_extra_flag=javac=--debug
จะเปิดการแก้ไขข้อบกพร่องสําหรับ Javac เท่านั้น
คุณตั้งค่า Flag ของ Wrkr ได้เพียง 1 รายการต่อการใช้ Flag นี้ และสำหรับคําช่วยจํารายการเดียวเท่านั้น
ผู้ปฏิบัติงานไม่ได้สร้างขึ้นแยกต่างหากสำหรับการช่วยจำแต่ละรายการ แต่รวมถึงผู้ปฏิบัติงานด้วย
ที่แตกต่างกันใน Flag การเริ่มต้น ชุดค่าผสมของ mnemonic และ flag เริ่มต้นแต่ละชุดจะรวมกันเป็น WorkerKey
และระบบอาจสร้างผู้ปฏิบัติงานได้สูงสุด worker_max_instances
คนสำหรับ WorkerKey
แต่ละรายการ โปรดดูส่วนถัดไปเกี่ยวกับ
การกำหนดค่าการดำเนินการสามารถระบุแฟล็กการตั้งค่าได้ด้วย
คุณสามารถใช้ Flag --high_priority_workers
เพื่อระบุคําช่วยจําที่ควรเรียกใช้แทนคําช่วยจําที่มีลําดับความสําคัญเป็นปกติ ซึ่งจะช่วยจัดลําดับความสําคัญของการดำเนินการที่อยู่ในเส้นทางสําคัญเสมอ หากมีผู้ปฏิบัติงานที่มีลําดับความสําคัญสูงดําเนินการตามคําขอ 2 คนขึ้นไป ระบบจะป้องกันไม่ให้ผู้ปฏิบัติงานคนอื่นๆ ทํางาน คุณใช้ Flag นี้ซ้ำได้
การส่งผ่าน Flag --worker_sandboxing
จะทำให้คำขอของเวิร์กเกอร์แต่ละรายการใช้ไดเรกทอรีแซนด์บ็อกซ์แยกต่างหากสำหรับอินพุตทั้งหมด การตั้งค่าแซนด์บ็อกซ์ใช้เวลานานขึ้น
โดยเฉพาะอย่างยิ่งใน macOS แต่ให้การรับประกันความถูกต้องที่ดีกว่า
Flag --worker_quit_after_build
มีประโยชน์สําหรับการแก้ไขข้อบกพร่องและการสร้างโปรไฟล์เป็นหลัก ธงนี้จะบังคับให้ผู้ปฏิบัติงานทั้งหมด
ที่ควรออกจากการสร้าง
เมื่อสร้างเสร็จแล้ว นอกจากนี้ คุณยังส่ง --worker_verbose
เพื่อรับเอาต์พุตเพิ่มเติมเกี่ยวกับสิ่งที่ผู้ดําเนินการทําอยู่ได้ด้วย การตั้งค่าสถานะนี้จะแสดงใน
verbosity
ใน WorkRequest
ซึ่งช่วยให้ติดตั้งใช้งานสำหรับผู้ปฏิบัติงานได้ด้วย
มีรายละเอียดมากขึ้น
ผู้ปฏิบัติงานจะจัดเก็บบันทึกไว้ในไดเรกทอรี <outputBase>/bazel-workers
เช่น /tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log
ชื่อไฟล์จะประกอบด้วยรหัสผู้ปฏิบัติงานและเทคนิคช่วยจำ เนื่องจากWorkerKey
อาจมีได้มากกว่า 1 รายการต่อคําช่วยจํา คุณจึงอาจเห็นไฟล์บันทึกมากกว่า worker_max_instances
ไฟล์สําหรับคําช่วยจําหนึ่งๆ
สำหรับบิลด์ของ Android โปรดดูรายละเอียดที่ หน้าประสิทธิภาพบิลด์ของ Android
การใช้ผู้ปฏิบัติงานแบบถาวร
ดูข้อมูลเพิ่มเติมเกี่ยวกับวิธีสร้างผู้ปฏิบัติงานได้ที่หน้าการสร้างผู้ปฏิบัติงานแบบถาวร
ตัวอย่างนี้แสดงการกำหนดค่า Starlark สำหรับผู้ปฏิบัติงานที่ใช้ JSON:
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
จะมีลักษณะดังนี้
หมายเหตุ: แม้ว่าข้อกำหนดของบัฟเฟอร์โปรโตคอลจะใช้ "รูปแบบ Snake Case" (request_id
) แต่โปรโตคอล JSON จะใช้ "รูปแบบ Camel Case" (requestId
) ในเอกสารนี้ เราจะใช้รูปแบบ Camel Case ในตัวอย่าง JSON แต่จะใช้รูปแบบ Snake Case เมื่อพูดถึงช่อง ไม่ว่าจะใช้โปรโตคอลใดก็ตาม
{
"arguments": [ "-g", "-source", "1.5", "Foo.java" ]
"inputs": [
{ "path": "symlinkfarm/input1", "digest": "d49a..." },
{ "path": "symlinkfarm/input2", "digest": "093d..." },
],
}
ผู้ใช้งานที่รับข้อมูลนี้ใน stdin
จะได้รับข้อมูลในรูปแบบ JSON ที่คั่นด้วยการขึ้นบรรทัดใหม่ (เนื่องจากมีการตั้งค่า requires-worker-protocol
เป็น JSON) จากนั้นเวิร์กเกอร์จะดำเนินการและส่ง WorkResponse
ในรูปแบบ JSON ไปยัง Bazel บน stdout จากนั้น Bazel จะแยกวิเคราะห์การตอบกลับนี้และแปลงเป็น WorkResponse
proto ด้วยตนเอง ถึง
สื่อสารกับผู้ปฏิบัติงานที่เกี่ยวข้องโดยใช้ Protobuf ที่เข้ารหัสแบบไบนารีแทน
ระบบจะตั้งค่า JSON requires-worker-protocol
เป็น proto
ดังนี้
execution_requirements = {
"supports-workers" : "1" ,
"requires-worker-protocol" : "proto"
}
หากคุณไม่ได้รวม requires-worker-protocol
ไว้ในข้อกำหนดการเรียกใช้ ระบบของ Bazel จะกำหนดค่าเริ่มต้นให้การสื่อสารของเวิร์กเกอร์ใช้ protobuf
Bazel จะดึงข้อมูล WorkerKey
จากคําช่วยจําและ Flag ที่แชร์ ดังนั้นหากการกําหนดค่านี้อนุญาตให้เปลี่ยนพารามิเตอร์ max_mem
ระบบจะสร้างเวิร์กเกอร์แยกต่างหากสําหรับแต่ละค่าที่ใช้ ซึ่งอาจทำให้เกิดการใช้หน่วยความจำมากเกินไปหาก
ใช้รูปแบบมากเกินไป
ปัจจุบันผู้ปฏิบัติงานแต่ละคนประมวลผลคำขอได้ทีละ 1 คำขอเท่านั้น การทดสอบ ฟีเจอร์ผู้ปฏิบัติงานมัลติเพล็กซ์อนุญาตให้ใช้ หากเครื่องมือที่สำคัญเป็นแบบมัลติเทรดและ Wrapper ได้รับการตั้งค่าเป็น เข้าใจเรื่องนี้
ในที่เก็บ GitHub นี้ คุณจะเห็นตัวอย่าง Wrapper ของ Worker ที่เขียนด้วย Java และ Python หากคุณทํางานใน JavaScript หรือ TypeScript แพ็กเกจ @bazel/worker และตัวอย่าง nodejs worker อาจมีประโยชน์
ผู้ปฏิบัติงานส่งผลต่อแซนด์บ็อกซ์อย่างไร
การใช้กลยุทธ์ worker
โดยค่าเริ่มต้นจะไม่เรียกใช้การดําเนินการในแซนด์บ็อกซ์ ซึ่งคล้ายกับกลยุทธ์ local
คุณสามารถตั้งค่า Flag --worker_sandboxing
เพื่อเรียกใช้เวิร์กเกอร์ทั้งหมดภายในแซนด์บ็อกซ์ เพื่อให้แน่ใจว่าการเรียกใช้เครื่องมือแต่ละครั้งจะเห็นเฉพาะไฟล์อินพุตที่ควรจะเห็น เครื่องมือ
จึงอาจยังทำให้ข้อมูลระหว่างคำขอรั่วไหลภายใน เช่น ผ่าน
แคช กำลังใช้กลยุทธ์dynamic
กำหนดให้ผู้ปฏิบัติงานต้องถูกแซนด์บ็อกซ์
เพื่อให้ผู้ปฏิบัติงานใช้แคชของคอมไพเลอร์ได้อย่างถูกต้อง ระบบจะส่งผ่านไดเจสต์ กับไฟล์อินพุตแต่ละไฟล์ ดังนั้นคอมไพเลอร์หรือรัปเปอร์จะตรวจสอบได้ว่าอินพุตยังคงใช้งานได้หรือไม่โดยไม่ต้องอ่านไฟล์
แม้จะใช้ข้อมูลสรุปอินพุตเพื่อป้องกันการแคชที่ไม่ต้องการ แต่เวิร์กเกอร์ที่อยู่ในแซนด์บ็อกซ์จะให้บริการแซนด์บ็อกซ์ที่เข้มงวดน้อยกว่าแซนด์บ็อกซ์แบบสมบูรณ์ เนื่องจากเครื่องมืออาจเก็บสถานะภายในอื่นๆ ที่ได้รับผลกระทบจากคำขอก่อนหน้าไว้
คุณจะจัดเก็บเวิร์กเกอร์แบบหลายรายการไว้ในแซนด์บ็อกซ์ได้ก็ต่อเมื่อการติดตั้งใช้งานเวิร์กเกอร์รองรับเท่านั้น และจะต้องเปิดใช้แซนด์บ็อกซ์นี้แยกต่างหากด้วย Flag --experimental_worker_multiplex_sandboxing
ดูรายละเอียดเพิ่มเติมได้ในเอกสารการออกแบบ)
อ่านเพิ่มเติม
ดูข้อมูลเพิ่มเติมเกี่ยวกับผู้ปฏิบัติงานแบบถาวรได้ที่