이 페이지에서는 영구 작업자를 사용하는 방법, 이점, 요구사항, 작업자가 샌드박싱에 미치는 영향
영구 작업자는 Bazel 서버가 시작하는 장기 실행 프로세스로,
실제 도구 (일반적으로 컴파일러)를 둘러싸는 래퍼로 기능합니다.
도구 자체입니다. 지속적인 작업자의 이점을 누리기 위해서는 이 도구가
일련의 컴파일을 지원하며 래퍼는
요청/응답 형식 간에 차이가 있을 수 있습니다. 똑같음
worker는 --persistent_worker
플래그 유무와 관계없이 호출될 수 있습니다.
빌드하며, 컨테이너 이미지를 적절하게 시작하고
종료 시 작업자를 종료해야 합니다. 각 작업자 인스턴스는
아래의 별도의 작업 디렉터리를
<outputBase>/bazel-workers
영구 작업자를 사용하는 것은 실행 전략으로 더 많은 JIT 컴파일이 허용되며 작업 실행의 추상 구문 트리를 예로 들 수 있습니다 이 전략 장기 실행 프로젝트에 여러 개의 요청을 전송하여 프로세스입니다
영구 작업자는 Java, Node.js 및 Scala, Kotlin 등이 있습니다.
NodeJS 런타임을 사용하는 프로그램은 @bazel/worker 도우미 라이브러리를 사용하여 작업자 프로토콜을 구현합니다
영구 작업자 사용
Bazel 0.27 이상
빌드를 실행할 때 기본적으로 영구 작업자를 사용하지만
실행이 우선합니다 영구 작업자를 지원하지 않는 작업의 경우
Bazel은 각 작업의 도구 인스턴스를 시작하는 것으로 대체합니다. 명시적으로
worker
를 설정하여 영구 작업자를 사용하도록 빌드를 설정합니다.
해당 도구의 전략
사용됩니다. 권장사항에 따라 이 예에는 local
를
worker
전략으로 대체합니다.
bazel build //my:target --strategy=Javac=worker,local
로컬 전략 대신 작업자 전략을 사용하면 컴파일을 개선할 수 있습니다. 속도가 훨씬 빨라질 수 있습니다. Java의 경우 빌드는 2~4일 수 있습니다. 증분 컴파일의 경우 더 빨라질 수 있습니다. Bazel 컴파일 작업 속도가 약 2.5배 더 빠릅니다 자세한 내용은 "작업자 수 선택" 섹션으로 이동합니다.
로컬 빌드와 일치하는 원격 빌드 환경도 있는 경우
실험적인 환경을 사용하여
동적 전략으로
원격 실행과 작업자 실행을 경합합니다. 동적 할당이
전략을 세우고
--experimental_spawn_scheduler
플래그. 이 전략은 작업자를 자동으로 사용 설정하므로
worker
전략을 지정하지만 여전히 local
또는 sandboxed
를 다음과 같이 사용할 수 있습니다.
있습니다.
작업자 수 선택
니모닉당 기본 작업자 인스턴스 수는 4개이지만 조정할 수 있습니다.
다음 코드로 교체합니다.
worker_max_instances
드림
플래그. 사용 가능한 CPU를 잘 활용하는 것과
캐시 적중 횟수도 줄일 수 있습니다. 작업자가 많을수록
대상은 JIT로 처리되지 않은 코드를 실행하고 콜드 다운에 이르는 시작 비용을 지불하게 됩니다.
있습니다 빌드할 대상 수가 적은 경우 단일 작업자가
컴파일 속도와 리소스 사용량 간의 최적의 절충점을 찾아야 합니다 (예:
문제 #8586을 참조하세요.
worker_max_instances
플래그는 지정된 각 클러스터의 최대 작업자 인스턴스 수를
니모닉과 플래그 집합 (아래 참조)을 사용하므로 혼합 시스템에서
기본값을 유지하면 꽤 많은 메모리가 제공됩니다. 증분 빌드의 경우
여러 작업자 인스턴스의 이점은 훨씬 더 적습니다.
이 그래프는 Bazel (타겟 로드 시간)의
//src:bazel
)(6코어 하이퍼 스레드 Intel Xeon 3.5GHz Linux 워크스테이션에서 실행)
64GB RAM으로 구성됩니다. 각 작업자 구성에 대해 5개의 클린 빌드가 실행되고
마지막 4개의 평균이 사용됩니다.
그림 1. 클린 빌드의 성능 개선 그래프
이 구성의 경우 두 작업자가 가장 빠른 컴파일을 제공함(단, 14%에 불과함) 직원 한 명에 비해 크게 개선되었습니다. 원하는 경우 단일 작업자가 좋은 옵션입니다. 더 적은 메모리를 사용합니다
증분 컴파일은 일반적으로 더 많은 이점을 제공합니다. 클린 빌드는 비교적 드물지만 컴파일 간에 단일 파일을 변경하는 것은 일반적입니다. 특히 테스트 기반 개발에 집중할 수 있습니다 위의 예에는 Java가 아닌 증분 컴파일 시간을 덮어쓸 수 있는 패키징 작업을 수동으로 처리할 수 있습니다.
Java 소스만 다시 컴파일
(//src/main/java/com/google/devtools/build/lib/bazel:BazelServer_deploy.jar
개)
내부 문자열 상수를 변경한 후
AbstractContainerizingSandboxedSpawn.java
3배의 속도 향상 (준비 빌드 1회로 평균 20개의 증분 빌드)
삭제됨).
그림 2. 증분 빌드의 성능 개선 그래프
속도 향상은 수행 중인 변경사항에 따라 다릅니다. 인수 6의 속도 향상은 위의 상황에서 흔히 사용되는 상수가 변경될 때 측정됩니다.
영구 작업자 수정
다음을 전달할 수 있습니다.
--worker_extra_flag
드림
니모닉으로 키가 지정된 작업자에 시작 플래그를 지정하는 플래그입니다. 예를 들면 다음과 같습니다.
--worker_extra_flag=javac=--debug
를 전달하면 Javac의 디버깅만 사용 설정됩니다.
이 플래그 사용당 하나의 작업자 플래그는 하나의 니모닉에 대해서만 설정할 수 있습니다.
작업자는 각 니모닉에 대해 개별적으로 생성되는 것이 아니라
시작 플래그의 변형과 일치해야 합니다. 니모닉과 시작의 각 조합
플래그는 WorkerKey
로 결합되며 각 WorkerKey
의 경우
worker_max_instances
작업자를 만들 수 있습니다. 다음 섹션에서
작업 구성은 설정 플래그를 지정할 수도 있습니다.
이
--high_priority_workers
드림
일반 우선순위보다 우선적으로 실행되어야 하는 니모닉을 지정하는 플래그
사용됩니다. 이렇게 하면 항상 중요한 위협에 해당하는 작업의 우선순위를
있습니다. 요청을 실행하는 우선순위가 높은 작업자가 둘 이상 있는 경우
다른 작업자는 실행되지 않습니다 이 플래그는 여러 번 사용할 수 있습니다.
--worker_sandboxing
드림
플래그는 각 작업자 요청이 모든 해당 작업자에 대해 별도의 샌드박스 디렉터리를
사용됩니다. 샌드박스를 설정하는 데는 시간이 좀 더 걸립니다.
더 나은 정확성을 보장합니다.
이
--worker_quit_after_build
드림
플래그는 주로 디버깅 및 프로파일링에 유용합니다. 이 플래그는 모든 작업자가
종료할 수 있습니다. 또한
--worker_verbose
(으)로
작업자가 하는 일에 대해 더 많은 출력을 얻을 수 있습니다. 이 플래그는
WorkRequest
의 verbosity
필드로, 작업자 구현도 다음을 할 수 있습니다.
더 장황하게 만들 수 있습니다.
작업자는 로그를 <outputBase>/bazel-workers
디렉터리에 저장합니다.
예시
/tmp/_bazel_larsrc/191013354bebe14fdddae77f2679c3ef/bazel-workers/worker-1-Javac.log
파일 이름에는 작업자 ID와 니모닉이 포함됩니다. 더 많은 데이터가
연상 기호당 하나 이상의 WorkerKey
인 경우 worker_max_instances
개보다 많이 표시될 수 있습니다.
모든 니모닉에 대한 로그 파일을 생성합니다.
Android 빌드의 경우 Android 빌드 성능 페이지
영구 작업자 구현
자세한 내용은 영구 작업자 만들기 페이지를 참조하세요. 작업자를 만드는 방법에 대한 정보를 제공합니다.
이 예시에서는 JSON을 사용하는 작업자의 Starlark 구성을 보여줍니다.
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" }
)
이 정의를 통해 이 작업을 처음 사용하는 것은
명령줄 /bin/some_compiler -max_mem=4G --persistent_worker
요청
Foo.java
를 컴파일하면 다음과 같습니다.
참고: 프로토콜 버퍼 사양에서는 '스네이크 케이스'를 사용합니다. (request_id
),
JSON 프로토콜은 '카멜 표기법'을 사용합니다. (requestId
). 이 문서에서는
JSON 예에서는 카멜 표기법을 사용하지만 필드에 대해 설명할 때는 스네이크 표기법을 사용합니다.
99.999%의 가용성을 제공합니다
{
"arguments": [ "-g", "-source", "1.5", "Foo.java" ]
"inputs": [
{ "path": "symlinkfarm/input1", "digest": "d49a..." },
{ "path": "symlinkfarm/input2", "digest": "093d..." },
],
}
작업자는 stdin
에서 줄바꿈으로 구분된 JSON 형식으로 이를 수신합니다.
requires-worker-protocol
가 JSON으로 설정됨). 그런 다음 작업자가 작업을 수행하고,
JSON 형식의 WorkResponse
을 stdout의 Bazel로 전송합니다. 그러면 Bazel이
이 응답을 파싱하고 수동으로 WorkResponse
proto로 변환합니다. 받는사람
대신 바이너리로 인코딩된 protobuf를 사용하여 연결된 작업자와 통신합니다.
JSON의 경우 requires-worker-protocol
은 다음과 같이 proto
로 설정됩니다.
execution_requirements = {
"supports-workers" : "1" ,
"requires-worker-protocol" : "proto"
}
실행 요구사항에 requires-worker-protocol
를 포함하지 않으면
Bazel은 기본적으로 작업자 통신을 통해 protobuf를 사용합니다.
Bazel은 니모닉과 공유 플래그에서 WorkerKey
를 파생하므로 다음과 같은 경우
max_mem
매개변수를 변경할 수 있는 구성으로, 별도의 작업자는
생성된 모든 값에 대해 생성됩니다. 이로 인해 과도한 메모리 소비가 발생할 수 있습니다.
너무 많은 변형이 사용됩니다.
각 작업자는 현재 한 번에 하나의 요청만 처리할 수 있습니다. 실험용 멀티플렉스 작업자 기능을 사용하면 기본 도구가 멀티스레드이고 래퍼가 이해하실 수 있을 겁니다
포함 이 GitHub 저장소에서 Java와 Python으로 작성된 작업자 래퍼의 예를 확인할 수 있습니다. 만약 JavaScript 또는 TypeScript에서 작동하고 있는 경우 @bazel/worker 패키지 및 nodejs 작업자 예시 유용할 수 있습니다
작업자는 샌드박스에 어떤 영향을 주나요?
기본적으로 worker
전략을 사용하면 다음에서 작업이 실행되지 않습니다.
sandbox이며 local
전략과 유사합니다. 이
--worker_sandboxing
플래그: 샌드박스 내에서 모든 worker를 실행하여 각 worker가
도구 실행에는 있어야 할 입력 파일만 볼 수 있습니다. 도구
내부적으로 요청 간에 정보가 유출될 수도 있습니다. 예를 들어
있습니다. dynamic
전략 사용 중
작업자를 샌드박스 처리해야 합니다.
작업자와 함께 컴파일러 캐시를 올바르게 사용할 수 있도록 다이제스트가 함께 전달됩니다. 각 입력 파일과 함께 따라서 컴파일러나 래퍼는 입력이 여전히 유효합니다.
원치 않는 캐싱을 방지하기 위해 입력 다이제스트를 사용하는 경우에도 샌드박스 처리됨 순수한 샌드박스보다 덜 엄격한 샌드박스를 제공하는데, 왜냐하면 도구가 이전 요청의 영향을 받은 다른 내부 상태를 유지합니다.
멀티플렉스 작업자는 작업자 구현에서 지원하는 경우에만 샌드박스화될 수 있습니다.
이 샌드박스는 별도로 활성화해야 하며
--experimental_worker_multiplex_sandboxing
플래그. 자세한 내용은
디자인 문서 참조).
추가 자료
영구 작업자에 대한 자세한 내용은 다음을 참조하세요.
- 원래 영구 작업자 블로그 게시물
- Haskell 구현 설명 {: .external}
- 블로그 게시물: 마이크 모어티 {: .external}
- Bazel을 사용한 프런트엔드 개발: Angular/TypeScript 및 영구 작업자 Asana 사용 {: .external}
- Bazel 전략 설명 {: .external}
- bazel-discuss 메일링 리스트에 대한 유익한 작업자 전략 논의 {: .external}