동적 실행은 버전 0.21부터 Bazel의 기능으로, 동일한 작업의 로컬 실행과 원격 실행이 동시에 시작되고, 완료된 첫 번째 브랜치의 출력을 사용하여 다른 브랜치를 취소합니다. 원격 빌드 시스템의 실행 성능 또는 대규모 공유 캐시와 로컬 실행의 짧은 지연 시간을 결합하여 깔끔한 빌드와 증분 빌드 모두에 최상의 환경을 제공합니다.
이 페이지에서는 동적 실행을 사용 설정, 조정, 디버그하는 방법을 설명합니다. 로컬 실행과 원격 실행을 모두 설정했으며 성능을 개선하기 위해 Bazel 설정을 조정하려고 하는 경우 이 페이지가 도움이 됩니다. 아직 원격 실행을 설정하지 않았다면 먼저 Bazel 원격 실행 개요로 이동하세요.
동적 실행을 사용 설정하고 있나요?
동적 실행 모듈은 Bazel의 일부이지만 동적 실행을 사용하려면 이미 동일한 Bazel 설정에서 로컬과 원격에서 모두 컴파일할 수 있어야 합니다.
동적 실행 모듈을 사용 설정하려면 --internal_spawn_scheduler
플래그를 Bazel에 전달합니다. 그러면 dynamic
라는 새로운 실행 전략이 추가됩니다. 이제 이를 동적으로 실행하려는 니모닉(예: --strategy=Javac=dynamic
)의 전략으로 사용할 수 있습니다. 동적 실행을 사용 설정할 니모닉을 선택하는 방법은 다음 섹션을 참고하세요.
동적 전략을 사용하는 모든 mnemonic의 경우 원격 실행 전략은 --dynamic_remote_strategy
플래그에서 가져오고 로컬 전략은 --dynamic_local_strategy
플래그에서 가져옵니다. --dynamic_local_strategy=worker,sandboxed
를 전달하면 동적 실행의 로컬 브랜치에 작업자 또는 샌드박스 실행을 시도할 기본값이 설정됩니다. --dynamic_local_strategy=Javac=worker
를 전달하면 Javac 니모닉의 기본값만 재정의됩니다. 원격 버전도 동일한 방식으로 작동합니다. 두 플래그 모두 여러 번 지정할 수 있습니다. 작업을 로컬에서 실행할 수 없는 경우 평소와 같이 원격으로 실행되고 그 반대의 경우도 마찬가지입니다.
원격 시스템에 캐시가 있는 경우 --local_execution_delay
플래그는 원격 시스템에서 캐시 적중을 나타낸 후 로컬 실행에 밀리초 단위의 지연을 추가합니다. 이렇게 하면 캐시 히트가 더 많이 발생할 가능성이 있는 경우 로컬 실행을 실행하지 않아도 됩니다. 기본값은 1000밀리초이지만 캐시 적중 시 걸리는 시간보다 약간 더 길게 조정해야 합니다. 실제 시간은 원격 시스템과 왕복하는 데 걸리는 시간에 따라 다릅니다. 일반적으로 이 값은 왕복 지연 시간을 추가할 만큼 충분히 멀리 떨어져 있는 일부 사용자가 아니라면 지정된 원격 시스템의 모든 사용자에게 동일합니다. Bazel 프로파일링 기능을 사용하여 일반적인 캐시 히트가 걸리는 시간을 확인할 수 있습니다.
동적 실행은 로컬 샌드박스 전략과 영구 작업자와 함께 사용할 수 있습니다. 영구 작업자는 동적 실행과 함께 사용하면 자동으로 샌드박스로 실행되며 다중 작업자를 사용할 수 없습니다. Darwin 및 Windows 시스템에서는 샌드박스 전략이 느릴 수 있습니다. 이러한 시스템에서 샌드박스를 만드는 오버헤드를 줄이기 위해 --reuse_sandbox_directories
를 전달할 수 있습니다.
동적 실행은 standalone
전략으로 실행할 수도 있지만, standalone
전략은 실행을 시작할 때 출력 잠금을 가져와야 하므로 원격 전략이 먼저 완료되는 것을 효과적으로 차단합니다. --experimental_local_lockfree_output
플래그를 사용하면 로컬 실행이 출력에 직접 쓸 수 있도록 허용하면서 원격 실행이 먼저 완료되면 원격 실행에 의해 중단되도록 허용하여 이 문제를 해결할 수 있습니다.
동적 실행의 브랜치 중 하나가 먼저 완료되었지만 실패하면 전체 작업이 실패합니다. 이는 로컬 실행과 원격 실행 간의 차이가 눈에 띄지 않도록 하기 위한 의도적인 선택입니다.
동적 실행 및 잠금의 작동 방식에 관한 자세한 내용은 Julio Merino의 훌륭한 블로그 게시물을 참고하세요.
동적 실행은 언제 사용해야 하나요?
동적 실행에는 어떤 형태로든 원격 실행 시스템이 필요합니다. 캐시 미스가 실패한 작업으로 간주되므로 현재 캐시 전용 원격 시스템을 사용할 수 없습니다.
일부 작업 유형은 원격 실행에 적합하지 않습니다. 가장 적합한 후보는 지속형 작업자를 사용하는 등 로컬에서 본질적으로 더 빠른 코드이거나 원격 실행의 오버헤드가 실행 시간을 지배할 만큼 충분히 빠르게 실행되는 코드입니다. 로컬에서 실행되는 각 작업은 일정량의 CPU 및 메모리 리소스를 잠그므로 이러한 카테고리에 속하지 않는 작업을 실행하면 해당 카테고리에 속하는 작업의 실행이 지연될 뿐입니다.
5.0.0-pre.20210708.4 출시부터 성능 프로파일링에는 동적 실행 경합에서 패배한 후 작업 요청을 완료하는 데 걸린 시간을 비롯하여 작업자 실행에 관한 데이터가 포함됩니다. 동적 실행 작업자 스레드가 리소스를 가져오는 데 많은 시간을 소비하거나 async-worker-finish
에서 많은 시간을 소비하는 경우 느린 로컬 작업으로 인해 작업자 스레드가 지연될 수 있습니다.
위의 프로필은 8개의 Javac 작업자를 사용하며, 많은 Javac 작업자가 경합에서 지고 async-worker-finish
스레드에서 작업을 완료한 것을 볼 수 있습니다. 이는 작업자가 아닌 니모닉이 작업자를 지연시키기에 충분한 리소스를 사용했기 때문입니다.
동적 실행으로 Javac만 실행하면 시작된 작업자 중 약 절반만 작업을 시작한 후 경합에서 지고 맙니다.
이전에 권장된 --experimental_spawn_scheduler
플래그는 지원 중단되었습니다.
동적 실행을 사용 설정하고 모든 니모닉의 기본 전략으로 dynamic
를 설정합니다. 이로 인해 이러한 유형의 문제가 발생하는 경우가 많습니다.
문제 해결
동적 실행 문제는 로컬 실행과 원격 실행의 특정 조합에서만 나타날 수 있으므로 미묘하고 디버그하기 어려울 수 있습니다.
--debug_spawn_scheduler
는 이러한 문제를 디버그하는 데 도움이 되는 동적 실행 시스템의 추가 출력을 추가합니다. --local_execution_delay
플래그와 원격 작업과 로컬 작업의 수를 조정하여 문제를 더 쉽게 재현할 수도 있습니다.
standalone
전략을 사용하여 동적 실행에 문제가 있는 경우 --experimental_local_lockfree_output
없이 실행하거나 로컬 작업을 샌드박스 처리하여 실행해 보세요. 이렇게 하면 빌드 속도가 약간 느려질 수 있지만 (Mac 또는 Windows를 사용하는 경우 위 참고) 오류의 원인이 될 수 있는 몇 가지 요소가 제거됩니다.