Kararlı Çalışanlar

Sorun bildir Kaynağı göster

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 uzun süreli bir süreçtir. Bu süreç, gerçek aracı (genellikle bir derleyici) etrafında bir sarmalayıcı olarak işlev görür veya aracın kendisidir. Kalıcı çalışanlardan yararlanmak için aracın bir dizi derleme yapmasını desteklemesi ve sarmalayıcının aracın API'si ile aşağıda açıklanan istek/yanıt biçimi arasında geçiş yapması gerekir. Aynı çalışan, aynı derlemede --persistent_worker işaretiyle ve bu işaret olmadan çağrılabilir. Ayrıca, aracı düzgün bir şekilde başlatmak ve konuşmaktan, ayrıca çıkışta çalışanları kapatmaktan sorumludur. Her çalışan örneği, <outputBase>/bazel-workers altında ayrı bir çalışma dizini atanır (ancak krootlanmış değildir).

Kalıcı çalışanları kullanmak, başlangıç 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 işleme birden çok istek göndererek bu iyileştirmeleri sağlar.

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, uzaktan yürütme öncelikli olsa da derlemeleri yürütürken varsayılan olarak kalıcı çalışanlar kullanır. Kalıcı çalışanları desteklemeyen işlemler için 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 ayarlayarak derlemenizi kalıcı çalışanlar kullanacak şekilde açık bir şekilde ayarlayabilirsiniz. En iyi uygulama olarak bu örnekte, worker stratejisi için yedek olarak local belirtilmesi bulunuyor:

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 için derlemeler 2-4 kat daha hızlı, bazen de artımlı derleme için daha fazla olabilir. Bazel'i derlemek, çalışanlarla yaklaşık 2,5 kat daha hızlı. 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 uzaktan derleme ortamınız da varsa uzaktan yürütme ve çalışan yürütmesi ile yarışan deneysel dinamik stratejisini 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 belirtmenize gerek yoktur ancak yedek olarak local veya sandboxed kullanabilirsiniz.

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

Hatırlatı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 elde ettiğiniz JIT derlemesi ve önbellek isabetlerinin miktarı arasında bir denge vardır. Çalışan sayısı arttıkça daha fazla hedef, JIT olmayan kod çalıştırma ve soğuk önbelleğe alma maliyetleri için başlangıç maliyetlerini öder. Oluşturmanız gereken hedef sayısı azsa 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, anımsatıcı ve işaret grubu (aşağıya bakın) başına maksimum çalışan örneği sayısını belirler. Bu nedenle, varsayılan değeri korursanız karma bir sistemde oldukça fazla bellek kullanabilirsiniz. Artımlı derlemeler için birden fazla çalışan örneğinin avantajı daha da küçüktür.

Bu grafik, 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 zamanlarını gösterir. 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 derlemelerin performans iyileştirmelerini gösteren grafik

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

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

Artımlı derleme genellikle daha fazla avantaj sağlar. 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ölgeleyebilecek bazı Java dışı paketleme işlemleri de vardır.

AbstractContainerizingSandboxedSpawn.java dosyasında 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 kazandırır (bir ısınma derlemesi ile ortalama 20 artımlı derleme):

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

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 sabitin değiştirildiği durumlarda 6 faktörü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 aktarabilirsiniz. Ö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ı ve yalnızca bir anımsatıcı için yalnızca bir çalışan işareti 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 bayraklarını nasıl belirtebileceğini öğrenmek için bir sonraki bölüme bakın.

Normal öncelikli anımsatıcılara tercih olarak çalıştırılması gereken bir anımsatıcı belirtmek için --high_priority_workers işaretini kullanabilirsiniz. Bu, her zaman kritik yolunda olan işlemlere öncelik verilmesine yardımcı olabilir. İ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 çok kez kullanılabilir.

--worker_sandboxing işaretinin iletilmesi, 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, en çok hata ayıklama ve profil oluşturma için kullanışlıdır. Bu işaret, tüm çalışanları derleme tamamlandığında çalışmayı bırakmaya zorlar. Çalışanların neler yaptığı hakkında daha fazla çıkış almak için --worker_verbose parametresini de iletebilirsiniz. Bu işaret, WorkRequest içindeki verbosity alanına yansıtılarak çalışan uygulamalarının da daha ayrıntılı olabilmesine olanak tanır.

Ç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. Hatırlatıcı başına birden fazla WorkerKey olabileceğinden belirli bir anımsatıcı için worker_max_instances adetten fazla günlük dosyası görebilirsiniz.

Android derlemeleri için Android Derleme 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ışanlar oluşturma sayfasını inceleyin.

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

NOT: Protokol arabelleği spesifikasyonu "yılan kılıfı" (request_id) kullanırken JSON protokolü "deve durumu" (requestId) kullanır. Bu belgede, JSON örneklerinde deve olgusu, 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, bunu stdin üzerinde yeni satırlarla ayrılmış JSON biçiminde alır (requires-worker-protocol JSON olarak ayarlandığından). Daha sonra, çalışan işlemi gerçekleştirir ve stdout'ta Bazel'e JSON biçimli 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 kodlu 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 varsayılan olarak çalışan iletişimini protobuf kullanacak şekilde ayarlar.

Bazel, WorkerKey anımsatıcılarından ve paylaşılan işaretlerden türetir. Dolayısıyla bu yapılandırma, max_mem parametresinin değiştirilmesine olanak tanıyorsa kullanılan her değer için ayrı bir çalışan oluşturulur. Bu da ç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. Deneysel Multiplex çalışanlar özelliği, temel aracın çok iş parçacıklı olması ve sarmalayıcı bunu anlayacak şekilde ayarlanmışsa birden fazla iş parçacığının kullanılmasına olanak tanır.

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

Çalışanlar korumalı alanı 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 yürütme işlemi, yalnızca olması gereken giriş dosyalarını görür. Araç, istekler arasında dahili olarak (örneğin, bir önbellek) 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 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 alma işlemlerine karşı koruma sağlamak için giriş özetleri kullanılırken bile, araç önceki isteklerden etkilenen diğer dahili durumları koruyabildiğinden, korumalı alana sahip çalışanlar saf korumalı alana göre daha az katı korumalı alan sunar.

Multiplex çalışanları, yalnızca çalışan uygulaması destekliyorsa korumalı alana alınabilir. Bu korumalı alana alma işlemi, --experimental_worker_multiplex_sandboxing işaretiyle ayrı olarak etkinleştirilmelidir. Daha fazla ayrıntı için tasarım belgesini inceleyin).

Daha fazla bilgi

Kalıcı çalışanlar hakkında daha fazla bilgi için şu makaleyi inceleyin: