InfoGrab Docs

Gitaly 클러스터(Praefect)

요약

Git 스토리지는 GitLab의 Gitaly 서비스를 통해 제공되며 GitLab 운영에 필수적입니다. Gitaly는 클러스터 구성으로 실행하여 다음을 달성할 수 있습니다: 이 구성에서 모든 Git 저장소는 클러스터의 여러 Gitaly 노드에 저장될 수 있습니다.

Git 스토리지는 GitLab의 Gitaly 서비스를 통해 제공되며 GitLab 운영에 필수적입니다. 사용자, 저장소, 활동 수가 증가함에 따라 다음을 통해 Gitaly를 적절히 확장하는 것이 중요합니다:

  • 리소스 고갈로 Git, Gitaly, GitLab 애플리케이션 성능이 저하되기 전에 Git에서 사용 가능한 CPU 및 메모리 리소스를 늘립니다.
  • 스토리지 한도에 도달하여 쓰기 작업이 실패하기 전에 사용 가능한 스토리지를 늘립니다.
  • 단일 장애 지점을 제거하여 내결함성을 향상시킵니다. 서비스 저하가 프로덕션에 대한 변경 배포를 방해할 경우 Git은 미션 크리티컬로 간주해야 합니다.

Gitaly는 클러스터 구성으로 실행하여 다음을 달성할 수 있습니다:

  • Gitaly 서비스 확장.
  • 내결함성 향상.

이 구성에서 모든 Git 저장소는 클러스터의 여러 Gitaly 노드에 저장될 수 있습니다.

Gitaly 클러스터(Praefect)를 사용하면 다음을 통해 내결함성이 향상됩니다:

  • 대기 Gitaly 노드에 쓰기 작업 복제.
  • Gitaly 노드 장애 감지.
  • 사용 가능한 Gitaly 노드로 Git 요청 자동 라우팅.
Note

Gitaly 클러스터(Praefect)에 대한 기술 지원은 GitLab Premium 및 Ultimate 고객으로 제한됩니다.

다음은 Gitaly 클러스터(Praefect)에서 제공하는 가상 스토리지인 storage-1에 액세스하도록 설정된 GitLab을 보여줍니다:

GitLab application interacting with virtual Gitaly storage, which interacts with Gitaly physical storage

이 예시에서:

  • 저장소는 storage-1이라는 가상 스토리지에 저장됩니다.
  • 세 개의 Gitaly 노드가 storage-1 액세스를 제공합니다: gitaly-1, gitaly-2, gitaly-3.
  • 세 개의 Gitaly 노드는 세 개의 개별 해시 스토리지 위치에서 데이터를 공유합니다.
  • 복제 계수3입니다. 각 저장소의 복사본이 세 개 유지됩니다.

단일 노드 장애를 가정한 Gitaly 클러스터(Praefect)의 가용성 목표는:

  • 복구 시점 목표(RPO): 1분 미만.

    쓰기는 비동기적으로 복제됩니다. 새로 승격된 프라이머리에 복제되지 않은 쓰기는 손실됩니다. 실패한 노드에서 진행 중이던 읽기 작업은 종료됩니다.

    강한 일관성은 일부 상황에서 손실을 방지합니다.

  • 복구 시간 목표(RTO): 10초 미만. 중단은 각 Praefect 노드가 매초 실행하는 상태 확인에 의해 감지됩니다. 페일오버는 각 Praefect 노드에서 연속적으로 10번 실패한 상태 확인이 필요합니다.

RPO 및 RTO 개선 사항은 에픽 8903에서 제안됩니다.

Warning

완전한 클러스터 장애가 발생하면 재해 복구 계획을 실행해야 합니다. 이는 앞서 설명한 RPO 및 RTO에 영향을 미칠 수 있습니다.

Gitaly 클러스터(Praefect) 배포 전에#

Gitaly 클러스터(Praefect)는 내결함성의 이점을 제공하지만 추가적인 설정 및 관리 복잡성이 따릅니다. Gitaly 클러스터(Praefect)를 배포하기 전에 다음을 참조하십시오:

아직 Gitaly 클러스터(Praefect)로 마이그레이션하지 않은 경우 두 가지 옵션이 있습니다:

  • 샤드된 Gitaly 인스턴스.
  • Gitaly 클러스터(Praefect).

질문이 있으면 고객 성공 관리자 또는 고객 지원에 문의하십시오.

이미 Gitaly 클러스터(Praefect)를 사용 중이고 문제 또는 제한을 경험하고 있는 경우 복원 또는 복구에 대한 즉각적인 도움을 위해 고객 지원에 문의하십시오.

알려진 문제#

다음 표는 Gitaly 클러스터(Praefect) 사용에 영향을 미치는 현재 알려진 문제를 요약합니다. 이러한 문제의 현재 상태는 참조된 이슈와 에픽을 참조하십시오.

문제 요약 방지 방법
Gitaly 클러스터(Praefect) + Geo - 실패한 동기화 재시도 문제 Gitaly 클러스터(Praefect)가 Geo 보조 사이트에서 사용되는 경우 동기화에 실패한 저장소가 Geo가 다시 동기화를 시도할 때 계속 실패할 수 있습니다. 이 상태에서 복구하려면 지원의 도움을 받아 수동 단계를 실행해야 합니다. GitLab 15.0에서 15.2까지는 Geo 프라이머리 사이트에서 gitaly_praefect_generated_replica_paths 기능 플래그를 활성화합니다. GitLab 15.3에서는 기능 플래그가 기본적으로 활성화됩니다.
업그레이드 후 마이그레이션이 적용되지 않아 Praefect가 데이터베이스에 데이터를 삽입할 수 없음 데이터베이스가 완료된 마이그레이션으로 최신 상태를 유지하지 않으면 Praefect 노드가 표준 작업을 수행할 수 없습니다. Praefect 데이터베이스가 모든 마이그레이션이 완료된 상태로 실행 중인지 확인합니다. 예를 들어 이 명령은 적용된 모든 마이그레이션 목록을 표시해야 합니다: sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status. 업그레이드 계획을 지원이 검토할 수 있도록 업그레이드 지원 요청을 고려합니다.
실행 중인 클러스터의 스냅샷에서 Gitaly 클러스터(Praefect) 노드 복원 Gitaly 클러스터(Praefect)는 일관된 상태로 실행되므로 뒤처진 단일 노드를 도입하면 클러스터가 다른 노드의 데이터와 해당 노드의 데이터를 조정할 수 없게 됩니다. 백업 스냅샷에서 단일 Gitaly 클러스터(Praefect) 노드를 복원하지 마십시오. 백업에서 복원해야 하는 경우:

1. GitLab을 종료합니다.
2. 모든 Gitaly 클러스터(Praefect) 노드를 동시에 스냅샷합니다.
3. Praefect 데이터베이스의 덤프를 가져옵니다.
Kubernetes, Amazon ECS 또는 이와 유사한 환경에서 실행 시 제한 사항 Gitaly 클러스터(Praefect)는 지원되지 않으며 Gitaly에는 알려진 제한 사항이 있습니다. 자세한 내용은 에픽 6127을 참조하십시오. 참조 아키텍처를 사용합니다.
Praefect가 쓰기를 기록하기 전에 PostReceiveHook 호출 경쟁 조건으로 인해 PostReceiveHook이 쓰기가 모든 노드에 복제되기 전에 실행될 수 있습니다. CI/CD 파이프라인이 아직 쓰기를 받지 못한 레플리카를 대상으로 할 때 이 경쟁 조건으로 인해 파이프라인이 couldn't find remote ref refs/merge-requests/$iid/{head,merge} 오류와 함께 실패합니다. 자세한 내용은 이슈 5406을 참조하십시오 전체 잡 또는 소스 가져오기 단계만 재시도합니다. 자세한 내용은 잡 단계 시도를 참조하십시오.
HPA 자동 확장으로 인해 스토리지 이동이 자동으로 실패할 수 있음 Sidekiq 파드에서 수평 파드 자동 확장기(HPA)를 사용할 때 파드 확장 중에 저장소 스토리지 이동이 자동으로 실패할 수 있습니다. 저장소 스토리지 이동을 수행하기 전에 HPA를 고정 레플리카로 구성하고, 마이그레이션 중 확장을 방지하기 위해 minReplicas = maxReplicas를 설정합니다.

스냅샷 백업 및 복구#

Gitaly 클러스터(Praefect)는 스냅샷 백업을 지원하지 않습니다. 스냅샷 백업은 Praefect 데이터베이스가 디스크 스토리지와 동기화되지 않는 문제를 일으킬 수 있습니다. Praefect가 복원 중에 Gitaly 디스크 정보의 복제 메타데이터를 재구축하는 방식으로 인해 공식 백업 및 복원 Rake 작업을 사용해야 합니다.

증분 백업 방법을 사용하면 Gitaly 클러스터(Praefect) 백업 속도를 높일 수 있습니다.

두 방법 중 어느 것도 사용할 수 없는 경우 복원 도움을 위해 고객 지원에 문의하십시오.

Geo와의 비교#

Gitaly 클러스터(Praefect)와 Geo는 서로 다른 유형의 중복성을 제공합니다.

  • Gitaly 클러스터(Praefect)의 중복성은 데이터 스토리지에 대한 내결함성을 제공하며 사용자에게 투명합니다.
  • Geo의 중복성은 전체 GitLab 인스턴스에 대한 복제(사용자에게 표시됨)와 재해 복구를 제공합니다. Geo는 Git 데이터를 포함한 여러 데이터 유형을 복제합니다.

다음 표는 Gitaly 클러스터(Praefect)와 Geo의 주요 차이점을 요약합니다:

도구 노드 위치 지연 시간 허용 범위 페일오버 일관성 다음에 대한 중복성 제공
Gitaly 클러스터(Praefect) 여러 개 단일 1초 미만, 이상적으로는 한 자릿수 밀리초 자동 강함 Git의 데이터 스토리지
Geo 여러 개 여러 개 최대 1분 수동 결과적 전체 GitLab 인스턴스

자세한 내용은 다음을 참조하십시오:

가상 스토리지#

가상 스토리지를 통해 GitLab에서 단일 저장소 스토리지를 갖는 것이 가능하며 저장소 관리를 단순화합니다.

Gitaly 클러스터(Praefect)를 사용한 가상 스토리지는 일반적으로 직접 Gitaly 스토리지 구성을 대체할 수 있습니다. 그러나 이는 각 저장소를 여러 Gitaly 노드에 저장하는 데 필요한 추가 스토리지 공간의 비용이 따릅니다. 직접 Gitaly 스토리지 대비 Gitaly 클러스터(Praefect) 가상 스토리지를 사용하는 이점은:

  • 향상된 내결함성 - 각 Gitaly 노드가 모든 저장소의 복사본을 가집니다.
  • 향상된 리소스 활용 - 읽기 부하가 Gitaly 노드 간에 분산되므로 샤드별 최대 부하에 대한 과도한 프로비저닝 필요성이 줄어듭니다.
  • 수동 재균형 불필요 - 읽기 부하가 Gitaly 노드 간에 분산됩니다.
  • 간소화된 관리 - 모든 Gitaly 노드가 동일합니다.

저장소 레플리카 수는 복제 계수를 사용하여 구성할 수 있습니다.

모든 저장소에 동일한 복제 계수를 갖는 것은 비경제적일 수 있습니다. 매우 큰 GitLab 인스턴스에 더 큰 유연성을 제공하기 위해 가변 복제 계수가 이 이슈에서 추적됩니다.

표준 Gitaly 스토리지와 마찬가지로 가상 스토리지도 샤딩할 수 있습니다.

여러 가상 스토리지#

Gitaly 클러스터(Praefect) 배포에서 여러 가상 스토리지를 구성할 수 있습니다. 이를 통해 다음을 할 수 있습니다:

  • 서로 다른 성능 특성을 가진 별도의 클러스터로 저장소를 구성합니다.
  • 저장소 그룹에 따라 서로 다른 복제 계수를 적용합니다.
  • 인프라의 다른 부분을 독립적으로 확장합니다.

가상 스토리지는 GitLab 서버의 gitlab_rails['repositories_storages']에 구성됩니다. 이 해시의 각 항목은 별개의 가상 스토리지를 나타냅니다. Praefect 구성은 각 가상 스토리지를 서비스하는 Gitaly 노드를 정의합니다. 서로 다른 가상 스토리지의 저장소는 완전히 독립적이며 가상 스토리지 간에 복제되지 않습니다.

예를 들어 다음과 같이 구성할 수 있습니다:

  • storage-1: 복제 계수 3인 중요한 프로덕션 저장소용 가상 스토리지.
  • storage-2: 복제 계수 2인 덜 중요한 저장소용 가상 스토리지.

각 가상 스토리지에는 자체 Gitaly 노드 세트가 필요합니다.

Mermaid 다이어그램 (18줄)
소스 코드 보기
%%{init: { "fontFamily": "GitLab Sans" }}%%
graph TD
    accTitle: Multiple virtual storages
    accDescr: Example of multiple virtual storages, one with a replication factor of three and one with a replication factor of two.
GitLab[[GitLab server]]
Storage1[(storage-1<br/>Praefect cluster)]
Storage2[(storage-2<br/>Praefect cluster)]

GitLab --> Storage1
GitLab --> Storage2

Storage1 --> G1[Gitaly node 1]
Storage1 --> G2[Gitaly node 2]
Storage1 --> G3[Gitaly node 3]

Storage2 --> G4[Gitaly node 4]
Storage2 --&gt; G5[Gitaly node 5]</code></pre></details></div>

구성 지침은 여러 가상 스토리지 구성을 참조하십시오.

혼합 구성#

GitLab을 다음의 조합으로 사용하도록 구성할 수 있습니다:

  • 독립형 Gitaly 인스턴스(직접 Gitaly 스토리지).
  • Gitaly 클러스터(Praefect) 가상 스토리지.

다음과 같은 경우 혼합 구성을 사용할 수 있습니다:

  • 독립형 Gitaly에서 Gitaly 클러스터(Praefect)로 점진적으로 마이그레이션하는 경우.
  • 일부 저장소는 고가용성이 필요하고 다른 저장소는 그렇지 않은 경우.
  • 중요한 저장소에만 Gitaly 클러스터(Praefect)를 사용하여 비용을 최적화하려는 경우.

혼합 구성에서 각 스토리지는 GitLab에서 독립적으로 구성됩니다:

  • 독립형 Gitaly 스토리지는 Gitaly 노드에 직접 연결됩니다.
  • Gitaly 클러스터(Praefect) 스토리지는 Praefect 로드 밸런서에 연결됩니다.

GitLab은 독립형인지 클러스터된인지에 관계없이 모든 구성된 스토리지를 동등하게 취급합니다. 새 저장소를 만들 때 GitLab은 구성된 스토리지 가중치와 사용 가능한 용량을 기반으로 스토리지를 선택합니다.

Mermaid 다이어그램 (15줄)
소스 코드 보기
%%{init: { "fontFamily": "GitLab Sans" }}%%
graph TD
    accTitle: Mixed configuration
    accDescr: Example result of mixed configuration, with a Gitaly Cluster (Praefect) and standalone Gitaly configured together.
GitLab[[GitLab server]]
Praefect[(Praefect cluster)]
Standalone1[(Standalone gitaly)]

GitLab --&gt;|cluster storage| Praefect
GitLab --&gt;|default storage| Standalone1

Praefect --&gt; G1[Gitaly node 1]
Praefect --&gt; G2[Gitaly node 2]
Praefect --&gt; G3[Gitaly node 3]</code></pre></details></div>

자세한 내용은 다음을 참조하십시오:

스토리지 레이아웃#

Warning

스토리지 레이아웃은 Gitaly 클러스터(Praefect)의 내부 세부 사항이며 릴리스 간에 안정적으로 유지되는 것이 보장되지 않습니다. 여기의 정보는 참고 목적으로만 제공되며 디버깅에 도움을 주기 위한 것입니다. 디스크에서 직접 저장소를 변경하는 것은 지원되지 않으며 장애를 일으키거나 변경 사항이 덮어쓰여질 수 있습니다.

Gitaly 클러스터(Praefect) 가상 스토리지는 단일 스토리지처럼 보이는 추상화를 제공하지만 실제로는 여러 물리적 스토리지로 구성됩니다. Gitaly 클러스터(Praefect)는 각 물리적 스토리지에 각 작업을 복제해야 합니다. 작업은 일부 물리적 스토리지에서는 성공하고 다른 곳에서는 실패할 수 있습니다.

부분적으로 적용된 작업은 다른 작업에 문제를 일으키고 시스템이 복구할 수 없는 상태로 만들 수 있습니다. 이러한 문제를 방지하기 위해 각 작업은 완전히 적용되거나 전혀 적용되지 않아야 합니다. 작업의 이 속성을 원자성이라고 합니다.

GitLab은 저장소 스토리지의 스토리지 레이아웃을 제어합니다. GitLab은 저장소 스토리지에 저장소를 생성, 삭제, 이동할 위치를 지시합니다. 이러한 작업은 여러 물리적 스토리지에 적용될 때 원자성 문제를 일으킵니다. 예를 들어:

  • GitLab이 레플리카 중 하나를 사용할 수 없는 동안 저장소를 삭제합니다.
  • GitLab이 나중에 저장소를 다시 생성합니다.

그 결과 삭제 시 사용할 수 없었던 오래된 레플리카가 충돌을 일으키고 저장소 재생성을 방해할 수 있습니다.

이러한 원자성 문제는 다음과 관련하여 과거에 여러 문제를 일으켰습니다:

  • Gitaly 클러스터(Praefect)가 있는 보조 사이트로의 Geo 동기화.
  • 백업 복원.
  • 저장소 스토리지 간 저장소 이동.

Gitaly 클러스터(Praefect)는 부분적으로 적용된 작업으로 인해 발생할 수 있는 충돌을 방지하는 특수 레이아웃에 디스크에 저장소를 저장하여 이러한 작업에 원자성을 제공합니다.

클라이언트 생성 레플리카 경로#

저장소는 Gitaly 클라이언트에 의해 결정된 상대 경로에 스토리지에 저장됩니다. 이러한 경로는 @cluster 접두사로 시작하지 않는 것으로 식별할 수 있습니다. 상대 경로는 해시 스토리지 스키마를 따릅니다.

Praefect 생성 레플리카 경로#

Gitaly 클러스터(Praefect)가 저장소를 만들 때 저장소에 _저장소 ID_라고 하는 고유하고 영구적인 ID를 할당합니다. 저장소 ID는 Gitaly 클러스터(Praefect)에 내부적이며 GitLab의 다른 곳에 있는 ID와 관련이 없습니다. 저장소가 Gitaly 클러스터(Praefect)에서 제거되고 나중에 다시 이동되면 저장소에 새 저장소 ID가 할당되며 Gitaly 클러스터(Praefect)의 관점에서 다른 저장소가 됩니다. 저장소 ID의 시퀀스는 항상 증가하지만 시퀀스에 간격이 있을 수 있습니다.

저장소 ID는 클러스터의 각 저장소에 대한 _레플리카 경로_라는 고유한 스토리지 경로를 도출하는 데 사용됩니다. 저장소의 레플리카는 모두 스토리지의 동일한 레플리카 경로에 저장됩니다. 레플리카 경로는 _상대 경로_와 구별됩니다:

  • 상대 경로는 Gitaly 클라이언트가 가상 스토리지와 함께 저장소를 식별하는 데 사용하는 이름으로, 그것들에게 고유합니다.
  • 레플리카 경로는 물리적 스토리지의 실제 물리적 경로입니다.

Praefect는 클라이언트 요청을 처리할 때 RPC의 저장소를 가상 (가상 스토리지, 상대 경로) 식별자에서 물리적 저장소 (스토리지, 레플리카_경로) 식별자로 변환합니다.

레플리카 경로의 형식:

  • 오브젝트 풀은 @cluster/pools/<xx>/<xx>/<저장소 ID>입니다. 오브젝트 풀은 다른 저장소와 다른 디렉토리에 저장됩니다. 하우스키핑의 일부로 가지치기되는 것을 방지하기 위해 Gitaly에서 식별 가능해야 합니다. 오브젝트 풀을 가지치기하면 연결된 저장소에서 데이터가 손실될 수 있습니다.
  • 다른 저장소는 @cluster/repositories/<xx>/<xx>/<저장소 ID>입니다.

예를 들어 @cluster/repositories/6f/96/54771.

레플리카 경로의 마지막 구성 요소인 54771이 저장소 ID입니다. 이를 사용하여 디스크에서 저장소를 식별할 수 있습니다.

<xx>/<xx>는 저장소 ID의 문자열 표현의 SHA256 해시의 처음 네 개 16진수입니다. 이 숫자는 일부 파일 시스템에서 문제를 일으킬 수 있는 지나치게 큰 디렉토리를 피하기 위해 저장소를 하위 디렉토리에 고르게 분산하는 데 사용됩니다. 이 경우 547716f960ab01689464e768366d3315b3d3b2c28f38761a58a70110554eb04d582f7로 해시되므로 처음 네 자리는 6f96입니다.

디스크에서 저장소 식별#

praefect metadata 하위 명령을 사용하여 다음을 수행합니다:

  • 메타데이터 저장소에서 저장소의 가상 스토리지와 상대 경로를 검색합니다. 해시 스토리지 경로를 얻은 후 Rails 콘솔을 사용하여 프로젝트 경로를 검색할 수 있습니다.
  • 다음 중 하나를 사용하여 저장소가 클러스터에 저장된 위치를 찾습니다:
    • 가상 스토리지와 상대 경로.
    • 저장소 ID.

디스크의 저장소에는 Git 구성 파일에 프로젝트 경로도 포함되어 있습니다. 저장소의 메타데이터가 삭제된 경우에도 이 구성 파일을 사용하여 프로젝트 경로를 확인할 수 있습니다. 해시 스토리지 문서의 지침을 따릅니다.

작업의 원자성#

Gitaly 클러스터(Praefect)는 PostgreSQL 메타데이터 저장소와 스토리지 레이아웃을 사용하여 저장소 생성, 삭제, 이동 작업의 원자성을 보장합니다. 디스크 작업은 여러 스토리지에 걸쳐 원자적으로 적용할 수 없습니다. 그러나 PostgreSQL은 메타데이터 작업의 원자성을 보장합니다. Gitaly 클러스터(Praefect)는 실패한 작업이 항상 메타데이터를 일관된 상태로 유지하는 방식으로 작업을 모델링합니다. 성공적인 작업 후에도 디스크에 오래된 상태가 남아 있을 수 있습니다. 이 상황은 예상된 것이며 남은 상태는 향후 작업을 방해하지 않지만 정리가 수행될 때까지 불필요하게 디스크 공간을 사용할 수 있습니다.

스토리지에서 남은 저장소를 정리하는 백그라운드 크롤러에 대한 작업이 진행 중입니다.

저장소 생성#

저장소를 만들 때 Praefect는:

  1. PostgreSQL에서 저장소 ID를 예약합니다. 이는 원자적이며 두 생성이 동일한 ID를 받지 않습니다.
  2. 저장소 ID에서 파생된 레플리카 경로에 Gitaly 스토리지에 레플리카를 만듭니다.
  3. 디스크에 저장소가 성공적으로 생성된 후 메타데이터 레코드를 만듭니다.

두 개의 동시 작업이 동일한 저장소를 만들더라도 스토리지의 다른 디렉토리에 저장되므로 충돌하지 않습니다. 먼저 완료되는 것이 메타데이터 레코드를 만들고 다른 작업은 "이미 존재함" 오류와 함께 실패합니다. 실패한 생성은 스토리지에 남은 저장소를 남깁니다. 스토리지에서 남은 저장소를 정리하는 백그라운드 크롤러에 대한 작업이 진행 중입니다.

저장소 ID는 PostgreSQL의 repositories_repository_id_seq에서 생성됩니다. 이전 예시에서 실패한 작업은 성공적으로 저장소를 만들지 않고 하나의 저장소 ID를 차지했습니다. 실패한 저장소 생성으로 인해 저장소 ID에 간격이 생기는 것은 예상된 일입니다.

저장소 삭제#

저장소는 메타데이터 레코드를 제거하여 삭제됩니다. 메타데이터 레코드가 삭제되는 즉시 저장소는 논리적으로 존재하지 않게 됩니다. PostgreSQL은 제거의 원자성을 보장하며 동시 삭제는 "찾을 수 없음" 오류와 함께 실패합니다. 메타데이터 레코드를 성공적으로 삭제한 후 Praefect는 스토리지에서 레플리카를 제거하려고 시도합니다. 이는 실패하여 스토리지에 남은 상태를 남길 수 있습니다. 남은 상태는 결국 정리됩니다.

저장소 이동#

Gitaly와 달리 Gitaly 클러스터(Praefect)는 스토리지에서 저장소를 이동하지 않고 메타데이터 저장소에서 저장소의 상대 경로를 업데이트하여 저장소를 가상으로만 이동합니다.

구성 요소#

Gitaly 클러스터(Praefect)는 여러 구성 요소로 구성됩니다:

  • 요청을 분산하고 Praefect 노드에 내결함성 액세스를 제공하는 로드 밸런서.
  • 클러스터를 관리하고 Gitaly 노드로 요청을 라우팅하는 Praefect 노드.
  • 클러스터 메타데이터를 유지하기 위한 PostgreSQL 데이터베이스 및 Praefect의 데이터베이스 연결 풀링에 권장되는 PgBouncer.
  • 저장소 스토리지 및 Git 액세스를 제공하는 Gitaly 노드.

아키텍처#

Praefect는 Gitaly용 라우터 및 트랜잭션 관리자이며 Gitaly 클러스터(Praefect) 실행에 필요한 구성 요소입니다.

Praefect distributing incoming connections to Gitaly Cluster (Praefect) nodes

자세한 내용은 Gitaly 고가용성(HA) 설계를 참조하십시오.

기능#

Gitaly 클러스터(Praefect)는 다음 기능을 제공합니다:

읽기의 수평적 분산을 포함한 제안된 개선 사항은 에픽 1489를 따르십시오.

분산 읽기#

Gitaly 클러스터(Praefect)는 가상 스토리지에 구성된 Gitaly 노드 간에 읽기 작업 분산을 지원합니다.

ACCESSOR 옵션으로 표시된 모든 RPC는 최신 상태이며 정상적인 Gitaly 노드로 리디렉션됩니다. 예를 들어 GetBlob.

여기서 "최신 상태"는 다음을 의미합니다:

  • 이 Gitaly 노드에 대한 복제 작업이 예약되어 있지 않습니다.
  • 마지막 복제 작업이 완료된 상태입니다.

다음과 같은 경우 프라이머리 노드가 요청을 처리하기 위해 선택됩니다:

  • 최신 상태의 노드가 없습니다.
  • 노드 선택 중 다른 오류가 발생합니다.

변경 사항이 Praefect가 보조 노드에 복제할 수 있는 것보다 더 빠르게 들어오는 경우(예: 매우 크고 빈번하게 수정되는 저장소) 프라이머리 노드가 대부분 또는 모든 요청을 처리할 수 있습니다. 이 경우 CI/CD 잡 및 기타 저장소 트래픽이 프라이머리 노드의 용량으로 병목 현상이 발생합니다.

Prometheus를 사용하여 읽기 분산을 모니터링할 수 있습니다.

강한 일관성#

Gitaly 클러스터(Praefect)는 모든 정상적인 최신 레플리카에 동기적으로 변경 사항을 기록하여 강한 일관성을 제공합니다. 레플리카가 트랜잭션 시점에 오래되었거나 비정상적인 경우 쓰기는 비동기적으로 복제됩니다.

강한 일관성은 기본 복제 방법입니다. 일부 작업은 강한 일관성 대신 복제 잡(결과적 일관성)을 사용합니다. 자세한 내용은 강한 일관성 에픽을 참조하십시오.

강한 일관성을 사용할 수 없는 경우 Gitaly 클러스터(Praefect)는 결과적 일관성을 보장합니다. 이 경우 Gitaly 클러스터(Praefect)는 프라이머리 Gitaly 노드에 쓰기가 발생한 후 보조 Gitaly 노드에 모든 쓰기를 복제합니다.

강한 일관성 모니터링에 대한 자세한 내용은 Gitaly 클러스터(Praefect) 모니터링을 참조하십시오.

복제 계수#

복제 계수는 Gitaly 클러스터(Praefect)가 주어진 저장소의 복사본을 유지하는 수입니다. 더 높은 복제 계수는:

  • 더 나은 중복성과 읽기 워크로드 분산을 제공합니다.
  • 더 높은 스토리지 비용을 초래합니다.

기본적으로 Gitaly 클러스터(Praefect)는 가상 스토리지의 모든 스토리지에 저장소를 복제합니다.

구성 정보는 복제 계수 구성을 참조하십시오.

Gitaly 클러스터(Praefect) 업그레이드#

Gitaly 클러스터(Praefect)를 업그레이드하려면 제로 다운타임 업그레이드 문서를 따르십시오.

Gitaly 클러스터(Praefect)를 이전 버전으로 롤백#

Gitaly 클러스터(Praefect)를 이전 버전으로 롤백해야 하는 경우 일부 Praefect 데이터베이스 마이그레이션을 되돌려야 할 수 있습니다.

여러 Praefect 노드가 있는 경우 Gitaly 클러스터(Praefect)를 롤백하려면:

  1. 모든 Praefect 노드에서 Praefect 서비스를 중지합니다:

    gitlab-ctl stop praefect
    
  2. Praefect 노드 중 하나에서 GitLab 패키지를 이전 버전으로 롤백합니다.

  3. 롤백된 노드에서 Praefect 마이그레이션 상태를 확인합니다:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status
    
  4. APPLIED 열에 unknown migration이 있는 마이그레이션 수를 세어봅니다.

  5. 롤백되지 않은 Praefect 노드에서 롤백의 드라이 런을 수행하여 되돌릴 마이그레이션을 검증합니다. 은 롤백된 노드에서 보고한 알 수 없는 마이그레이션 수입니다.

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate 
    
  6. 결과가 올바르면 -f 옵션을 사용하여 동일한 명령을 실행하여 마이그레이션을 되돌립니다:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate -f 
    
  7. 나머지 Praefect 노드에서 GitLab 패키지를 롤백하고 Praefect 서비스를 다시 시작합니다:

    gitlab-ctl start praefect
    

Gitaly 클러스터(Praefect)로 마이그레이션#

Warning

Gitaly 클러스터(Praefect)에는 일부 알려진 문제가 있습니다. 계속하기 전에 다음 정보를 검토하십시오.

Gitaly 클러스터(Praefect)로 마이그레이션하기 전에:

Gitaly 클러스터(Praefect)로 마이그레이션하려면:

  1. 필요한 스토리지를 만듭니다. 저장소 스토리지 권장 사항을 참조합니다.
  2. Gitaly 클러스터(Praefect)를 만들고 구성합니다.
  3. 아직 그렇게 구성되지 않은 경우 기존 Gitaly 인스턴스를 TCP 사용으로 구성합니다.
  4. 저장소를 이동합니다. Gitaly 클러스터(Praefect)로 마이그레이션하려면 Gitaly 클러스터(Praefect) 외부에 저장된 기존 저장소를 이동해야 합니다. 자동 마이그레이션은 없지만 GitLab API로 이동을 예약할 수 있습니다.

default 저장소 스토리지를 사용하지 않더라도 구성해야 합니다. 이 제한 사항에 대한 자세한 내용.

Kubernetes의 Gitaly 차트에서 마이그레이션하려면 특정 마이그레이션 지침을 따릅니다.

Gitaly 클러스터(Praefect)에서 마이그레이션#

Gitaly 클러스터(Praefect)의 제한 사항과 트레이드오프가 환경에 적합하지 않은 경우 Gitaly 클러스터(Praefect)에서 샤드된 Gitaly 인스턴스로 마이그레이션할 수 있습니다:

  1. Gitaly 서버를 만들고 구성합니다.
  2. 새로 생성된 스토리지로 저장소를 이동합니다. 샤드 또는 그룹별로 이동할 수 있으며 여러 Gitaly 서버에 분산할 수 있습니다.

Gitaly 클러스터(Praefect)

Tier: Free, Premium, Ultimate
Offering: GitLab Self-Managed
원문 보기
요약

Git 스토리지는 GitLab의 Gitaly 서비스를 통해 제공되며 GitLab 운영에 필수적입니다. Gitaly는 클러스터 구성으로 실행하여 다음을 달성할 수 있습니다: 이 구성에서 모든 Git 저장소는 클러스터의 여러 Gitaly 노드에 저장될 수 있습니다.

Git 스토리지는 GitLab의 Gitaly 서비스를 통해 제공되며 GitLab 운영에 필수적입니다. 사용자, 저장소, 활동 수가 증가함에 따라 다음을 통해 Gitaly를 적절히 확장하는 것이 중요합니다:

  • 리소스 고갈로 Git, Gitaly, GitLab 애플리케이션 성능이 저하되기 전에 Git에서 사용 가능한 CPU 및 메모리 리소스를 늘립니다.
  • 스토리지 한도에 도달하여 쓰기 작업이 실패하기 전에 사용 가능한 스토리지를 늘립니다.
  • 단일 장애 지점을 제거하여 내결함성을 향상시킵니다. 서비스 저하가 프로덕션에 대한 변경 배포를 방해할 경우 Git은 미션 크리티컬로 간주해야 합니다.

Gitaly는 클러스터 구성으로 실행하여 다음을 달성할 수 있습니다:

  • Gitaly 서비스 확장.
  • 내결함성 향상.

이 구성에서 모든 Git 저장소는 클러스터의 여러 Gitaly 노드에 저장될 수 있습니다.

Gitaly 클러스터(Praefect)를 사용하면 다음을 통해 내결함성이 향상됩니다:

  • 대기 Gitaly 노드에 쓰기 작업 복제.
  • Gitaly 노드 장애 감지.
  • 사용 가능한 Gitaly 노드로 Git 요청 자동 라우팅.
Note

Gitaly 클러스터(Praefect)에 대한 기술 지원은 GitLab Premium 및 Ultimate 고객으로 제한됩니다.

다음은 Gitaly 클러스터(Praefect)에서 제공하는 가상 스토리지인 storage-1에 액세스하도록 설정된 GitLab을 보여줍니다:

GitLab application interacting with virtual Gitaly storage, which interacts with Gitaly physical storage

이 예시에서:

  • 저장소는 storage-1이라는 가상 스토리지에 저장됩니다.
  • 세 개의 Gitaly 노드가 storage-1 액세스를 제공합니다: gitaly-1, gitaly-2, gitaly-3.
  • 세 개의 Gitaly 노드는 세 개의 개별 해시 스토리지 위치에서 데이터를 공유합니다.
  • 복제 계수3입니다. 각 저장소의 복사본이 세 개 유지됩니다.

단일 노드 장애를 가정한 Gitaly 클러스터(Praefect)의 가용성 목표는:

  • 복구 시점 목표(RPO): 1분 미만.

    쓰기는 비동기적으로 복제됩니다. 새로 승격된 프라이머리에 복제되지 않은 쓰기는 손실됩니다. 실패한 노드에서 진행 중이던 읽기 작업은 종료됩니다.

    강한 일관성은 일부 상황에서 손실을 방지합니다.

  • 복구 시간 목표(RTO): 10초 미만. 중단은 각 Praefect 노드가 매초 실행하는 상태 확인에 의해 감지됩니다. 페일오버는 각 Praefect 노드에서 연속적으로 10번 실패한 상태 확인이 필요합니다.

RPO 및 RTO 개선 사항은 에픽 8903에서 제안됩니다.

Warning

완전한 클러스터 장애가 발생하면 재해 복구 계획을 실행해야 합니다. 이는 앞서 설명한 RPO 및 RTO에 영향을 미칠 수 있습니다.

Gitaly 클러스터(Praefect) 배포 전에#

Gitaly 클러스터(Praefect)는 내결함성의 이점을 제공하지만 추가적인 설정 및 관리 복잡성이 따릅니다. Gitaly 클러스터(Praefect)를 배포하기 전에 다음을 참조하십시오:

아직 Gitaly 클러스터(Praefect)로 마이그레이션하지 않은 경우 두 가지 옵션이 있습니다:

  • 샤드된 Gitaly 인스턴스.
  • Gitaly 클러스터(Praefect).

질문이 있으면 고객 성공 관리자 또는 고객 지원에 문의하십시오.

이미 Gitaly 클러스터(Praefect)를 사용 중이고 문제 또는 제한을 경험하고 있는 경우 복원 또는 복구에 대한 즉각적인 도움을 위해 고객 지원에 문의하십시오.

알려진 문제#

다음 표는 Gitaly 클러스터(Praefect) 사용에 영향을 미치는 현재 알려진 문제를 요약합니다. 이러한 문제의 현재 상태는 참조된 이슈와 에픽을 참조하십시오.

문제 요약 방지 방법
Gitaly 클러스터(Praefect) + Geo - 실패한 동기화 재시도 문제 Gitaly 클러스터(Praefect)가 Geo 보조 사이트에서 사용되는 경우 동기화에 실패한 저장소가 Geo가 다시 동기화를 시도할 때 계속 실패할 수 있습니다. 이 상태에서 복구하려면 지원의 도움을 받아 수동 단계를 실행해야 합니다. GitLab 15.0에서 15.2까지는 Geo 프라이머리 사이트에서 gitaly_praefect_generated_replica_paths 기능 플래그를 활성화합니다. GitLab 15.3에서는 기능 플래그가 기본적으로 활성화됩니다.
업그레이드 후 마이그레이션이 적용되지 않아 Praefect가 데이터베이스에 데이터를 삽입할 수 없음 데이터베이스가 완료된 마이그레이션으로 최신 상태를 유지하지 않으면 Praefect 노드가 표준 작업을 수행할 수 없습니다. Praefect 데이터베이스가 모든 마이그레이션이 완료된 상태로 실행 중인지 확인합니다. 예를 들어 이 명령은 적용된 모든 마이그레이션 목록을 표시해야 합니다: sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status. 업그레이드 계획을 지원이 검토할 수 있도록 업그레이드 지원 요청을 고려합니다.
실행 중인 클러스터의 스냅샷에서 Gitaly 클러스터(Praefect) 노드 복원 Gitaly 클러스터(Praefect)는 일관된 상태로 실행되므로 뒤처진 단일 노드를 도입하면 클러스터가 다른 노드의 데이터와 해당 노드의 데이터를 조정할 수 없게 됩니다. 백업 스냅샷에서 단일 Gitaly 클러스터(Praefect) 노드를 복원하지 마십시오. 백업에서 복원해야 하는 경우:

1. GitLab을 종료합니다.
2. 모든 Gitaly 클러스터(Praefect) 노드를 동시에 스냅샷합니다.
3. Praefect 데이터베이스의 덤프를 가져옵니다.
Kubernetes, Amazon ECS 또는 이와 유사한 환경에서 실행 시 제한 사항 Gitaly 클러스터(Praefect)는 지원되지 않으며 Gitaly에는 알려진 제한 사항이 있습니다. 자세한 내용은 에픽 6127을 참조하십시오. 참조 아키텍처를 사용합니다.
Praefect가 쓰기를 기록하기 전에 PostReceiveHook 호출 경쟁 조건으로 인해 PostReceiveHook이 쓰기가 모든 노드에 복제되기 전에 실행될 수 있습니다. CI/CD 파이프라인이 아직 쓰기를 받지 못한 레플리카를 대상으로 할 때 이 경쟁 조건으로 인해 파이프라인이 couldn't find remote ref refs/merge-requests/$iid/{head,merge} 오류와 함께 실패합니다. 자세한 내용은 이슈 5406을 참조하십시오 전체 잡 또는 소스 가져오기 단계만 재시도합니다. 자세한 내용은 잡 단계 시도를 참조하십시오.
HPA 자동 확장으로 인해 스토리지 이동이 자동으로 실패할 수 있음 Sidekiq 파드에서 수평 파드 자동 확장기(HPA)를 사용할 때 파드 확장 중에 저장소 스토리지 이동이 자동으로 실패할 수 있습니다. 저장소 스토리지 이동을 수행하기 전에 HPA를 고정 레플리카로 구성하고, 마이그레이션 중 확장을 방지하기 위해 minReplicas = maxReplicas를 설정합니다.

스냅샷 백업 및 복구#

Gitaly 클러스터(Praefect)는 스냅샷 백업을 지원하지 않습니다. 스냅샷 백업은 Praefect 데이터베이스가 디스크 스토리지와 동기화되지 않는 문제를 일으킬 수 있습니다. Praefect가 복원 중에 Gitaly 디스크 정보의 복제 메타데이터를 재구축하는 방식으로 인해 공식 백업 및 복원 Rake 작업을 사용해야 합니다.

증분 백업 방법을 사용하면 Gitaly 클러스터(Praefect) 백업 속도를 높일 수 있습니다.

두 방법 중 어느 것도 사용할 수 없는 경우 복원 도움을 위해 고객 지원에 문의하십시오.

Geo와의 비교#

Gitaly 클러스터(Praefect)와 Geo는 서로 다른 유형의 중복성을 제공합니다.

  • Gitaly 클러스터(Praefect)의 중복성은 데이터 스토리지에 대한 내결함성을 제공하며 사용자에게 투명합니다.
  • Geo의 중복성은 전체 GitLab 인스턴스에 대한 복제(사용자에게 표시됨)와 재해 복구를 제공합니다. Geo는 Git 데이터를 포함한 여러 데이터 유형을 복제합니다.

다음 표는 Gitaly 클러스터(Praefect)와 Geo의 주요 차이점을 요약합니다:

도구 노드 위치 지연 시간 허용 범위 페일오버 일관성 다음에 대한 중복성 제공
Gitaly 클러스터(Praefect) 여러 개 단일 1초 미만, 이상적으로는 한 자릿수 밀리초 자동 강함 Git의 데이터 스토리지
Geo 여러 개 여러 개 최대 1분 수동 결과적 전체 GitLab 인스턴스

자세한 내용은 다음을 참조하십시오:

가상 스토리지#

가상 스토리지를 통해 GitLab에서 단일 저장소 스토리지를 갖는 것이 가능하며 저장소 관리를 단순화합니다.

Gitaly 클러스터(Praefect)를 사용한 가상 스토리지는 일반적으로 직접 Gitaly 스토리지 구성을 대체할 수 있습니다. 그러나 이는 각 저장소를 여러 Gitaly 노드에 저장하는 데 필요한 추가 스토리지 공간의 비용이 따릅니다. 직접 Gitaly 스토리지 대비 Gitaly 클러스터(Praefect) 가상 스토리지를 사용하는 이점은:

  • 향상된 내결함성 - 각 Gitaly 노드가 모든 저장소의 복사본을 가집니다.
  • 향상된 리소스 활용 - 읽기 부하가 Gitaly 노드 간에 분산되므로 샤드별 최대 부하에 대한 과도한 프로비저닝 필요성이 줄어듭니다.
  • 수동 재균형 불필요 - 읽기 부하가 Gitaly 노드 간에 분산됩니다.
  • 간소화된 관리 - 모든 Gitaly 노드가 동일합니다.

저장소 레플리카 수는 복제 계수를 사용하여 구성할 수 있습니다.

모든 저장소에 동일한 복제 계수를 갖는 것은 비경제적일 수 있습니다. 매우 큰 GitLab 인스턴스에 더 큰 유연성을 제공하기 위해 가변 복제 계수가 이 이슈에서 추적됩니다.

표준 Gitaly 스토리지와 마찬가지로 가상 스토리지도 샤딩할 수 있습니다.

여러 가상 스토리지#

Gitaly 클러스터(Praefect) 배포에서 여러 가상 스토리지를 구성할 수 있습니다. 이를 통해 다음을 할 수 있습니다:

  • 서로 다른 성능 특성을 가진 별도의 클러스터로 저장소를 구성합니다.
  • 저장소 그룹에 따라 서로 다른 복제 계수를 적용합니다.
  • 인프라의 다른 부분을 독립적으로 확장합니다.

가상 스토리지는 GitLab 서버의 gitlab_rails['repositories_storages']에 구성됩니다. 이 해시의 각 항목은 별개의 가상 스토리지를 나타냅니다. Praefect 구성은 각 가상 스토리지를 서비스하는 Gitaly 노드를 정의합니다. 서로 다른 가상 스토리지의 저장소는 완전히 독립적이며 가상 스토리지 간에 복제되지 않습니다.

예를 들어 다음과 같이 구성할 수 있습니다:

  • storage-1: 복제 계수 3인 중요한 프로덕션 저장소용 가상 스토리지.
  • storage-2: 복제 계수 2인 덜 중요한 저장소용 가상 스토리지.

각 가상 스토리지에는 자체 Gitaly 노드 세트가 필요합니다.

Mermaid 다이어그램 (18줄)
소스 코드 보기
%%{init: { "fontFamily": "GitLab Sans" }}%%
graph TD
    accTitle: Multiple virtual storages
    accDescr: Example of multiple virtual storages, one with a replication factor of three and one with a replication factor of two.
GitLab[[GitLab server]]
Storage1[(storage-1&lt;br/&gt;Praefect cluster)]
Storage2[(storage-2&lt;br/&gt;Praefect cluster)]

GitLab --&gt; Storage1
GitLab --&gt; Storage2

Storage1 --&gt; G1[Gitaly node 1]
Storage1 --&gt; G2[Gitaly node 2]
Storage1 --&gt; G3[Gitaly node 3]

Storage2 --&gt; G4[Gitaly node 4]
Storage2 --&gt; G5[Gitaly node 5]</code></pre></details></div>

구성 지침은 여러 가상 스토리지 구성을 참조하십시오.

혼합 구성#

GitLab을 다음의 조합으로 사용하도록 구성할 수 있습니다:

  • 독립형 Gitaly 인스턴스(직접 Gitaly 스토리지).
  • Gitaly 클러스터(Praefect) 가상 스토리지.

다음과 같은 경우 혼합 구성을 사용할 수 있습니다:

  • 독립형 Gitaly에서 Gitaly 클러스터(Praefect)로 점진적으로 마이그레이션하는 경우.
  • 일부 저장소는 고가용성이 필요하고 다른 저장소는 그렇지 않은 경우.
  • 중요한 저장소에만 Gitaly 클러스터(Praefect)를 사용하여 비용을 최적화하려는 경우.

혼합 구성에서 각 스토리지는 GitLab에서 독립적으로 구성됩니다:

  • 독립형 Gitaly 스토리지는 Gitaly 노드에 직접 연결됩니다.
  • Gitaly 클러스터(Praefect) 스토리지는 Praefect 로드 밸런서에 연결됩니다.

GitLab은 독립형인지 클러스터된인지에 관계없이 모든 구성된 스토리지를 동등하게 취급합니다. 새 저장소를 만들 때 GitLab은 구성된 스토리지 가중치와 사용 가능한 용량을 기반으로 스토리지를 선택합니다.

Mermaid 다이어그램 (15줄)
소스 코드 보기
%%{init: { "fontFamily": "GitLab Sans" }}%%
graph TD
    accTitle: Mixed configuration
    accDescr: Example result of mixed configuration, with a Gitaly Cluster (Praefect) and standalone Gitaly configured together.
GitLab[[GitLab server]]
Praefect[(Praefect cluster)]
Standalone1[(Standalone gitaly)]

GitLab --&gt;|cluster storage| Praefect
GitLab --&gt;|default storage| Standalone1

Praefect --&gt; G1[Gitaly node 1]
Praefect --&gt; G2[Gitaly node 2]
Praefect --&gt; G3[Gitaly node 3]</code></pre></details></div>

자세한 내용은 다음을 참조하십시오:

스토리지 레이아웃#

Warning

스토리지 레이아웃은 Gitaly 클러스터(Praefect)의 내부 세부 사항이며 릴리스 간에 안정적으로 유지되는 것이 보장되지 않습니다. 여기의 정보는 참고 목적으로만 제공되며 디버깅에 도움을 주기 위한 것입니다. 디스크에서 직접 저장소를 변경하는 것은 지원되지 않으며 장애를 일으키거나 변경 사항이 덮어쓰여질 수 있습니다.

Gitaly 클러스터(Praefect) 가상 스토리지는 단일 스토리지처럼 보이는 추상화를 제공하지만 실제로는 여러 물리적 스토리지로 구성됩니다. Gitaly 클러스터(Praefect)는 각 물리적 스토리지에 각 작업을 복제해야 합니다. 작업은 일부 물리적 스토리지에서는 성공하고 다른 곳에서는 실패할 수 있습니다.

부분적으로 적용된 작업은 다른 작업에 문제를 일으키고 시스템이 복구할 수 없는 상태로 만들 수 있습니다. 이러한 문제를 방지하기 위해 각 작업은 완전히 적용되거나 전혀 적용되지 않아야 합니다. 작업의 이 속성을 원자성이라고 합니다.

GitLab은 저장소 스토리지의 스토리지 레이아웃을 제어합니다. GitLab은 저장소 스토리지에 저장소를 생성, 삭제, 이동할 위치를 지시합니다. 이러한 작업은 여러 물리적 스토리지에 적용될 때 원자성 문제를 일으킵니다. 예를 들어:

  • GitLab이 레플리카 중 하나를 사용할 수 없는 동안 저장소를 삭제합니다.
  • GitLab이 나중에 저장소를 다시 생성합니다.

그 결과 삭제 시 사용할 수 없었던 오래된 레플리카가 충돌을 일으키고 저장소 재생성을 방해할 수 있습니다.

이러한 원자성 문제는 다음과 관련하여 과거에 여러 문제를 일으켰습니다:

  • Gitaly 클러스터(Praefect)가 있는 보조 사이트로의 Geo 동기화.
  • 백업 복원.
  • 저장소 스토리지 간 저장소 이동.

Gitaly 클러스터(Praefect)는 부분적으로 적용된 작업으로 인해 발생할 수 있는 충돌을 방지하는 특수 레이아웃에 디스크에 저장소를 저장하여 이러한 작업에 원자성을 제공합니다.

클라이언트 생성 레플리카 경로#

저장소는 Gitaly 클라이언트에 의해 결정된 상대 경로에 스토리지에 저장됩니다. 이러한 경로는 @cluster 접두사로 시작하지 않는 것으로 식별할 수 있습니다. 상대 경로는 해시 스토리지 스키마를 따릅니다.

Praefect 생성 레플리카 경로#

Gitaly 클러스터(Praefect)가 저장소를 만들 때 저장소에 _저장소 ID_라고 하는 고유하고 영구적인 ID를 할당합니다. 저장소 ID는 Gitaly 클러스터(Praefect)에 내부적이며 GitLab의 다른 곳에 있는 ID와 관련이 없습니다. 저장소가 Gitaly 클러스터(Praefect)에서 제거되고 나중에 다시 이동되면 저장소에 새 저장소 ID가 할당되며 Gitaly 클러스터(Praefect)의 관점에서 다른 저장소가 됩니다. 저장소 ID의 시퀀스는 항상 증가하지만 시퀀스에 간격이 있을 수 있습니다.

저장소 ID는 클러스터의 각 저장소에 대한 _레플리카 경로_라는 고유한 스토리지 경로를 도출하는 데 사용됩니다. 저장소의 레플리카는 모두 스토리지의 동일한 레플리카 경로에 저장됩니다. 레플리카 경로는 _상대 경로_와 구별됩니다:

  • 상대 경로는 Gitaly 클라이언트가 가상 스토리지와 함께 저장소를 식별하는 데 사용하는 이름으로, 그것들에게 고유합니다.
  • 레플리카 경로는 물리적 스토리지의 실제 물리적 경로입니다.

Praefect는 클라이언트 요청을 처리할 때 RPC의 저장소를 가상 (가상 스토리지, 상대 경로) 식별자에서 물리적 저장소 (스토리지, 레플리카_경로) 식별자로 변환합니다.

레플리카 경로의 형식:

  • 오브젝트 풀은 @cluster/pools/<xx>/<xx>/<저장소 ID>입니다. 오브젝트 풀은 다른 저장소와 다른 디렉토리에 저장됩니다. 하우스키핑의 일부로 가지치기되는 것을 방지하기 위해 Gitaly에서 식별 가능해야 합니다. 오브젝트 풀을 가지치기하면 연결된 저장소에서 데이터가 손실될 수 있습니다.
  • 다른 저장소는 @cluster/repositories/<xx>/<xx>/<저장소 ID>입니다.

예를 들어 @cluster/repositories/6f/96/54771.

레플리카 경로의 마지막 구성 요소인 54771이 저장소 ID입니다. 이를 사용하여 디스크에서 저장소를 식별할 수 있습니다.

<xx>/<xx>는 저장소 ID의 문자열 표현의 SHA256 해시의 처음 네 개 16진수입니다. 이 숫자는 일부 파일 시스템에서 문제를 일으킬 수 있는 지나치게 큰 디렉토리를 피하기 위해 저장소를 하위 디렉토리에 고르게 분산하는 데 사용됩니다. 이 경우 547716f960ab01689464e768366d3315b3d3b2c28f38761a58a70110554eb04d582f7로 해시되므로 처음 네 자리는 6f96입니다.

디스크에서 저장소 식별#

praefect metadata 하위 명령을 사용하여 다음을 수행합니다:

  • 메타데이터 저장소에서 저장소의 가상 스토리지와 상대 경로를 검색합니다. 해시 스토리지 경로를 얻은 후 Rails 콘솔을 사용하여 프로젝트 경로를 검색할 수 있습니다.
  • 다음 중 하나를 사용하여 저장소가 클러스터에 저장된 위치를 찾습니다:
    • 가상 스토리지와 상대 경로.
    • 저장소 ID.

디스크의 저장소에는 Git 구성 파일에 프로젝트 경로도 포함되어 있습니다. 저장소의 메타데이터가 삭제된 경우에도 이 구성 파일을 사용하여 프로젝트 경로를 확인할 수 있습니다. 해시 스토리지 문서의 지침을 따릅니다.

작업의 원자성#

Gitaly 클러스터(Praefect)는 PostgreSQL 메타데이터 저장소와 스토리지 레이아웃을 사용하여 저장소 생성, 삭제, 이동 작업의 원자성을 보장합니다. 디스크 작업은 여러 스토리지에 걸쳐 원자적으로 적용할 수 없습니다. 그러나 PostgreSQL은 메타데이터 작업의 원자성을 보장합니다. Gitaly 클러스터(Praefect)는 실패한 작업이 항상 메타데이터를 일관된 상태로 유지하는 방식으로 작업을 모델링합니다. 성공적인 작업 후에도 디스크에 오래된 상태가 남아 있을 수 있습니다. 이 상황은 예상된 것이며 남은 상태는 향후 작업을 방해하지 않지만 정리가 수행될 때까지 불필요하게 디스크 공간을 사용할 수 있습니다.

스토리지에서 남은 저장소를 정리하는 백그라운드 크롤러에 대한 작업이 진행 중입니다.

저장소 생성#

저장소를 만들 때 Praefect는:

  1. PostgreSQL에서 저장소 ID를 예약합니다. 이는 원자적이며 두 생성이 동일한 ID를 받지 않습니다.
  2. 저장소 ID에서 파생된 레플리카 경로에 Gitaly 스토리지에 레플리카를 만듭니다.
  3. 디스크에 저장소가 성공적으로 생성된 후 메타데이터 레코드를 만듭니다.

두 개의 동시 작업이 동일한 저장소를 만들더라도 스토리지의 다른 디렉토리에 저장되므로 충돌하지 않습니다. 먼저 완료되는 것이 메타데이터 레코드를 만들고 다른 작업은 "이미 존재함" 오류와 함께 실패합니다. 실패한 생성은 스토리지에 남은 저장소를 남깁니다. 스토리지에서 남은 저장소를 정리하는 백그라운드 크롤러에 대한 작업이 진행 중입니다.

저장소 ID는 PostgreSQL의 repositories_repository_id_seq에서 생성됩니다. 이전 예시에서 실패한 작업은 성공적으로 저장소를 만들지 않고 하나의 저장소 ID를 차지했습니다. 실패한 저장소 생성으로 인해 저장소 ID에 간격이 생기는 것은 예상된 일입니다.

저장소 삭제#

저장소는 메타데이터 레코드를 제거하여 삭제됩니다. 메타데이터 레코드가 삭제되는 즉시 저장소는 논리적으로 존재하지 않게 됩니다. PostgreSQL은 제거의 원자성을 보장하며 동시 삭제는 "찾을 수 없음" 오류와 함께 실패합니다. 메타데이터 레코드를 성공적으로 삭제한 후 Praefect는 스토리지에서 레플리카를 제거하려고 시도합니다. 이는 실패하여 스토리지에 남은 상태를 남길 수 있습니다. 남은 상태는 결국 정리됩니다.

저장소 이동#

Gitaly와 달리 Gitaly 클러스터(Praefect)는 스토리지에서 저장소를 이동하지 않고 메타데이터 저장소에서 저장소의 상대 경로를 업데이트하여 저장소를 가상으로만 이동합니다.

구성 요소#

Gitaly 클러스터(Praefect)는 여러 구성 요소로 구성됩니다:

  • 요청을 분산하고 Praefect 노드에 내결함성 액세스를 제공하는 로드 밸런서.
  • 클러스터를 관리하고 Gitaly 노드로 요청을 라우팅하는 Praefect 노드.
  • 클러스터 메타데이터를 유지하기 위한 PostgreSQL 데이터베이스 및 Praefect의 데이터베이스 연결 풀링에 권장되는 PgBouncer.
  • 저장소 스토리지 및 Git 액세스를 제공하는 Gitaly 노드.

아키텍처#

Praefect는 Gitaly용 라우터 및 트랜잭션 관리자이며 Gitaly 클러스터(Praefect) 실행에 필요한 구성 요소입니다.

Praefect distributing incoming connections to Gitaly Cluster (Praefect) nodes

자세한 내용은 Gitaly 고가용성(HA) 설계를 참조하십시오.

기능#

Gitaly 클러스터(Praefect)는 다음 기능을 제공합니다:

읽기의 수평적 분산을 포함한 제안된 개선 사항은 에픽 1489를 따르십시오.

분산 읽기#

Gitaly 클러스터(Praefect)는 가상 스토리지에 구성된 Gitaly 노드 간에 읽기 작업 분산을 지원합니다.

ACCESSOR 옵션으로 표시된 모든 RPC는 최신 상태이며 정상적인 Gitaly 노드로 리디렉션됩니다. 예를 들어 GetBlob.

여기서 "최신 상태"는 다음을 의미합니다:

  • 이 Gitaly 노드에 대한 복제 작업이 예약되어 있지 않습니다.
  • 마지막 복제 작업이 완료된 상태입니다.

다음과 같은 경우 프라이머리 노드가 요청을 처리하기 위해 선택됩니다:

  • 최신 상태의 노드가 없습니다.
  • 노드 선택 중 다른 오류가 발생합니다.

변경 사항이 Praefect가 보조 노드에 복제할 수 있는 것보다 더 빠르게 들어오는 경우(예: 매우 크고 빈번하게 수정되는 저장소) 프라이머리 노드가 대부분 또는 모든 요청을 처리할 수 있습니다. 이 경우 CI/CD 잡 및 기타 저장소 트래픽이 프라이머리 노드의 용량으로 병목 현상이 발생합니다.

Prometheus를 사용하여 읽기 분산을 모니터링할 수 있습니다.

강한 일관성#

Gitaly 클러스터(Praefect)는 모든 정상적인 최신 레플리카에 동기적으로 변경 사항을 기록하여 강한 일관성을 제공합니다. 레플리카가 트랜잭션 시점에 오래되었거나 비정상적인 경우 쓰기는 비동기적으로 복제됩니다.

강한 일관성은 기본 복제 방법입니다. 일부 작업은 강한 일관성 대신 복제 잡(결과적 일관성)을 사용합니다. 자세한 내용은 강한 일관성 에픽을 참조하십시오.

강한 일관성을 사용할 수 없는 경우 Gitaly 클러스터(Praefect)는 결과적 일관성을 보장합니다. 이 경우 Gitaly 클러스터(Praefect)는 프라이머리 Gitaly 노드에 쓰기가 발생한 후 보조 Gitaly 노드에 모든 쓰기를 복제합니다.

강한 일관성 모니터링에 대한 자세한 내용은 Gitaly 클러스터(Praefect) 모니터링을 참조하십시오.

복제 계수#

복제 계수는 Gitaly 클러스터(Praefect)가 주어진 저장소의 복사본을 유지하는 수입니다. 더 높은 복제 계수는:

  • 더 나은 중복성과 읽기 워크로드 분산을 제공합니다.
  • 더 높은 스토리지 비용을 초래합니다.

기본적으로 Gitaly 클러스터(Praefect)는 가상 스토리지의 모든 스토리지에 저장소를 복제합니다.

구성 정보는 복제 계수 구성을 참조하십시오.

Gitaly 클러스터(Praefect) 업그레이드#

Gitaly 클러스터(Praefect)를 업그레이드하려면 제로 다운타임 업그레이드 문서를 따르십시오.

Gitaly 클러스터(Praefect)를 이전 버전으로 롤백#

Gitaly 클러스터(Praefect)를 이전 버전으로 롤백해야 하는 경우 일부 Praefect 데이터베이스 마이그레이션을 되돌려야 할 수 있습니다.

여러 Praefect 노드가 있는 경우 Gitaly 클러스터(Praefect)를 롤백하려면:

  1. 모든 Praefect 노드에서 Praefect 서비스를 중지합니다:

    gitlab-ctl stop praefect
    
  2. Praefect 노드 중 하나에서 GitLab 패키지를 이전 버전으로 롤백합니다.

  3. 롤백된 노드에서 Praefect 마이그레이션 상태를 확인합니다:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate-status
    
  4. APPLIED 열에 unknown migration이 있는 마이그레이션 수를 세어봅니다.

  5. 롤백되지 않은 Praefect 노드에서 롤백의 드라이 런을 수행하여 되돌릴 마이그레이션을 검증합니다. 은 롤백된 노드에서 보고한 알 수 없는 마이그레이션 수입니다.

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate 
    
  6. 결과가 올바르면 -f 옵션을 사용하여 동일한 명령을 실행하여 마이그레이션을 되돌립니다:

    sudo -u git -- /opt/gitlab/embedded/bin/praefect -config /var/opt/gitlab/praefect/config.toml sql-migrate -f 
    
  7. 나머지 Praefect 노드에서 GitLab 패키지를 롤백하고 Praefect 서비스를 다시 시작합니다:

    gitlab-ctl start praefect
    

Gitaly 클러스터(Praefect)로 마이그레이션#

Warning

Gitaly 클러스터(Praefect)에는 일부 알려진 문제가 있습니다. 계속하기 전에 다음 정보를 검토하십시오.

Gitaly 클러스터(Praefect)로 마이그레이션하기 전에:

Gitaly 클러스터(Praefect)로 마이그레이션하려면:

  1. 필요한 스토리지를 만듭니다. 저장소 스토리지 권장 사항을 참조합니다.
  2. Gitaly 클러스터(Praefect)를 만들고 구성합니다.
  3. 아직 그렇게 구성되지 않은 경우 기존 Gitaly 인스턴스를 TCP 사용으로 구성합니다.
  4. 저장소를 이동합니다. Gitaly 클러스터(Praefect)로 마이그레이션하려면 Gitaly 클러스터(Praefect) 외부에 저장된 기존 저장소를 이동해야 합니다. 자동 마이그레이션은 없지만 GitLab API로 이동을 예약할 수 있습니다.

default 저장소 스토리지를 사용하지 않더라도 구성해야 합니다. 이 제한 사항에 대한 자세한 내용.

Kubernetes의 Gitaly 차트에서 마이그레이션하려면 특정 마이그레이션 지침을 따릅니다.

Gitaly 클러스터(Praefect)에서 마이그레이션#

Gitaly 클러스터(Praefect)의 제한 사항과 트레이드오프가 환경에 적합하지 않은 경우 Gitaly 클러스터(Praefect)에서 샤드된 Gitaly 인스턴스로 마이그레이션할 수 있습니다:

  1. Gitaly 서버를 만들고 구성합니다.
  2. 새로 생성된 스토리지로 저장소를 이동합니다. 샤드 또는 그룹별로 이동할 수 있으며 여러 Gitaly 서버에 분산할 수 있습니다.