Kararlı Çalışanlar

Sorun bildir Kaynağı görüntüle Nightly · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Bu sayfada, kalıcı çalışanların nasıl kullanılacağı, avantajları, gereksinimleri ve çalışanların korumalı alan oluşturmayı nasıl etkilediği açıklanmaktadır.

Kalıcı çalışan, Bazel sunucusu tarafından başlatılan ve uzun süre çalışan bir işlemdir. Bu işlem, gerçek aracın (genellikle derleyici) etrafında sarmalayıcı olarak işlev görür veya aracın kendisidir. Kalıcı çalışanlardan yararlanmak için aracın bir derleme dizisi yapmayı desteklemesi ve sarmalayıcının, aracın API'si ile aşağıda açıklanan istek/yanıt biçimi arasında çeviri yapması gerekir. Aynı çalışan, aynı derlemede --persistent_worker işaretiyle ve işareti olmadan çağrılabilir. Aracı uygun şekilde başlatmaktan, araçla konuşmaktan ve çıkışta çalışanları kapatmaktan sorumludur. Her çalışan örneğine <outputBase>/bazel-workers altında ayrı bir çalışma dizini atanır (ancak chroot uygulanmaz).

Kalıcı çalışanlar kullanmak, başlangıç ek yükünü azaltan, daha fazla JIT derlemeye olanak tanıyan ve örneğin işlem yürütme sırasında soyut sözdizimi ağaçlarının önbelleğe alınmasını sağlayan bir yürütme stratejisidir. Bu strateji, uzun süredir devam eden bir işleme birden fazla istek göndererek bu iyileştirmeleri sağlar.

Kalıcı çalışanlar; Java, Scala, Kotlin gibi birden fazla dil için uygulanır.

NodeJS çalışma zamanını kullanan programlar, çalışan protokolünü uygulamak için @bazel/worker yardımcı kitaplığını kullanabilir.

Kalıcı çalışanları kullanma

Bazel 0.27 ve sonraki sürümler, derlemeleri yürütürken varsayılan olarak kalıcı çalışanları kullanır ancak uzaktan yürütme önceliklidir. Kalıcı çalışanları desteklemeyen işlemler için Bazel, her işlemde bir araç örneği başlatmaya geri döner. Geçerli araç anımsatıcıları için worker stratejisini ayarlayarak derlemenizi kalıcı çalışanları kullanacak şekilde açıkça ayarlayabilirsiniz. En iyi uygulama olarak bu örnekte, worker stratejisine geri dönüş olarak local belirtilmiştir:

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

Yerel strateji yerine çalışan stratejisini kullanmak, uygulamaya bağlı olarak derleme hızını önemli ölçüde artırabilir. Java'da derlemeler 2-4 kat daha hızlı olabilir. Artımlı derleme için bu süre bazen daha da kısalabilir. Bazel'i derleme, çalışanlarla yaklaşık 2,5 kat daha hızlıdır. Daha fazla bilgi için "Çalışan sayısını seçme" bölümüne bakın.

Yerel derleme ortamınızla eşleşen bir uzak derleme ortamınız da varsa uzak yürütme ve çalışan yürütme arasında yarışan deneysel dinamik stratejiyi kullanabilirsiniz. Dinamik stratejiyi etkinleştirmek için --experimental_spawn_scheduler işaretini iletin. Bu strateji, çalışanları otomatik olarak etkinleştirir. Bu nedenle, worker stratejisini belirtmeniz gerekmez ancak geri dönüş olarak local veya sandboxed stratejilerini kullanmaya devam edebilirsiniz.

Çalışan sayısını seçme

Her anımsatıcı için varsayılan çalışan örneği sayısı 4'tür ancak worker_max_instances işaretiyle ayarlanabilir. Mevcut CPU'lardan iyi bir şekilde yararlanmak ile JIT derleme ve önbellek isabeti miktarı arasında bir denge vardır. Daha fazla çalışanla birlikte, daha fazla hedef, JIT derlemesi yapılmamış kod çalıştırma ve soğuk önbelleklere erişme başlangıç maliyetlerini ödeyecektir. Oluşturulacak hedef sayısı azsa tek bir çalışan, derleme hızı ve kaynak kullanımı arasında en iyi dengeyi sağlayabilir (örneğin, 8586 numaralı soruna bakın). worker_max_instances işareti, her anımsatıcı ve işaret grubu için maksimum çalışan örneği sayısını ayarlar (aşağıya bakın). Bu nedenle, varsayılan değeri korursanız karma bir sistemde oldukça fazla bellek kullanabilirsiniz. Artımlı derlemelerde birden fazla çalışan örneğinin avantajı daha da azdır.

Bu grafikte, 6 çekirdekli, 3,5 GHz Intel Xeon Linux iş istasyonunda (64 GB RAM ile) Bazel'in (hedef //src:bazel) sıfırdan derleme süreleri gösterilmektedir. Her çalışan yapılandırması için beş temiz derleme çalıştırılır ve son dördünün ortalaması alınır.

Temiz derlemelerin performans iyileştirmelerini gösteren grafik

1.şekil Temiz derlemelerin performans iyileştirmelerini gösteren grafik.

Bu yapılandırmada, iki çalışan derlemeyi en hızlı şekilde gerçekleştirir ancak tek bir çalışana kıyasla yalnızca %14 daha hızlıdır. Daha az bellek kullanmak istiyorsanız bir çalışan iyi bir seçenektir.

Artımlı derleme genellikle daha da fazla avantaj sağlar. Temiz derlemeler nispeten nadirdir ancak derlemeler arasında tek bir dosyayı değiştirmek, özellikle test odaklı geliştirmede yaygındır. Yukarıdaki örnekte, artımlı derleme süresini gölgede bırakabilecek bazı Java dışı paketleme işlemleri de vardır.

AbstractContainerizingSandboxedSpawn.java dosyasında dahili bir dize sabiti değiştirildikten sonra yalnızca Java kaynaklarının yeniden derlenmesi (//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar) 3 kat hızlanma sağlar (bir ön ısıtma derlemesi atılarak 20 artımlı derlemenin ortalaması alınmıştır):

Artımlı derlemelerin performans iyileştirmelerini gösteren grafik

Şekil 2. Artımlı derlemelerin performans iyileştirmelerini gösteren grafik.

Hızlandırma, yapılan değişikliğe bağlıdır. Yukarıdaki durumda, yaygın olarak kullanılan bir sabit değiştirildiğinde 6 kat hızlanma ölçülür.

Kalıcı çalışanları değiştirme

Başlangıç işaretlerini çalışanlara belirtmek için --worker_extra_flag işaretini kısaltma ile anahtarlanmış olarak iletebilirsiniz. Örneğin, --worker_extra_flag=javac=--debug iletildiğinde yalnızca Javac için hata ayıklama etkinleştirilir. Bu işaretin her kullanımında yalnızca bir çalışan işareti ayarlanabilir ve yalnızca bir anımsatıcı için ayarlanabilir. Çalışanlar yalnızca her anımsatıcı için ayrı ayrı oluşturulmaz, aynı zamanda başlangıç işaretlerindeki varyasyonlar için de oluşturulur. Her bir anımsatıcı ve başlangıç işareti kombinasyonu WorkerKey ile birleştirilir ve her WorkerKey için en fazla worker_max_instances çalışan oluşturulabilir. İşlem yapılandırmasının nasıl kurulum işaretleri de belirtebileceği hakkında bilgi için sonraki bölüme bakın.

Normal öncelikli anımsatıcılara tercih edilmesi gereken bir anımsatıcıyı belirtmek için --high_priority_workers işaretini kullanabilirsiniz. Bu, her zaman kritik yolda olan işlemlere öncelik vermenize yardımcı olabilir. İstekleri yürüten iki veya daha fazla yüksek öncelikli çalışan varsa diğer tüm çalışanların çalışması engellenir. Bu işaret birden fazla kez kullanılabilir.

--worker_sandboxing işaretinin iletilmesi, her çalışan isteğinin tüm girişleri için ayrı bir sandbox dizini kullanmasını sağlar. Özel Korumalı Alan'ı ayarlamak, özellikle macOS'te biraz daha fazla zaman alır ancak daha iyi bir doğruluk garantisi sunar.

--worker_quit_after_build işareti, esas olarak hata ayıklama ve profil oluşturma için yararlıdır. Bu işaret, derleme tamamlandığında tüm çalışanların çıkmasını zorlar. Ayrıca, çalışanların ne yaptığı hakkında daha fazla bilgi almak için --worker_verbose değerini de iletebilirsiniz. Bu işaret, WorkRequest tablosundaki verbosity alanına yansıtılır ve çalışan uygulamalarının daha ayrıntılı olmasına olanak tanır.

Çalışanlar günlüklerini <outputBase>/bazel-workers dizininde saklar. Örneğin, /tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log. Dosya adı, çalışan kimliğini ve anımsatıcıyı içerir. Bir anımsatıcıda birden fazla WorkerKey olabileceğinden, belirli bir anımsatıcı için worker_max_instances'den fazla günlük dosyası görebilirsiniz.

Android derlemeleriyle ilgili ayrıntılar için Android Build Performance (Android Derleme Performansı) sayfasını inceleyin.

Kalıcı çalışanları uygulama

Çalışan oluşturma hakkında daha fazla bilgi için kalıcı çalışan oluşturma sayfasına bakın.

Bu örnekte, JSON kullanan bir çalışan için Starlark yapılandırması gösterilmektedir:

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" }
)

Bu tanıma göre, bu işlemin ilk kullanımı /bin/some_compiler -max_mem=4G --persistent_worker komut satırının yürütülmesiyle başlar. Foo.java derleme isteği şu şekilde görünür:

NOT: Protokol arabelleği spesifikasyonu "snake case" (request_id) kullanırken JSON protokolü "camel case" (requestId) kullanır. Bu belgede, JSON örneklerinde camel case, protokolden bağımsız olarak alan hakkında konuşurken ise snake case kullanılacaktır.

{
  "arguments": [ "-g", "-source", "1.5", "Foo.java" ]
  "inputs": [
    { "path": "symlinkfarm/input1", "digest": "d49a..." },
    { "path": "symlinkfarm/input2", "digest": "093d..." },
  ],
}

Çalışan, bunu yeni satırla sınırlandırılmış JSON biçiminde stdin üzerinde alır (çünkü requires-worker-protocol, JSON olarak ayarlanmıştır). Çalışan daha sonra işlemi gerçekleştirir ve stdout'unda Bazel'e JSON biçimli bir WorkResponse gönderir. Ardından Bazel, bu yanıtı ayrıştırır ve manuel olarak WorkResponse proto'ya dönüştürür. JSON yerine ikili kodlanmış protobuf kullanarak ilişkili çalışanla iletişim kurmak için requires-worker-protocol, proto olarak ayarlanır:

  execution_requirements = {
    "supports-workers" : "1" ,
    "requires-worker-protocol" : "proto"
  }

Yürütme koşullarına requires-worker-protocol eklemezseniz Bazel, çalışan iletişiminde varsayılan olarak protobuf'u kullanır.

Bazel, WorkerKey değerini anımsatıcıdan ve paylaşılan işaretlerden türetir. Bu nedenle, bu yapılandırma max_mem parametresinin değiştirilmesine izin veriyorsa kullanılan her değer için ayrı bir çalışan oluşturulur. Çok fazla varyasyon kullanılması durumunda bu durum aşırı bellek tüketimine yol açabilir.

Her çalışan şu anda yalnızca bir isteği işleyebilir. Deneysel çoklu görevli özelliği, temel araç çok iş parçacıklıysa ve sarmalayıcı bunu anlayacak şekilde ayarlanmışsa birden fazla iş parçacığı kullanmaya olanak tanır.

Bu GitHub deposunda, Java ve Python ile yazılmış örnek işçi sarmalayıcılarını görebilirsiniz. JavaScript veya TypeScript'te çalışıyorsanız @bazel/worker paketi ve nodejs worker örneği faydalı olabilir.

Çalışanlar, korumalı alanı nasıl etkiler?

Varsayılan olarak worker stratejisini kullanmak, local stratejisine benzer şekilde işlemi sandbox'ta çalıştırmaz. --worker_sandboxing işaretini ayarlayarak tüm çalışanları sanal alanlarda çalıştırabilir ve aracın her yürütülmesinde yalnızca sahip olması gereken giriş dosyalarının görüldüğünden emin olabilirsiniz. Araç, dahili olarak istekler arasında bilgi sızdırmaya devam edebilir. Örneğin, bu durum önbellek üzerinden gerçekleşebilir. dynamic stratejisini kullanmak için çalışanların korumalı alanda olması gerekir.

Derleyici önbelleklerinin çalışanlarla doğru şekilde kullanılabilmesi için her giriş dosyasıyla birlikte bir özet iletilir. Bu nedenle derleyici veya sarmalayıcı, dosyayı okumak zorunda kalmadan girişin hâlâ geçerli olup olmadığını kontrol edebilir.

İstenmeyen önbelleğe alma işlemine karşı koruma sağlamak için giriş özetleri kullanılırken bile, araç önceki isteklerden etkilenen başka bir dahili durumu koruyabileceğinden, sanal alanlı çalışanlar saf bir sanal alandan daha az katı bir sanal alan sunar.

Çoklu görev işçileri yalnızca işçi uygulaması destekliyorsa korumalı alana alınabilir ve bu korumalı alan, --experimental_worker_multiplex_sandboxing işaretiyle ayrı olarak etkinleştirilmelidir. Daha fazla ayrıntı için tasarım belgesine bakın.

Daha fazla bilgi

Kalıcı çalışanlar hakkında daha fazla bilgi için aşağıdaki kaynaklara bakın: