원격 실행을 위한 원격 캐시 적중 디버깅

문제 신고 소스 보기 Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

이 페이지에서는 캐시 적중률을 확인하는 방법과 원격 실행 컨텍스트에서 캐시 누락을 조사하는 방법을 설명합니다.

이 페이지에서는 원격 실행을 성공적으로 활용하는 빌드 또는 테스트가 있고 원격 캐시를 효과적으로 활용하고자 한다고 가정합니다.

캐시 적중률 확인

Bazel 실행의 표준 출력에서 프로세스를 나열하는 INFO 행을 확인합니다. 이 행은 대략 Bazel 작업에 해당합니다. 이 줄에는 작업이 실행된 위치가 자세히 나와 있습니다. 원격으로 실행된 작업을 나타내는 remote 라벨, 로컬 샌드박스에서 실행된 작업의 경우 linux-sandbox, 기타 실행 전략의 경우 다른 값을 찾습니다. 결과가 원격 캐시에서 가져온 작업은 remote cache hit로 표시됩니다.

예를 들면 다음과 같습니다.

INFO: 11 processes: 6 remote cache hit, 3 internal, 2 remote.

이 예에서는 원격 캐시 조회가 6회 있었고 2개의 작업에는 캐시 조회가 없어 원격으로 실행되었습니다. 내부 3부분은 무시할 수 있습니다. 일반적으로 심볼릭 링크 만들기와 같은 작은 내부 작업입니다. 이 요약에는 로컬 캐시 히트가 포함되지 않습니다. 프로세스가 0개이거나 예상보다 적은 경우 bazel clean를 실행한 다음 빌드/테스트 명령어를 실행합니다.

캐시 적중 문제 해결

예상한 캐시 적중률을 얻지 못하는 경우 다음을 실행합니다.

동일한 빌드/테스트 명령어를 다시 실행하면 캐시 히트가 발생하는지 확인

  1. 캐시를 채울 것으로 예상되는 빌드 또는 테스트를 실행합니다. 특정 스택에서 새 빌드가 처음 실행되면 원격 캐시 히트가 없을 수 있습니다. 원격 실행의 일환으로 작업 결과가 캐시에 저장되며 후속 실행에서 이를 가져와야 합니다.

  2. bazel clean을 실행합니다. 이 명령어는 로컬 캐시를 지우므로 로컬 캐시에서 데이터를 읽지 않고도 원격 캐시 적중을 조사할 수 있습니다.

  3. 조사하려는 빌드 및 테스트를 동일한 머신에서 다시 실행합니다.

  4. 캐시 적중률의 INFO 선을 확인합니다. remote cache hitinternal를 제외한 프로세스가 표시되지 않으면 캐시가 올바르게 채워지고 액세스되고 있는 것입니다. 이 경우 다음 섹션으로 건너뜁니다.

  5. 불일치의 원인은 빌드에서 밀폐되지 않아 두 실행에서 작업이 서로 다른 작업 키를 수신하게 되는 것입니다. 이러한 작업을 찾으려면 다음 단계를 따르세요.

    a. 문제의 빌드 또는 테스트를 다시 실행하여 실행 로그를 가져옵니다.

      bazel clean
      bazel --optional-flags build //your:target --execution_log_compact_file=/tmp/exec1.log
    

    b. 두 실행 간의 실행 로그를 비교합니다. 두 로그 파일에서 액션이 동일한지 확인합니다. 불일치는 실행 간에 발생한 변경사항에 관한 단서를 제공합니다. 이러한 불일치를 없애도록 빌드를 업데이트합니다.

    캐싱 문제를 해결할 수 있고 반복 실행 시 모든 캐시 히트가 발생하면 다음 섹션으로 건너뜁니다.

    작업 ID가 동일하지만 캐시 조회가 없는 경우 구성에 캐싱을 방해하는 요소가 있는 것입니다. 이 섹션을 계속 진행하여 일반적인 문제를 확인합니다.

  6. 실행 로그의 모든 작업에 cacheable가 true로 설정되어 있는지 확인합니다. 특정 작업의 실행 로그에 cacheable가 표시되지 않으면 해당 규칙의 BUILD 파일 정의에 no-cache 태그가 있을 수 있습니다. 실행 로그에서 mnemonictarget_label 필드를 확인하여 작업의 출처를 파악합니다.

  7. 작업이 동일하고 cacheable이지만 캐시가 히트하지 않는 경우 명령줄에 빌드의 캐시 조회를 사용 중지하는 --noremote_accept_cached가 포함되어 있을 수 있습니다.

    실제 명령줄을 파악하기 어렵다면 다음과 같이 빌드 이벤트 프로토콜의 정규 명령줄을 사용하세요.

    a. 텍스트의 로그 버전을 얻으려면 Bazel 명령어에 --build_event_text_file=/tmp/bep.txt를 추가하세요.

    b. 텍스트 버전의 로그를 열고 command_line_label: "canonical"가 포함된 structured_command_line 메시지를 검색합니다. 펼치면 모든 옵션이 표시됩니다.

    c. remote_accept_cached를 검색하고 false로 설정되어 있는지 확인합니다.

    d. remote_accept_cachedfalse인 경우 명령줄 또는 bazelrc 파일 중 어디에서 false로 설정되는지 확인합니다.

여러 머신에서 캐싱 확인

동일한 머신에서 예상대로 캐시가 발생하면 다른 머신에서 동일한 빌드/테스트를 실행합니다. 여러 머신에서 캐싱이 이루어지지 않는 것으로 의심되면 다음 단계를 따르세요.

  1. 기존 캐시를 사용하지 않도록 빌드를 약간 수정합니다.

  2. 첫 번째 머신에서 빌드를 실행합니다.

     bazel clean
     bazel ... build ... --execution_log_compact_file=/tmp/exec1.log
    
  3. 두 번째 머신에서 빌드를 실행하여 1단계의 수정사항이 포함되었는지 확인합니다.

     bazel clean
     bazel ... build ... --execution_log_compact_file=/tmp/exec2.log
    
  4. 두 실행의 실행 로그를 비교합니다. 로그가 동일하지 않으면 빌드 구성에서 불일치가 있는지, 그리고 호스트 환경의 속성이 빌드 중 하나로 유출되는지 조사합니다.

실행 로그 비교

실행 로그에는 빌드 중에 실행된 작업의 기록이 포함됩니다. 각 레코드는 입력 (파일뿐만 아니라 명령줄 인수, 환경 변수 등)과 작업의 출력을 모두 설명합니다. 따라서 로그를 검사하면 작업이 다시 실행된 이유를 알 수 있습니다.

실행 로그는 컴팩트 (--execution_log_compact_file), 바이너리 (--execution_log_binary_file) 또는 JSON (--execution_log_json_file) 형식 중 하나로 생성할 수 있습니다. 컴팩트 형식은 런타임 오버헤드가 거의 없이 훨씬 더 작은 파일을 생성하므로 권장됩니다. 다음 안내는 모든 형식에 적용됩니다. //src/tools/execlog:converter 도구를 사용하여 두 형식 간에 변환할 수도 있습니다.

예상대로 캐시 히트를 공유하지 않는 두 빌드의 로그를 비교하려면 다음 단계를 따르세요.

  1. 각 빌드에서 실행 로그를 가져와 /tmp/exec1.log/tmp/exec2.log로 저장합니다.

  2. Bazel 소스 코드를 다운로드하고 //src/tools/execlog:parser 도구를 빌드합니다.

    git clone https://github.com/bazelbuild/bazel.git cd bazel bazel build //src/tools/execlog:parser

  3. //src/tools/execlog:parser 도구를 사용하여 로그를 사람이 읽을 수 있는 텍스트 형식으로 변환합니다. 이 형식에서는 두 번째 로그의 작업이 첫 번째 로그의 순서와 일치하도록 정렬되므로 비교가 더 쉬워집니다.

    bazel-bin/src/tools/execlog/parser \
      --log_path=/tmp/exec1.log \
      --log_path=/tmp/exec2.log \
      --output_path=/tmp/exec1.log.txt \
      --output_path=/tmp/exec2.log.txt
    
  4. 좋아하는 텍스트 diff를 사용하여 /tmp/exec1.log.txt/tmp/exec2.log.txt를 비교합니다.