Kararlı Çalışanlar

Sorun bildirme Kaynağı görüntüleme Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bu sayfada, kalıcı çalışanların nasıl kullanılacağı, avantajları, koşulları ve çalışanların korumalı alanı nasıl etkilediği ele alınmaktadır.

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

Kalıcı çalışanlar kullanmak, başlangıç maliyetini düşüren, daha fazla JIT derlemesine olanak tanıyan ve örneğin işlem yürütmedeki soyut söz dizimi ağaçlarının önbelleğe alınmasını sağlayan bir yürütme stratejisidir. Bu strateji, uzun süren bir işleme birden fazla istek göndererek bu iyileştirmeleri sağlar.

Kalıcı çalışanlar Java, Scala, Kotlin ve daha birçok dil için uygulanır.

NodeJS çalışma zamanı kullanan programlar, işleyici 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. Bununla birlikte, uzaktan yürütme önceliklidir. Kalıcı çalışanları desteklemeyen işlemler için Bazel, her işlem için bir araç örneği başlatır. Geçerli araç anımsalları için workerstratejiyi ayarlayarak derlemenizin kalıcı çalışanlar kullanacağını açıkça belirtebilirsiniz. En iyi uygulama olarak bu örnekte, worker stratejisine yedek olarak local belirtilmiştir:

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

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

Yerel derleme ortamınızla eşleşen bir uzaktan derleme ortamınız varsa uzaktan yürütme ve çalışan yürütme yöntemini kullanan deneysel dinamik stratejisini kullanabilirsiniz. Dinamik stratejiyi etkinleştirmek için --experimental_spawn_scheduler bayrağını iletin. Bu strateji, işçileri otomatik olarak etkinleştirir. Bu nedenle, worker stratejisini belirtmeniz gerekmez. Ancak yedek olarak local veya sandboxed'yi kullanmaya devam edebilirsiniz.

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

Anımsatıcı başına 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 ve JIT derlemesi ile önbellek isabetlerinin miktarı arasında bir denge vardır. Daha fazla çalışanla, daha fazla hedef, JIT'siz kod çalıştırma ve soğuk önbelleğe alma işlemlerinin başlangıç maliyetlerini karşılar. Derlemeniz gereken az sayıda hedef varsa tek bir çalışan, derleme hızı ile kaynak kullanımı arasında en iyi dengeyi sağlayabilir (örneğin, 8586 numaralı soruna bakın). worker_max_instances işareti, her mnemoni ve işaret grubu için maksimum işleyici örneği sayısını belirler (aşağıya bakın). Bu nedenle, karma bir sistemde varsayılan değeri kullanırsanız çok fazla bellek kullanabilirsiniz. Artımlı derlemelerde birden çok çalışan örneğinin avantajı daha da azdır.

Bu grafikte, 64 GB RAM'e sahip 6 çekirdekli hiper iş parçacıklı Intel Xeon 3,5 GHz Linux iş istasyonunda 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ört derlemenin ortalaması alınır.

Temiz derlemelerde performans iyileştirmelerini gösteren grafik

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

Bu yapılandırmada, iki çalışan en hızlı derlemeyi sağlar ancak tek bir çalışana kıyasla yalnızca %14 oranında iyileşme sağlanır. Daha az bellek kullanmak istiyorsanız bir işleyici iyi bir seçenektir.

Artımlı derleme genellikle daha da fazla avantaj sağlar. Temiz derlemeler nispeten nadirdir ancak özellikle test odaklı geliştirmede, derlemeler arasında tek bir dosyanın değiştirilmesi yaygın karşılaşılan bir durumdur. Yukarıdaki örnekte, artımlı derleme süresini gölgeleyebilecek bazı Java dışı paketleme işlemleri de vardır.

