Kararlı Çalışanlar

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

Kalıcı çalışan, Bazel sunucusu tarafından başlatılan ve gerçek aracın (genellikle bir derleyici) etrafında bir sarmalayıcı olarak çalışan veya aracın kendisi tarafından başlatılan uzun süreli bir süreçtir. Aracın kalıcı çalışanlardan yararlanabilmesi için bir dizi derlemenin gerçekleştirilmesi ve sarmalayıcının aracın API ile aşağıda açıklanan istek/yanıt biçimi arasında çeviri yapması gerekir. Aynı çalışan, aynı derleme içinde --persistent_worker işaretiyle ve bu işaret olmadan çağrılabilir. Aracı düzgün bir şekilde başlatmak ve kullanmakla, çalışanları çıkışta kapatmaktan sorumludur. Her çalışan örneğine <outputBase>/bazel-workers altında ayrı bir çalışma dizini atanır (ancak kroot başlatılmaz).

Kalıcı çalışanları kullanmak, başlatma ek yükünü azaltan, daha fazla JIT derlemesine olanak tanıyan ve işlem yürütme sırasında 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üreli bir sürece birden çok istek göndererek bu iyileştirmeleri gerçekleştirir.

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

NodeJS çalışma zamanı 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şlemlerde, Bazel her işlem için bir araç örneği başlatmaya geri döner. Geçerli araç anımsatıcıları için worker stratejisini belirleyerek derlemenizi kalıcı çalışanlar kullanacak şekilde açıkça ayarlayabilirsiniz. En iyi uygulama olarak bu örnekte, worker stratejisinin yedeği olarak local belirtilmektedir:

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ı, bazen de artımlı derleme için daha fazla olabilir. Bazel derlemesi, çalışanlarla yaklaşık 2,5 kat daha hızlı. Daha fazla bilgi için "Çalışan sayısı seçme" bölümüne bakın.

Ayrıca yerel derleme ortamınızla eşleşen bir uzak derleme ortamınız varsa uzaktan yürütme ve çalışan yürütme yarışı yapan deneysel dinamik stratejisini kullanabilirsiniz. Dinamik stratejiyi etkinleştirmek için --experimental_spawn_scheduler işaretini geçirin. Bu strateji, çalışanları otomatik olarak etkinleştirir. Bu nedenle, worker stratejisini belirtmenize gerek yoktur ancak local veya sandboxed öğelerini yedek olarak kullanabilirsiniz.

Ç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 şekilde yararlanma ile JIT derlemesi ve elde edeceğiniz önbellek isabetleri arasında bir denge vardır. Çalışan sayısı arttıkça daha fazla hedef, JIT edilmemiş kodları çalıştırma ve soğuk önbelleğe alma işlemlerinin başlatma maliyetlerini öder. Derlenecek az sayıda hedefiniz 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, hatırlatıcı ve işaret grubu başına maksimum çalışan örneği sayısını belirler (aşağıya bakın). Bu nedenle, karma bir sistemde varsayılan değeri korursanız oldukça fazla bellek kullanabilirsiniz. Artımlı derlemelerde birden fazla çalışan örneğinin avantajı daha da küçüktür.

Bu grafikte, 64 GB RAM'e sahip 6 çekirdekli hiper iş parçacıklı Intel Xeon 3,5 GHz Linux iş istasyonunda Bazel (hedef //src:bazel) için en baştan 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.

Net derlemelerin performans iyileştirmeleri grafiği

Şekil 1. Temiz derlemelerin performans iyileştirmelerinin grafiği.

Bu yapılandırmada, bir çalışana kıyasla yalnızca %14 artışla iki çalışan en hızlı derlemeyi sağlar. Daha az bellek kullanmak istiyorsanız bir çalışan iyi bir seçenektir.

Artımlı derleme genellikle daha da faydalıdır. Temiz derlemeler nispeten nadirdir ancak derlemeler arasında tek bir dosyanın değiştirilmesi, özellikle test odaklı geliştirmede yaygındır. Yukarıdaki örnekte, artımlı derleme süresini gölgede bırakabilecek bazı Java dışı paket işlemleri de bulunmaktadır.

