Halaman ini membahas cara menggunakan pekerja persisten, manfaat, persyaratan, dan pengaruh pekerja terhadap sandbox.
Pekerja persisten adalah proses yang berjalan lama yang dimulai oleh server Bazel, yang berfungsi sebagai wrapper di sekitar alat sebenarnya (biasanya compiler), atau merupakan alat itu sendiri. Agar dapat memanfaatkan pekerja persisten, alat harus mendukung urutan kompilasi, dan wrapper harus menerjemahkan antara API alat dan format permintaan/respons yang dijelaskan di bawah. Pekerja yang sama dapat dipanggil dengan dan tanpa flag --persistent_worker dalam build yang sama, dan bertanggung jawab untuk memulai dan berkomunikasi dengan alat secara tepat, serta mematikan pekerja saat keluar. Setiap instance pekerja ditetapkan
(tetapi tidak di-chroot) ke direktori kerja terpisah di bawah
<outputBase>/bazel-workers.
Penggunaan pekerja persisten adalah sebuah strategi eksekusi yang mengurangi overhead startup, memungkinkan lebih banyak kompilasi JIT, dan memungkinkan penyimpanan dalam cache, misalnya, pohon sintaksis abstrak dalam eksekusi tindakan. Strategi ini mencapai peningkatan ini dengan mengirimkan beberapa permintaan ke proses yang berjalan lama.
Pekerja persisten diimplementasikan untuk beberapa bahasa, termasuk Java, Scala, Kotlin, dan lainnya.
Program yang menggunakan runtime NodeJS dapat menggunakan library helper @bazel/worker untuk menerapkan protokol pekerja.
Menggunakan pekerja persisten
Bazel 0.27 dan yang lebih tinggi
menggunakan pekerja persisten secara default saat menjalankan build, meskipun eksekusi jarak jauh
diutamakan. Untuk tindakan yang tidak mendukung pekerja persisten, Bazel akan kembali ke memulai instance alat untuk setiap tindakan. Anda dapat secara eksplisit
menetapkan build Anda untuk menggunakan pekerja persisten dengan menetapkan worker
strategi untuk mnemonik alat yang berlaku. Sebagai praktik terbaik, contoh ini mencakup penentuan local sebagai pengganti strategi worker:
bazel build //my:target --strategy=Javac=worker,localMenggunakan strategi pekerja, bukan strategi lokal, dapat meningkatkan kecepatan kompilasi secara signifikan, bergantung pada implementasinya. Untuk Java, build dapat 2–4 kali lebih cepat, terkadang lebih untuk kompilasi inkremental. Kompilasi Bazel sekitar 2,5 kali lebih cepat dengan pekerja. Untuk mengetahui detail selengkapnya, lihat bagian "Memilih jumlah pekerja".
Jika Anda juga memiliki lingkungan build jarak jauh yang cocok dengan lingkungan build lokal
lingkungan, Anda dapat menggunakan strategi
dinamis eksperimental,
yang menjalankan eksekusi jarak jauh dan eksekusi pekerja. Untuk mengaktifkan strategi dinamis, teruskan flag
--experimental_spawn_scheduler. Strategi ini otomatis mengaktifkan pekerja, sehingga Anda tidak perlu menentukan strategi worker, tetapi Anda tetap dapat menggunakan local atau sandboxed sebagai pengganti.
Memilih jumlah pekerja
Jumlah default instance pekerja per mnemonik adalah 4, tetapi dapat disesuaikan
dengan
worker_max_instances
flag. Ada pertukaran antara penggunaan CPU yang tersedia dengan baik dan jumlah kompilasi JIT serta hit cache yang Anda dapatkan. Dengan lebih banyak pekerja, lebih banyak target akan membayar biaya startup untuk menjalankan kode non-JIT dan mencapai cache dingin. Jika Anda memiliki sejumlah kecil target untuk dibuat, satu pekerja dapat memberikan
pertukaran terbaik antara kecepatan kompilasi dan penggunaan resource (misalnya,
lihat masalah #8586.
Flag worker_max_instances menetapkan jumlah maksimum instance pekerja per mnemonik dan kumpulan flag (lihat di bawah), sehingga dalam sistem campuran, Anda dapat menggunakan cukup banyak memori jika mempertahankan nilai default. Untuk build inkremental, manfaat beberapa instance pekerja bahkan lebih kecil.
Grafik ini menunjukkan waktu kompilasi dari awal untuk Bazel (target //src:bazel) di workstation Linux Intel Xeon 3,5 GHz hyper-threaded 6 core dengan RAM 64 GB. Untuk setiap konfigurasi pekerja, lima build bersih dijalankan dan rata-rata empat build terakhir diambil.

Gambar 1. Grafik peningkatan performa build bersih.
Untuk konfigurasi ini, dua pekerja memberikan kompilasi tercepat, meskipun hanya peningkatan 14% dibandingkan dengan satu pekerja. Satu pekerja adalah opsi yang baik jika Anda ingin menggunakan lebih sedikit memori.
Kompilasi inkremental biasanya lebih bermanfaat. Build bersih relatif jarang, tetapi mengubah satu file antara kompilasi adalah hal yang umum, khususnya dalam pengembangan berbasis pengujian. Contoh di atas juga memiliki beberapa tindakan pengemasan non-Java yang dapat menutupi waktu kompilasi inkremental.
Mengompilasi ulang sumber Java saja
(//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar)
setelah mengubah konstanta string internal di
AbstractContainerizingSandboxedSpawn.java
memberikan peningkatan kecepatan 3x (rata-rata 20 build inkremental dengan satu build pemanasan
dihapus):

Gambar 2. Grafik peningkatan performa build inkremental.
Peningkatan kecepatan bergantung pada perubahan yang dilakukan. Peningkatan kecepatan sebesar faktor 6 diukur dalam situasi di atas saat konstanta yang umum digunakan diubah.
Mengubah pekerja persisten
Anda dapat meneruskan flag
--worker_extra_flag
untuk menentukan flag startup ke pekerja, yang dikelompokkan berdasarkan mnemonik. Misalnya, meneruskan --worker_extra_flag=javac=--debug hanya akan mengaktifkan proses debug untuk Javac.
Hanya satu flag pekerja yang dapat ditetapkan per penggunaan flag ini, dan hanya untuk satu mnemonik.
Pekerja tidak hanya dibuat secara terpisah untuk setiap mnemonik, tetapi juga untuk variasi dalam flag startup-nya. Setiap kombinasi mnemonik dan flag startup digabungkan ke dalam WorkerKey, dan untuk setiap WorkerKey, hingga worker_max_instances pekerja dapat dibuat. Lihat bagian berikutnya untuk mengetahui cara konfigurasi tindakan juga dapat menentukan flag penyiapan.
Meneruskan flag
--worker_sandboxing
akan membuat setiap permintaan pekerja menggunakan direktori sandbox terpisah untuk semua
inputnya. Menyiapkan sandbox memerlukan waktu tambahan,
terutama di macOS, tetapi memberikan jaminan kebenaran yang lebih baik.
Flag
--worker_quit_after_build
terutama berguna untuk proses debug dan pembuatan profil. Flag ini memaksa semua pekerja untuk keluar setelah build selesai. Anda juga dapat meneruskan
--worker_verbose untuk
mendapatkan lebih banyak output tentang aktivitas pekerja. Flag ini tercermin dalam kolom verbosity di WorkRequest, sehingga implementasi pekerja juga dapat menjadi lebih verbose.
Pekerja menyimpan log mereka di direktori <outputBase>/bazel-workers, misalnya
/tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log.
Nama file mencakup ID pekerja dan mnemonik. Karena dapat ada lebih dari satu WorkerKey per mnemonik, Anda mungkin melihat lebih dari worker_max_instances file log untuk mnemonik tertentu.
Untuk build Android, lihat detailnya di halaman Performa Build Android.
Mengimplementasikan pekerja persisten
Lihat halaman membuat pekerja persisten untuk mengetahui informasi selengkapnya tentang cara membuat pekerja.
Contoh ini menunjukkan konfigurasi Starlark untuk pekerja yang menggunakan 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" }
)
Dengan definisi ini, penggunaan pertama tindakan ini akan dimulai dengan menjalankan command line /bin/some_compiler -max_mem=4G --persistent_worker. Permintaan untuk mengompilasi Foo.java akan terlihat seperti:
CATATAN: Meskipun spesifikasi buffer protokol menggunakan "snake case" (request_id), protokol JSON menggunakan "camel case" (requestId). Dalam dokumen ini, kita akan menggunakan camel case dalam contoh JSON, tetapi snake case saat membahas kolom, terlepas dari protokol.
{
"arguments": [ "-g", "-source", "1.5", "Foo.java" ]
"inputs": [
{ "path": "symlinkfarm/input1", "digest": "d49a..." },
{ "path": "symlinkfarm/input2", "digest": "093d..." },
],
}
Pekerja menerima ini di stdin dalam format JSON yang dibatasi baris baru (karena requires-worker-protocol ditetapkan ke JSON). Kemudian, pekerja melakukan tindakan, dan mengirim WorkResponse berformat JSON ke Bazel di stdout-nya. Bazel kemudian mengurai respons ini dan mengonversinya secara manual ke proto WorkResponse. Untuk
berkomunikasi dengan pekerja terkait menggunakan protobuf yang dienkode biner, bukan
JSON, requires-worker-protocol akan ditetapkan ke proto, seperti ini:
execution_requirements = {
"supports-workers" : "1" ,
"requires-worker-protocol" : "proto"
}
Jika Anda tidak menyertakan requires-worker-protocol dalam persyaratan eksekusi, Bazel akan menetapkan komunikasi pekerja secara default untuk menggunakan protobuf.
Bazel memperoleh WorkerKey dari mnemonik dan flag bersama, sehingga jika konfigurasi ini memungkinkan perubahan parameter max_mem, pekerja terpisah akan dibuat untuk setiap nilai yang digunakan. Hal ini dapat menyebabkan konsumsi memori yang berlebihan jika terlalu banyak variasi yang digunakan.
Setiap pekerja saat ini hanya dapat memproses satu permintaan dalam satu waktu. Fitur pekerja multiplex eksperimental memungkinkan penggunaan beberapa thread, jika alat yang mendasarinya bersifat multithread dan wrapper disiapkan untuk memahami hal ini.
Di repo GitHub ini, Anda dapat melihat contoh wrapper pekerja yang ditulis dalam Java dan Python. Jika Anda menggunakan JavaScript atau TypeScript, paket @bazel/worker dan contoh pekerja nodejs mungkin berguna.
Bagaimana pengaruh pekerja terhadap sandbox?
Penggunaan strategi worker secara default tidak menjalankan tindakan dalam
sandbox, mirip dengan strategi local. Anda dapat menetapkan flag --worker_sandboxing untuk menjalankan semua pekerja di dalam sandbox, sehingga memastikan setiap eksekusi alat hanya melihat file input yang seharusnya dimiliki. Alat ini mungkin masih membocorkan informasi antar-permintaan secara internal, misalnya melalui cache. Penggunaan strategi dynamic
mengharuskan pekerja di-sandbox.
Untuk memungkinkan penggunaan cache compiler yang benar dengan pekerja, ringkasan diteruskan bersama dengan setiap file input. Dengan demikian, compiler atau wrapper dapat memeriksa apakah input masih valid tanpa harus membaca file.
Meskipun menggunakan ringkasan input untuk melindungi dari penyimpanan dalam cache yang tidak diinginkan, pekerja sandbox menawarkan sandbox yang kurang ketat daripada sandbox murni, karena alat ini dapat menyimpan status internal lain yang telah terpengaruh oleh permintaan sebelumnya.
Pekerja multiplex hanya dapat di-sandbox jika implementasi pekerja mendukungnya, dan sandbox ini harus diaktifkan secara terpisah dengan flag --experimental_worker_multiplex_sandboxing. Lihat detail selengkapnya di
dokumen desain).
Bacaan lebih lanjut
Untuk mengetahui informasi selengkapnya tentang pekerja persisten, lihat: