동적 실행

문제 신고하기 소스 보기

동적 실행은 동일한 작업의 로컬 및 원격 실행이 동시에 시작되고 완료된 첫 번째 브랜치의 출력을 사용하여 다른 브랜치를 취소하는 Bazel의 기능입니다. 원격 빌드 시스템의 실행 성능 또는 대규모 공유 캐시와 로컬 실행의 짧은 지연 시간을 결합하여 클린 빌드와 증분 빌드 모두를 위한 최상의 결과를 제공합니다.

이 페이지에서는 동적 실행을 사용 설정, 조정, 디버그하는 방법을 설명합니다. 로컬 및 원격 실행이 모두 설정되어 있고 성능 향상을 위해 Bazel 설정을 조정하려는 경우 이 페이지를 참고하세요. 아직 원격 실행을 설정하지 않았으면 먼저 Bazel 원격 실행 개요로 이동하세요.

동적 실행을 사용 설정하시겠어요?

동적 실행 모듈은 Bazel의 일부이지만 동적 실행을 이용하려면 동일한 Bazel 설정에서 로컬 및 원격으로 컴파일할 수 있어야 합니다.

동적 실행 모듈을 사용 설정하려면 --internal_spawn_scheduler 플래그를 Bazel에 전달합니다. 그러면 dynamic라는 새 실행 전략이 추가됩니다. 이제 동적으로 실행하려는 니모닉의 전략으로 이를 사용할 수 있습니다(예: --strategy=Javac=dynamic). 동적 실행을 사용 설정할 니모닉을 선택하는 방법은 다음 섹션을 참고하세요.

동적 전략을 사용하는 모든 니모닉의 경우 원격 실행 전략은 --dynamic_remote_strategy 플래그에서 가져오고 로컬 전략은 --dynamic_local_strategy 플래그에서 가져옵니다. --dynamic_local_strategy=worker,sandboxed를 전달하면 동적 실행의 로컬 브랜치에서 작업자 또는 샌드박스 실행을 순서대로 시도할 기본값이 설정됩니다. --dynamic_local_strategy=Javac=worker를 전달하면 Javac 니모닉의 기본값만 재정의됩니다. 원격 버전도 같은 방식으로 작동합니다. 두 플래그를 모두 여러 번 지정할 수 있습니다. 작업을 로컬에서 실행할 수 없으면 평소와 같이 원격으로 실행되며 그 반대의 경우도 마찬가지입니다.

원격 시스템에 캐시가 있는 경우 --dynamic_local_execution_delay 플래그는 원격 시스템이 캐시 적중을 표시한 후 로컬 실행에 지연을 밀리초 단위로 추가합니다. 이렇게 하면 캐시 적중률이 더 높을 때 로컬 실행이 이루어지는 것을 방지할 수 있습니다. 기본값은 1, 000ms이지만 일반적으로 캐시 적중보다 조금 더 길게 조정해야 합니다. 실제 시간은 원격 시스템과 왕복 소요 시간에 따라 다릅니다. 사용자 중 일부가 왕복 지연 시간을 추가할 만큼 충분히 멀리 떨어져 있지 않는 한 일반적으로 특정 원격 시스템의 모든 사용자에 대해 값은 동일합니다. 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만 동적 실행으로 실행되는 경우 시작된 worker의 약 절반만 작업을 시작한 후 경합에서 지게 됩니다.

이전에 권장된 --experimental_spawn_scheduler 플래그는 지원 중단되었습니다. 동적 실행이 사용 설정되고 모든 니모닉의 기본 전략으로 dynamic가 설정되므로 대개 이러한 종류의 문제가 발생합니다.

성능

동적 실행 접근 방식은 로컬 및 원격으로 사용 가능한 리소스가 충분하므로 전반적인 성능을 개선하기 위해 추가 리소스를 사용할 가치가 있다고 가정합니다. 하지만 리소스를 과도하게 사용하면 Bazel 자체 또는 Bazel이 실행되는 머신의 속도가 느려지거나 원격 시스템에 예기치 않은 압력이 가해질 수 있습니다. 동적 실행의 동작을 변경할 수 있는 몇 가지 옵션이 있습니다.

--dynamic_local_execution_delay는 현재 빌드 중에 원격 캐시 적중이 발생한 경우에만 원격 브랜치가 시작된 후 몇 밀리초 정도 로컬 브랜치 시작을 지연시킵니다. 이렇게 하면 원격 캐싱의 이점을 누리는 빌드가 대부분의 출력을 캐시에서 찾을 수 있을 때 로컬 리소스를 낭비하지 않습니다. 캐시 품질에 따라 이를 줄이면 빌드 속도가 향상되지만, 로컬 리소스를 더 많이 사용하게 될 수 있습니다.

--experimental_dynamic_local_load_factor는 실험용 고급 리소스 관리 옵션입니다. 0에서 1 사이의 값을 취하며 이 기능을 끄는 0입니다. 0보다 큰 값으로 설정하면 Bazel은 예약 대기 중인 작업이 많을 때 로컬에서 예약된 작업 수를 조정합니다. 이 값을 1로 설정하면 사용 가능한 CPU 수만큼의 작업을 예약할 수 있습니다 (--local_cpu_resources 기준). 값이 작을수록 실행할 수 있는 작업 수가 많아짐에 따라 예약된 작업 수가 더 적게 설정됩니다. 이는 직관적이지 않을 수 있지만 좋은 원격 시스템을 사용하면 많은 작업을 실행할 때 로컬 실행은 큰 도움이 되지 않으며 로컬 CPU는 원격 작업을 관리하는 데 더 적합합니다.

--experimental_dynamic_slow_remote_time는 원격 브랜치가 최소한 이 시간 동안 실행되고 있을 때 로컬 브랜치를 시작하는 데 우선순위를 둡니다. 일반적으로 가장 최근에 예약된 작업이 레이스에서 이길 가능성이 가장 높으므로 우선순위가 높지만 원격 시스템이 가끔 중단되거나 시간이 더 오래 걸리는 경우 빌드가 진행될 수 있습니다. 이 기능은 원격 시스템의 문제 해결이 필요한 부분을 숨길 수 있으므로 기본적으로 사용 설정되지 않습니다. 이 옵션을 사용 설정하는 경우 원격 시스템 성능을 모니터링해야 합니다.

--experimental_dynamic_ignore_local_signals는 특정 신호로 인해 로컬 생성이 종료될 때 원격 브랜치가 인계받도록 하는 데 사용할 수 있습니다. 이는 작업자 리소스 제한 (--experimental_worker_memory_limit_mb, --experimental_worker_sandbox_hardening, --experimental_sandbox_memory_limit_mb)과 함께 주로 유용하며, 작업자 프로세스가 너무 많은 리소스를 사용하면 종료될 수 있습니다.

JSON 트레이스 프로필에는 성능 및 리소스 사용량의 절충을 개선하는 방법을 식별하는 데 도움이 되는 여러 성능 관련 그래프가 포함되어 있습니다.

문제 해결

동적 실행과 관련된 문제는 로컬 실행과 원격 실행의 특정 조합에서만 나타날 수 있으므로 미묘하고 디버그하기 어려울 수 있습니다. --debug_spawn_scheduler는 동적 실행 시스템에서 이러한 문제를 디버그하는 데 도움이 되는 추가 출력을 추가합니다. 또한 문제를 더 쉽게 재현하도록 --dynamic_local_execution_delay 플래그와 원격 작업과 로컬 작업 수를 조정할 수 있습니다.

standalone 전략을 사용하는 동적 실행에 문제가 있는 경우 --experimental_local_lockfree_output 없이 실행하거나 샌드박스 처리된 로컬 작업을 실행합니다. 이로 인해 빌드 속도가 약간 느려질 수 있지만 (Mac 또는 Windows의 경우 위 내용 참조) 실패의 원인 중 일부를 제거합니다.