AbstractContainerizingSandboxedSpawn.java içinde dahili dize sabiti değiştirildikten sonra yalnızca Java kaynaklarının (//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar) yeniden derlenmesi 3 kat hız sağlar (bir Isınma derlemesi silinerek ortalama 20 artımlı derleme):

Artımlı derlemelerin performans iyileştirmeleri grafiği

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

Hız, yapılan değişikliğe bağlıdır. Yukarıdaki durumda, yaygın olarak kullanılan bir sabit değer değiştirildiğinde faktör 6'nın hızlanması ölçülür.

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

Çalışanlara başlangıç bayrakları belirtmek için --worker_extra_flag işaretini geçirebilirsiniz. Bu işaret, anımsatıcıyla anahtarlanır. Örneğin, --worker_extra_flag=javac=--debug geçirildiğinde yalnızca Javac için hata ayıklama etkinleştirilir. Bu işaretin her kullanımı için yalnızca bir çalışan işareti ayarlanabilir ve yalnızca bir hatırlatıcı ayarlanabilir. Çalışanlar yalnızca her anımsatıcı için ayrı ayrı değil, başlangıç bayraklarındaki varyasyonlar için de oluşturulur. Her anımsatıcı ve başlangıç işareti kombinasyonu bir WorkerKey içinde 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 belirleyebileceğini öğrenmek için bir sonraki bölüme bakın.

Normal öncelikli anımsatıcılar yerine çalıştırılması gereken bir anımsatıcı belirtmek için --high_priority_workers işaretini kullanabilirsiniz. Bu sayede her zaman kritik yolda olan işlemlere öncelik verebilirsiniz. İstek 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 geçilmesi, her çalışan isteğinin tüm girişleri için ayrı bir korumalı alan dizini kullanmasını sağlar. sandbox oluşturulması (özellikle macOS'te) biraz daha zaman alır ancak daha iyi bir doğruluk garantisi sağlar.

--worker_quit_after_build işareti genellikle hata ayıklama ve profil oluşturma için kullanışlıdır. Bu işaret, bir derleme tamamlandığında tüm çalışanları çalışmaya zorlar. Çalışanların ne yaptığı hakkında daha fazla çıkış elde etmek için --worker_verbose parametresini de iletebilirsiniz. Bu işaret, WorkRequest öğesindeki verbosity alanına yansıtılır ve çalışan uygulamaları daha ayrıntılı hale gelir.

Çalışanlar, günlüklerini <outputBase>/bazel-workers dizininde depolar (ö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. Hafıza başına birden fazla WorkerKey olabileceğinden, belirli bir anımsatıcı için birden fazla worker_max_instances günlük dosyası görebilirsiniz.

Android derlemeleri için Android Derlemesi Performansı sayfasındaki ayrıntılara bakın.

Kalıcı çalışanları uygulama

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

Bu örnekte, JSON kullanan bir çalışanın 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ımda bu eylemin ilk kullanımı, /bin/some_compiler -max_mem=4G --persistent_worker komut satırının yürütülmesiyle başlar. Foo.java öğesini derleme isteği şu şekilde görünür:

NOT: Protokol arabelleği spesifikasyonu "yılan kılıfı" (request_id) kullanırken JSON protokolü "deve vakası" (requestId) kullanır. Bu belgede JSON örneklerinde büyük/küçük harf kullanımı, protokolden bağımsız olarak alan hakkında konuşurken ise yılan durumu kullanılacaktır.

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

Çalışan, bu mesajı stdin üzerinde yeni satırlarla ayrılmış JSON biçiminde alır (çünkü requires-worker-protocol JSON değerine ayarlandığından). Ardından, çalışan işlemi gerçekleştirir ve stdout'ta Bazel'e JSON biçiminde bir WorkResponse gönderir. Daha sonra Bazel bu yanıtı ayrıştırır ve manuel olarak WorkResponse protokolüne dönüştürür. JSON yerine ikili kodlamalı protobuf kullanarak ilişkili çalışanla 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"
  }

Yürütme gereksinimlerine requires-worker-protocol eklemezseniz Bazel, çalışan iletişimini varsayılan olarak protobuf kullanacak şekilde ayarlar.

Bazel, WorkerKey parametresini anımsatıcılardan ve paylaşılan işaretlerden elde eder. Bu nedenle, bu yapılandırma max_mem parametresinin değiştirilmesine izin verdiyse kullanılan her değer için ayrı bir çalışan oluşturulur. Bu durum, çok fazla varyasyon kullanılırsa aşırı bellek tüketimine neden olabilir.

Şu anda her çalışan tek seferde yalnızca bir isteği işleyebilir. Temel aracın çok iş parçacığı kullanılıyorsa ve sarmalayıcı bunu anlayacak şekilde ayarlanmışsa deneysel Multiplex çalışanlar özelliği birden çok iş parçacığı kullanılmasına olanak tanır.

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

Çalışanlar korumalı alana almayı nasıl etkiler?

Varsayılan olarak worker stratejisi kullanıldığında, işlem local stratejisine benzer şekilde bir sandbox çalıştırılmaz. --worker_sandboxing işaretini, tüm çalışanları korumalı alanlarda çalıştıracak şekilde ayarlayabilirsiniz. Böylece, aracın her çalıştırmasının yalnızca olması gereken giriş dosyalarını görmesini sağlayabilirsiniz. Araç yine de istekler arasında dahili olarak (örneğin bir önbellek üzerinden) bilgi sızdırabilir. dynamic stratejisini kullanmak için çalışanların korumalı alana alınması gerekir.

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

İstenmeyen önbelleğe alma işlemlerine karşı koruma sağlamak için giriş özetleri kullanılırken bile, korumalı alana alınan çalışanlar saf korumalı alana göre daha az katı korumalı alan sunar. Bunun nedeni, aracın önceki isteklerden etkilenen diğer dahili durumları koruyabilmesidir.

Multiplex çalışanları, yalnızca çalışan uygulaması tarafından destekleniyorsa korumalı alana alınabilir. Bu korumalı alanın, --experimental_worker_multiplex_sandboxing işaretiyle ayrı olarak etkinleştirilmesi gerekir. Daha fazla ayrıntıyı tasarım dokümanında bulabilirsiniz).

Daha fazla bilgi

Kalıcı çalışanlar hakkında daha fazla bilgi için şu konulara bakın: