Gitaly 클러스터 문제 해결

Tier: Free, Premium, Ultimate Offering: Self-managed

Gitaly 클러스터(Praefect)를 문제 해결할 때 아래 정보를 참조하세요. Gitaly 문제 해결에 대한 정보는 Gitaly 문제 해결을 참고하세요.

클러스터 상태 확인

check Praefect 서브 커맨드는 Gitaly 클러스터의 건강 상태를 확인하기 위해 일련의 검사를 실행합니다.

gitlab-ctl praefect check

Praefect 차트를 사용하여 배포된 경우, 바이너리를 직접 실행하세요.

/usr/local/bin/praefect check

다음 섹션에서는 실행되는 검사를 설명합니다.

Praefect 마이그레이션

데이터베이스 마이그레이션이 Praefect가 올바르게 작동하기 위해 최신 상태여야 하므로, Praefect 마이그레이션이 최신 상태인지 확인합니다.

이 검사에 실패할 경우:

  1. 데이터베이스의 schema_migrations 테이블을 확인하여 어떤 마이그레이션이 실행되었는지 확인합니다.
  2. praefect sql-migrate를 실행하여 마이그레이션을 최신 상태로 업데이트합니다.

노드 연결성 및 디스크 접근

Praefect가 모든 Gitaly 노드에 연결할 수 있는지, 각 Gitaly 노드가 모든 저장소에 읽기 및 쓰기 접근이 가능한지 확인합니다.

이 검사에 실패할 경우:

  1. 네트워크 주소 및 토큰이 정확하게 설정되었는지 확인합니다:
    • Praefect 구성에서.
    • 각 Gitaly 노드의 구성에서.
  2. Gitaly 노드에서 gitaly 프로세스가 git으로 실행되고 있는지 확인합니다. Gitaly가 저장소 디렉토리에 접근하지 못하게 하는 권한 문제일 수 있습니다.
  3. Praefect와 Gitaly 노드를 연결하는 네트워크에 문제가 없는지 확인합니다.

데이터베이스 읽기 및 쓰기 접근

Praefect가 데이터베이스에서 읽고 쓸 수 있는지 확인합니다.

이 검사에 실패할 경우:

  1. Praefect 데이터베이스가 복구 모드인지 확인합니다. 복구 모드에서는 테이블이 읽기 전용이 될 수 있습니다. 확인하려면 다음을 실행합니다:

    select pg_is_in_recovery()
    
  2. Praefect가 PostgreSQL에 연결할 때 사용하는 사용자가 데이터베이스에 읽기 및 쓰기 접근이 있는지 확인합니다.
  3. 데이터베이스가 읽기 전용 모드로 설정되어 있는지 확인합니다. 확인하려면 다음을 실행합니다:

    show default_transaction_read_only
    

접근 불가능한 저장소

기본 할당이 없거나 기본이 사용 불가능하여 접근할 수 없는 저장소의 수를 확인합니다.

이 검사에 실패할 경우:

  1. Gitaly 노드 중 어떤 것이 다운되어 있는지 확인합니다. praefect ping-nodes를 실행하여 확인합니다.
  2. Praefect 데이터베이스에 부하가 큰지 확인합니다. Praefect 데이터베이스의 응답이 느리면, 데이터베이스에 상태 확인이 지속되지 않아 Praefect가 노드가 건강하지 않다고 판단할 수 있습니다.

시계 동기화 확인

Praefect와 Gitaly 서버 간의 인증은 서버 시간이 서로 60초 이내에 있어야 하며, 이로 인해 토큰 확인이 성공할 수 있습니다.

이 검사는 permission denied의 근본 원인을 식별하는 데 도움이 됩니다
Praefect에서 기록된 오류.

공식 NTP 서버인 pool.ntp.org에 접근할 수 없는 오프라인 환경의 경우, Praefect check 서브 커맨드는 다음과 유사한 오류 메시지로 검사에 실패합니다:

checking with NTP service at  and allowed clock drift 60000ms [correlation_id: <XXX>]
Failed (fatal) error: gitaly node at tcp://[gitlab.example-instance.com]:8075: rpc error: code = DeadlineExceeded desc = context deadline exceeded

이 문제를 해결하려면, 모든 Praefect 서버에서 접근할 수 있는 내부 Network Time Protocol (NTP) 서버를 가리키도록 환경 변수를 설정합니다. 예를 들어:

export NTP_HOST=ntp.example.com

Praefect 로그의 오류

오류가 발생하면 /var/log/gitlab/gitlab-rails/production.log를 확인하세요.

다음은 일반적인 오류와 잠재적인 원인입니다:

  • 500 응답 코드
    • ActionView::Template::Error (7:permission denied)
      • praefect['configuration'][:auth][:token]gitlab_rails['gitaly_token']이 GitLab 서버에서 일치하지 않습니다.
      • git_data_dirs 저장소 구성이 Sidekiq 서버에 없습니다.
    • Unable to save project. Error: 7:permission denied
      • GitLab 서버의 praefect['configuration'][:virtual_storage]에 있는 비밀 토큰이 하나 이상의 Gitaly 서버의 gitaly['auth_token'] 값과 일치하지 않습니다.
  • 503 응답 코드
    • GRPC::Unavailable (14:failed to connect to all addresses)
      • GitLab이 Praefect에 연결할 수 없었습니다.
    • GRPC::Unavailable (14:all SubCons are in TransientFailure...)
      • Praefect가 하나 이상의 자식 Gitaly 노드에 연결할 수 없습니다. 진단을 위해 Praefect 연결 검사기를 실행해 보세요.

Praefect 데이터베이스의 높은 CPU 로드

Praefect 데이터베이스가 높은 CPU 사용량을 경험하는 몇 가지 일반적인 이유는 다음과 같습니다:

  • Prometheus 메트릭 스크랩이 비용이 많이 드는 쿼리를 실행합니다. gitlab.rb에서 praefect['configuration'][:prometheus_exclude_database_from_default_metrics] = true로 설정하세요.
  • 읽기 분배 캐싱이 비활성화되어 사용자 트래픽이 높은 경우 데이터베이스에 대한 쿼리 수가 증가합니다. 읽기 분배 캐싱이 활성화되어 있는지 확인하세요.

주요 Gitaly 노드 결정하기

저장소의 주요 노드를 결정하려면 praefect metadata 하위 명령어를 사용하세요.

저장소 메타데이터 보기

Gitaly 클러스터는 클러스터에 저장된 저장소에 대한 메타데이터 데이터베이스를 유지합니다. 문제 해결을 위해 메타데이터를 검사하려면 praefect metadata 하위 명령어를 사용하세요.

Praefect가 할당한 저장소 ID로 저장소의 메타데이터를 검색할 수 있습니다:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml metadata -repository-id <repository-id>

물리적 저장소의 경로가 @cluster로 시작하면 물리적 경로에서 저장소 ID 찾기를 참조하세요.

가상 저장소와 상대 경로로도 저장소의 메타데이터를 검색할 수 있습니다:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml metadata -virtual-storage <virtual-storage> -relative-path <relative-path>

예시

Praefect가 할당한 저장소 ID가 1인 저장소의 메타데이터를 검색하려면:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml metadata -repository-id 1

가상 저장소가 default이고 상대 경로가 @hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git인 저장소의 메타데이터를 검색하려면:

sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml metadata -virtual-storage default -relative-path @hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git

이 예시 중 하나는 다음과 같은 메타데이터를 반환합니다:

Repository ID: 54771
Virtual Storage: "default"
Relative Path: "@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git"
Replica Path: "@hashed/b1/7e/b17ef6d19c7a5b1ee83b907c595526dcb1eb06db8227d650d5dda0a9f4ce8cd9.git"
Primary: "gitaly-1"
Generation: 1
Replicas:
- Storage: "gitaly-1"
  Assigned: true
  Generation: 1, fully up to date
  Healthy: true
  Valid Primary: true
  Verified At: 2021-04-01 10:04:20 +0000 UTC
- Storage: "gitaly-2"
  Assigned: true
  Generation: 0, behind by 1 changes
  Healthy: true
  Valid Primary: false
  Verified At: unverified
- Storage: "gitaly-3"
  Assigned: true
  Generation: replica not yet created
  Healthy: false
  Valid Primary: false
  Verified At: unverified

사용 가능한 메타데이터

praefect metadata로 검색된 메타데이터에는 다음 테이블의 필드가 포함됩니다.

필드 설명
Repository ID Praefect에 의해 저장소에 할당된 영구 고유 ID. GitLab이 저장소에 사용하는 ID와 다릅니다.
Virtual Storage 저장소가 저장된 가상 스토리지의 이름.
Relative Path 가상 스토리지 내에서의 저장소 경로.
Replica Path Gitaly 노드의 디스크에서 저장소의 복제본이 저장된 위치.
Primary 저장소의 현재 기본(primary).
Generation Praefect가 저장소 변경 사항을 추적하는 데 사용됨. 저장소 내의 각 기록은 저장소의 세대를 증가시킵니다.
Replicas 존재하거나 존재할 것으로 예상되는 복제본의 목록.

각 복제본에 대해 다음 메타데이터를 사용할 수 있습니다:

Replicas 필드 설명
Storage 복제본을 포함하는 Gitaly 스토리지의 이름.
Assigned 복제본이 스토리지에 존재할 것으로 예상되는지 여부. Gitaly 노드가 클러스터에서 제거되거나 저장소의 복제 인수가 감소한 후 추가 복사본이 포함된 경우 false일 수 있습니다.
Generation 복제본의 최신 확인 세대. 다음을 나타냅니다:

- 세대가 저장소의 세대와 일치하면 복제본이 완전히 최신 상태입니다.
- 복제본의 세대가 저장소의 세대보다 작으면 복제본이 구식입니다.
- 복제본이 스토리지에 아직 생성되지 않은 경우 replica not yet created입니다.
Healthy 이 복제본을 호스팅하는 Gitaly 노드가 Praefect 노드의 합의에 의해 건강하다고 간주되는지 여부.
Valid Primary 복제본이 기본 노드로서 적합한지 여부. 저장소의 기본이 유효한 기본이 아닌 경우, 다른 복제본이 유효한 기본이 있는 경우 다음 저장소 기록에서 장애 조치가 발생합니다. 복제본이 유효한 기본이면:

- 건강한 Gitaly 노드에 저장됩니다.
- 완전히 최신 상태입니다.
- 복제 인수를 줄이는 작업에 의해 삭제 대기 중인 항목이 아닙니다.
- 할당되었습니다.
Verified At 복제본을 검증 작업자에 의해 마지막으로 성공적으로 검증한 시간을 나타냅니다. 복제본이 아직 검증되지 않은 경우, 마지막 성공적인 검증 시간 대신 unverified가 표시됩니다. GitLab 15.0에서 도입되었습니다.

명령이 ‘repository not found’로 실패함

-virtual-storage에 제공된 값이 올바르지 않으면 명령은 다음 오류를 반환합니다:

get metadata: rpc error: code = NotFound desc = repository not found

문서에 있는 예는 -virtual-storage default를 지정합니다. /etc/gitlab/gitlab.rb에서 Praefect 서버 설정 praefect['configuration'][:virtual_storage]을 확인하세요.

저장소가 동기화되어 있는지 확인하기

일부 경우 Praefect 데이터베이스가 기본 Gitaly 노드와 동기화되지 않을 수 있습니다. 특정 저장소가 모든 노드에서 완전히 동기화되었는지 확인하려면, Rails 노드에서 gitlab:praefect:replicas Rake 작업을 실행하세요. 이 Rake 작업은 모든 Gitaly 노드에서 저장소의 체크섬을 확인합니다.

Praefect dataloss 명령은 Praefect 데이터베이스 내의 저장소 상태만 확인하며, 이 시나리오에서 동기화 문제를 감지하는 데 신뢰할 수 없습니다.

dataloss 명령은 @failed-geo-sync 저장소를 동기화되지 않음으로 표시합니다

@failed-geo-sync는 프로젝트 동기화가 실패했을 때 GitLab 16.1 및 이전 버전의 Geo에서 사용된 레거시 경로로, 사용 중단되었습니다.

GitLab 16.2 이상에서는 이 경로를 안전하게 삭제할 수 있습니다. @failed-geo-sync 디렉토리는 Gitaly 노드의 저장소 경로 아래에 위치합니다.

관계가 존재하지 않는 오류

기본적으로 Praefect 데이터베이스 테이블은 gitlab-ctl reconfigure 작업에 의해 자동으로 생성됩니다.

그러나 Praefect 데이터베이스 테이블은 초기 재구성 시 생성되지 않으며, 다음과 같은 경우 관계가 존재하지 않는 오류를 발생할 수 있습니다:

  • gitlab-ctl reconfigure 명령이 실행되지 않은 경우.
  • 실행 중 오류가 발생한 경우.

예를 들어:

  • ERROR: relation "node_status" does not exist at character 13
  • ERROR: relation "replication_queue_lock" does not exist at character 40
  • 이 오류:

    {"level":"error","msg":"Error updating node: pq: relation \"node_status\" does not exist","pid":210882,"praefectName":"gitlab1x4m:0.0.0.0:2305","time":"2021-04-01T19:26:19.473Z","virtual_storage":"praefect-cluster-1"}
    

이 문제를 해결하려면 praefect 명령의 sql-migrate 하위 명령을 사용하여 데이터베이스 스키마 마이그레이션을 수행할 수 있습니다:

$ sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate
praefect sql-migrate: OK (applied 21 migrations)

요청이 ‘repository scoped: invalid Repository’ 오류로 실패합니다

이는 Praefect 구성에서 사용된 가상 저장소 이름이 GitLab의 gitaly['configuration'][:storage][<index>][:name] 설정에서 사용된 저장소 이름과 일치하지 않음을 나타냅니다.

이 문제를 해결하려면 Praefect와 GitLab 구성에서 사용된 가상 저장소 이름을 일치시켜야 합니다.

클라우드 플랫폼에서 Gitaly 클러스터 성능 문제

Praefect는 많은 CPU 또는 메모리를 요구하지 않으며, 작은 가상 머신에서도 실행할 수 있습니다.

클라우드 서비스는 작은 VM이 사용할 수 있는 리소스에 대해 디스크 IO 및 네트워크 트래픽과 같은 추가 제한을 둘 수 있습니다.

Praefect 노드는 많은 네트워크 트래픽을 생성합니다. 클라우드 서비스에 의해 네트워크 대역폭이 제한된 경우 다음과 같은 증상이 나타날 수 있습니다:

  • Git 작업의 성능 저하.
  • 높은 네트워크 지연.
  • Praefect에 의한 높은 메모리 사용.

가능한 솔루션:

  • 더 큰 VM을 프로비저닝하여 더 큰 네트워크 트래픽 허용량을 확보합니다.
  • 클라우드 서비스의 모니터링 및 로깅을 사용하여 Praefect 노드가 트래픽 허용량을 소진하지 않도록 확인합니다.

gitlab-ctl reconfigure가 Praefect 구성 오류로 실패합니다

gitlab-ctl reconfigure가 실패하면 다음과 같은 오류가 발생할 수 있습니다:

STDOUT: praefect: configuration error: error reading config file: toml: cannot store TOML string into a Go int

이 오류는 praefect['database_port'] 또는 praefect['database_direct_port']가 정수가 아닌 문자열로 구성된 경우 발생합니다.

일반적인 복제 오류

다음은 몇 가지 일반적인 복제 오류와 가능한 해결책입니다.

잠금 파일 존재

잠금 파일은 동일한 참조에 대한 여러 업데이트를 방지하기 위해 사용됩니다. 때때로 잠금 파일이 오래되어 Replication이 error: cannot lock ref 오류와 함께 실패할 수 있습니다.

오래된 *.lock 파일을 지우려면 Rails 콘솔에서 OptimizeRepositoryRequest를 트리거할 수 있습니다:

p = Project.find <Project ID>
client = Gitlab::GitalyClient::RepositoryService.new(p.repository)
client.optimize_repository

OptimizeRepositoryRequest를 트리거해도 작동하지 않으면, 파일을 수동으로 검사하여 생성 날짜를 확인하고 *.lock 파일을 수동으로 제거할 수 있는지 결정합니다.

24시간 이상 생성된 잠금 파일은 안전하게 제거할 수 있습니다.

Git fsck 오류

잘못된 객체가 있는 Gitaly 리포지토리는 Gitaly 로그에서 다음과 같은 오류를 동반하여 복제 실패를 초래할 수 있습니다:

  • exit status 128, stderr: "fatal: git upload-pack: not our ref".
  • "fatal: bad object 58....e0f... ssh://gitaly/internal.git did not send all necessary objects.

Gitaly 노드 중 하나가 여전히 정상적인 리포지토리의 복사본을 보유하고 있는 한, 이러한 문제는 다음과 같이 해결할 수 있습니다:

  1. Praefect 데이터베이스에서 리포지토리 제거.
  2. Praefect track-repository 서브커맨드를 사용하여 다시 추적합니다.

이 작업은 권위 있는 Gitaly 노드의 리포지토리 복사본을 사용하여 모든 다른 Gitaly 노드의 복사본을 덮어씁니다.

이러한 명령을 실행하기 전에 리포지토리의 최근 백업이 생성되었는지 확인하십시오.

  1. 잘못된 리포지토리를 이동합니다:

    run `mv <REPOSITORY_PATH> <REPOSITORY_PATH>.backup`
    

    예를 들어:

    mv /var/opt/gitlab/git-data/repositories/@cluster/repositories/de/74/2335 /var/opt/gitlab/git-data/repositories/@cluster/repositories/de/74/2335.backup
    
  2. 복제를 트리거하기 위해 Praefect 명령을 실행합니다:

    # 올바른 리포지토리가 있는지 확인하십시오.
    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage gitaly -relative-path '<relative_path>' -db-only
    
    # Praefect 추적 데이터베이스에서 리포지토리를 제거하기 위해 '--apply' 플래그로 다시 실행합니다.
    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml remove-repository -virtual-storage gitaly -relative-path '<relative_path>' -db-only --apply
    
    # 리포지토리를 다시 추적하고 보조 노드를 덮어씁니다.
    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml track-repository -virtual-storage gitaly -authoritative-storage '<healthy_gitaly>' -relative-path '<relative_path>' -replica-path '<replica_path>' -replicate-immediately
    

복제가 조용히 실패

Praefect dataloss부분적으로 사용 불가능한 리포지토리를 보여주고, accept-dataloss 명령이 오류 없이 리포지토리를 동기화하지 못하면, 이는 storage_repositories 테이블의 repository_id 필드에서 Praefect 데이터베이스의 불일치로 인해 발생할 수 있습니다. 불일치를 확인하려면:

  1. Praefect 데이터베이스에 연결합니다.
  2. 다음 쿼리를 실행합니다:

    select * from storage_repositories where relative_path = '<relative-path>';
    

    <relative-path>@hashed로 시작하는 리포지토리 경로로 교체하십시오.

대체 디렉토리가 존재하지 않음

GitLab은 Git alternates 메커니즘을 사용하여 중복 제거를 수행합니다. alternates@pool 저장소의 objects 디렉토리를 가리키는 텍스트 파일로, 객체를 가져오기 위해 사용됩니다. 이 파일이 유효하지 않은 경로를 가리키면 다음과 같은 오류로 복제가 실패할 수 있습니다:

  • "error":"no alternates directory exists", "warning","msg":"alternates file does not point to valid git repository"
  • "error":"unexpected alternates content:
  • remote: error: unable to normalize alternate object path

이 오류의 원인을 조사하려면:

  1. Rails 콘솔을 사용하여 프로젝트가 풀의 일부인지 확인하세요:

    project = Project.find_by_id(<project id>)
    project.pool_repository
    
  2. 풀 저장소 경로가 디스크에 존재하는지 확인하고 대체(alternates) 파일 내용과 일치하는지 확인하세요.
  3. 프로젝트의 objects 디렉토리에서 alternates 파일의 경로에 접근할 수 있는지 확인하세요.

이러한 점검을 수행한 후, 수집한 정보를 가지고 GitLab 지원팀에 문의하세요.