AbstractContainerizingSandboxedSpawn.java içinde bir dahili dize sabit değeri değiştirildikten sonra yalnızca Java kaynaklarını (//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar) yeniden derlerseniz 3 kat hızlandırılmış (bir ısınma derlemesi silinmiş ortalama 20 artımlı derleme) elde edilir:

Artımlı derlemelerdeki performans iyileştirmelerinin grafiği

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

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

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

Çalışanlara başlangıç işaretlerini belirtmek için --worker_extra_flag işaretini iletebilirsiniz. Örneğin, --worker_extra_flag=javac=--debug parametresini iletmek yalnızca Javac için hata ayıklamayı etkinleştirir. Bu işaretin her kullanımı için yalnızca bir işçi işareti ve yalnızca bir anımsatıcı ayarlanabilir. İşçiler her anımsatıcı için ayrı ayrı değil, aynı zamanda başlangıç bayraklarındaki varyasyonlar için de oluşturulur. Her bir kısaltma ve başlangıç işareti kombinasyonu bir WorkerKey olarak birleştirilir ve her WorkerKey için en fazla worker_max_instances çalışan oluşturulabilir. İşlem yapılandırmasının kurulum işaretlerini nasıl belirtebileceğini öğrenmek için sonraki bölüme bakın.

Normal öncelikli anımsatıcılara tercih edilerek çalıştırılması gereken bir anımsatıcı 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 çok kez kullanılabilir.

--worker_sandboxing işaretçisi iletildiği takdirde her çalışan isteği, tüm girişleri için ayrı bir korumalı alan dizini kullanır. Korumalı alanın oluşturulması özellikle macOS'te biraz daha zaman alır ancak daha iyi doğruluk garantisi verir.

--worker_quit_after_build işareti, çoğunlukla hata ayıklama ve profil oluşturma için yararlıdır. Bu işaret, bir derleme tamamlandığında tüm iş parçacıklarını çıkmaya zorlar. Ayrıca, çalışanların ne yaptığıyla ilgili daha fazla sonuç almak için --worker_verbose parametresini de iletebilirsiniz. Bu işaret, WorkRequest dilindeki verbosity alanına yansıtılarak çalışan uygulamalarının daha ayrıntılı olmasına da olanak tanır.

Çalışanlar, günlüklerini <outputBase>/bazel-workers dizininde depolar (ör. /tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log). Dosya adı, çalışan kimliğini ve anımsatıcıyı içerir. Her anımsatıcı için birden fazla WorkerKey olabilir. Bu nedenle, belirli bir anımsatıcı için worker_max_instances'ten fazla günlük dosyası görebilirsiniz.

Android derlemeleri için Android Derleme Performansı sayfasında ayrıntıları inceleyin.

Kalıcı çalışanları uygulama

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

Bu örnekte, JSON kullanan bir işleyici 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ım doğrultusunda, 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 "yılan büyük/küçük harf" (request_id) kullanırken, JSON protokolünde "deve büyük/küçük harf" (requestId) kullanılır. Bu dokümanda, JSON örneklerinde büyük/küçük harf kullanılır, ancak protokolden bağımsız olarak alan hakkında konuşurken yılan büyük/küçük harf kullanılır.

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

Çalışan, bunu stdin üzerinde yeni satırla sınırlandırılmış JSON biçiminde alır (requires-worker-protocol JSON olarak ayarlandığından). İşleyici daha sonra işlemi gerçekleştirir ve stdout'sinde Bazel'e JSON biçiminde bir WorkResponse gönderir. Daha sonra Bazel bu yanıtı ayrıştırır ve manuel olarak WorkResponse protosuna dönüştürür. JSON yerine ikili kodlu protobuf kullanarak ilişkili işleyiciyle iletişim kurmak için requires-worker-protocol, aşağıdaki gibi proto olarak ayarlanır:

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

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

Bazel, WorkerKey değerini kısaltmadan ve paylaşılan işaretlerden türetmektedir. Bu nedenle, bu yapılandırma max_mem parametresinin değiştirilmesine izin veriyorsa kullanılan her değer için ayrı bir işleyici oluşturulur. Çok fazla varyasyon kullanılırsa bu durum aşırı bellek tüketimine yol açabilir.

Her çalışan şu anda bir seferde yalnızca bir isteği işleyebilir. Deneysel çoklu işleyici özelliği, temel araç çoklu iş parçacıklıysa ve sarmalayıcı bunu anlayacak şekilde ayarlandıysa birden fazla iş parçacığı kullanılmasına olanak tanır.

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

İşçiler korumalı alanı nasıl etkiler?

Varsayılan olarak worker stratejisi kullanıldığında işlem, local stratejisine benzer şekilde bir korumalı alanda çalıştırılmaz. --worker_sandboxing işaretini, tüm işleyicileri korumalı alan içinde çalıştıracak şekilde ayarlayarak aracın her çalıştırmasında yalnızca olması gereken giriş dosyalarının gösterilmesini sağlayabilirsiniz. Araç, istekler arasında dahili olarak (ör. önbelleğe alma yoluyla) bilgi sızdırmaya devam edebilir. dynamic stratejisinin kullanılması çalışanların korumalı alana alınmasını gerektirir.

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

İstenmeyen önbelleğe almaya karşı koruma sağlamak için giriş özetlerini kullanırken bile, korumalı alan çalışanları, önceki isteklerden etkilenen diğer dahili durumları saklayabileceğinden, saf korumalı alana kıyasla daha az katı korumalı alan sunar.

Multiplex çalışanları, yalnızca çalışan uygulaması destekliyorsa korumalı alana alınabilir. Bu korumalı alan, --experimental_worker_multiplex_sandboxing işaretiyle ayrı olarak etkinleştirilmelidir. Daha fazla ayrıntıyı tasarım belgesinde bulabilirsiniz.)

Daha fazla bilgi

Kalıcı çalışanlar hakkında daha fazla bilgi için bkz: