Status | Authors | Coach | DRIs | Owning Stage | Created |
---|---|---|---|---|---|
proposed |
@proglottis
|
@DylanGriffith
| devops systems | 2023-04-26 |
리포지터리 백업
요약
이 제안은 지탈리에 특화된 최적화를 적용할 수 있는 새로운 리포지터리 백업 솔루션을 GitLab에 제공하려고 합니다. 이를 위해 backup.rake
에서 리포지터리 백업을 하지 않고 리포지터리를 열거하고 리포지터리별로 백업을 트리거하는 조정 워커로 이동함으로써 Gitaly에서 직접 object-storage로 백업을 스트리밍합니다.
이 방식의 장점은 다음과 같습니다.
- 백업은 물리적 리포지터리를 호스팅하는 Gitaly에서 object-storage로 한 번만 전송됩니다.
- 특정 리포지터리 액세스 패턴을 활용하여 더 스마트한 결정을 내릴 수 있습니다.
- 백업 및 복원 부하를 분산시킵니다.
- 전체 프로세스가 Gitaly 내에서 실행되기 때문에 기존 모니터링을 사용할 수 있습니다.
- 미래의 WAL 아카이빙 및 기타 최적화를 위한 아키텍처를 제공합니다.
이로써 기존의 두 가지 전략의 주요한 트러블 스pod을 해소할 것으로 기대됩니다.
-
backup.rake
- 리포지터리 백업은 Gitaly 외부에서 RPC를 사용하여 스트리밍되어 단일 대형 tar 파일에 저장됩니다. 전송되는 데이터의 양 때문에 이러한 백업은 소규모 설치에 제한됩니다. - 스냅샷 - 클라우드 제공업체는 물리적 리포지터리 스냅샷을 촬영하는 것을 허용합니다. 이들은 클라우드 제공자에 특화되어 있기 때문에 Out-of-a-box 솔루션이 아닙니다.
모티베이션
목표
- 리포지터리 백업의 생성 및 복원 시간을 개선합니다.
- 리포지터리 백업 모니터링을 개선합니다.
비목표
- 파일 시스템 기반 스냅샷을 개선하는 것.
파일 시스템 기반 스냅샷
스냅샷은 클라우드 플랫폼이 Gitaly 및 Praefect가 데이터를 저장하는 디스크의 물리적 스냅샷을 촬영할 수 있어야 합니다. 공식적으로 추천되지는 않았지만, 예전 논란이 있었던 backup.rake
를 사용한 백업 생성 또는 복원이 시간이 오래 걸릴 때 주로 사용됩니다.
Gitaly 및 Git은 동시에 발생하는 프로세스와 부분적인 작성으로부터 리포지터리 손상을 방지하기 위해 잠금 파일과 fsync를 사용합니다. 일반적으로 파일이 쓰여지면 유효하게 됩니다. 그러나 Git 리포지터리는 많은 파일로 구성되어 있고 많은 쓰기 작업이 수행되기 때문에 파일 작업이 진행 중이 아닌 동안 스냅샷을 예약하는 것은 불가능합니다. 이는 스냅샷의 일관성을 보장할 수 없게 하며, 스냅샷 백업에서 복원을 매뉴얼으로 개입해야 할 수도 있습니다.
WAL은 충돌 내성을 향상시키고 스냅샷으로부터 자동 복구를 향상시킬 수 있지만, 각 리포지터리는 여전히 동기화된 대부분의 투표 복제본을 필요로 할 것으로 예상됩니다.
지탈리 클러스터의 각 노드는 동질적이지 않으며 복제 요인에 따라 완전한 스냅샷 복원을 위해 모든 노드가 스냅샷을 가져야 합니다. 이는 스냅샷 백업이 많은 리포지터리 데이터 복제를 필요로 한다는 것을 의미합니다.
스냅샷은 클라우드 제공자에 많은 의존이 있으므로 Out-of-a-box 경험을 제공하지 못할 것으로 예상됩니다.
다운타임
이상적인 리포지터리 백업 솔루션은 백업 및 복원 작업을 온라인으로 수행할 수 있어야 합니다. 구체적으로 각 노드/리포지터리가 일관되도록 보장하기 위해 쓰기를 중지하거나 일시 중지하고 싶지 않을 것입니다.
일관성
리포지터리 백업에서의 일관성이란:
- 복원 후 Git 리포지터리가 유효하다는 것을 의미합니다. 부분적으로 적용된 작업이 없습니다.
- 복원 후 모든 클러스터 리포지터리가 건강하거나 자동으로 건강하게 만들어진다는 것을 의미합니다.
일관성이 없는 백업은 데이터 손실을 초래하거나 복원 시 매뉴얼 개입이 필요할 수 있습니다.
스냅샷을 사용하면 이러한 두 가지 일관성을 달성하기 어렵습니다. 이는 여러 호스트의 파일 시스템 스냅샷이 동기적으로 촬영되고 해당 호스트 중 어느 것이라도 리포지터리가 변형되고 있지 않아야 한다는 것을 의미합니다.
작업 분배
백업/복원 작업을 backup.rake
를 실행하는 기계, 단일 Gitaly 노드 또는 단일 네트워크 연결로 병목될 일이 없도록 분배하고 싶습니다.
백업 시, backup.rake
는 모든 리포지터리 백업을 로컬 파일 시스템에 집계합니다. 따라서 모든 리포지터리 데이터를 Gitaly(아마도 Praefect를 통해)에서 Rake 작업이 실행되는 곳으로 스트리밍해야 합니다. 이것이 CNG이라면 Kubernetes에서 큰 볼륨이 필요합니다. 그 결과 생성된 백업 tar 파일은 객채 리포지터리로 전송됩니다. 복원 시에도 비슷한 프로세스가 발생하며, 부분 복원을 위해 리포지터리 일부를 복원할 때에도 전체 tar 파일이 로컬 파일 시스템에 다운로드되고 추출되어야 합니다. 사실상 모든 리포지터리 데이터가 여러 번에 걸쳐 여러 호스트 간에 전송됩니다.
각 Gitaly가 직접 백업을 업로드할 수 있다면 리포지터리 데이터를 한 번만 전송하므로 모든 호스트 수와 전체 데이터 전송량을 줄일 수 있을 것입니다.
지탈리가 제어
지탈리는 자체 백업을 소유할 수 있도록 노력하고 있습니다.
backup.rake
는 현재 백업할 리포지터리와 백업 위치를 결정합니다. 이는 Gitaly가 적용할 수 있는 최적화 유형을 제한하고 개발/테스트 복잡성을 증가시킵니다.
모니터링
backup.rake
는 다양한 환경에서 실행됩니다. 역사적으로 Gitaly의 관점에서 백업은 연결되지 않은 연속적인 RPC 호출로 이루어졌습니다. 이로 인해 백업이 거의 모니터링되지 않았습니다. 이상적으로 프로세스는 기존 메트릭 및 로그 스크래핑을 사용하여 모니터링할 수 있는 Gitaly 내에서 실행되어야 합니다.
자동 백업
backup.rake
가 cron에 설정된 경우, 해당 작업이 성공적으로 실행되었는지, 아직 실행 중인지, 걸린 시간, 사용한 공간의 양 등이 어렵습니다. cron이 이전 백업에 항상 액세스할 수 있도록 하여 점진적 백업을 허용하거나 백업을 업데이트할 필요가 있는지 여부를 결정하는 것이 어렵습니다.
지속적으로 조정 프로세스를 실행하는 것은 각 리포지터리가 사용 패턴과 우선 순위에 따라 자체 백업 일정을 결정할 수 있는 단일 샷 백업 전략에서 이동함으로써, 각 리포지터리가 과도한 부하를 추가하지 않고 상당히 최신의 백업을 갖도록 할 수 있습니다.
변경된 리포지터리에만 업데이트
backup.rake
는 모든 리포지터리 백업을 하나의 tar 파일로 패키징하고 일반적으로 이전 백업에 액세스할 수 없습니다. 이 때문에 리포지터리가 마지막 백업 이후에 변경되었는지 여부를 결정하는 것이 어렵습니다.
객체 리포지터리의 이전 백업에 액세스하는 것은 Gitaly가 더 쉽게 백업이 필요한지를 결정할 수 있게 합니다. 이는 더 이상 수정되지 않는 리포지터리의 백업을 덜 하도록하게 합니다.
특정 시점 복원
특정 시점으로 리포지터리 집합을 복원할 수 있는 메커니즘이 있어야 합니다. 식별자(백업 ID)는 관리자가 결정할 수 있어야 하며 모든 리포지터리에 적용 가능해야 합니다.
WAL (Write Ahead Log)
WAL을 지속적으로 아카이빙할 수 있는 인프라를 제공할 수 있기를 원합니다. 이는 아카이브를 스트리밍할 수 있는 중앙 위치를 제공하고 어떤 완전한 백업을 기록에 특정 지점과 일치시킬 수 있는 방법을 제공해야 합니다. 이로써 리포지터리가 특정 시점까지 온전히 복원되고 WAL이 적용될 수 있게 됩니다.
WORM
Gitaly 접근 가능 스토리지는 기존 백업이 노드의 객체 스토리지 자격 증명에 공격자가 액세스할 경우 수정되지 않도록 WORM(한 번 쓰고 여러 번 읽기)이어야 합니다.
리포지터리 백업에서 현재 사용 중인 포인터 레이아웃은 포인터 파일을 덮어쓸 수 있는 것에 의존하기 때문에 WORM 파일 스토어에서 사용하기에 적합하지 않을 것으로 보입니다.
WORM은 아마존 S3의 객체 잠금, 구글 클라우드의 WORM 유지 정책, MinIO의 객체 잠금과 같이 객체 스토리지 제공자별입니다.
bundle-uri
직접 액세스 백업 데이터를 갖는 것은 bundle-uri를 사용하여 clone/fetch 전송 최적화의 문을 열 수 있습니다. 이를 통해 Git 클라이언트를 리포지터리 자체에서 팩을 전송하는 대신 번들 파일을 직접 가리킬 수 있습니다. 그러면 대량 리포지터리 전송이 더 빨라지고 Gitaly 서버가 아닌 일반 http 서버로 오프로드됩니다.
제안
이 제안은 초기 MVP(Minimum Viable Product)와 리포지터리별 조정자로 구분됩니다.
MVP
MVP의 목표는 서버 측 백업 처리로 이동하여 최악의 경우, 총 손실 시나리오를 개선하는 것을 검증하는 것입니다. 즉, 전체 백업을 생성하고 복원하는 데 걸리는 총 시간을 줄입니다.
MVP는 백업 및 복원 리포지터리 RPC(원격 프로시저 호출)를 도입합니다. 조정 작업자는 없을 것입니다. RPC는 호출된 Gitaly 노드에서 백업을 직접 object storage로 스트리밍합니다. 이러한 RPC는 backup.rake
를 통해 gitaly-backup
도구를 통해 호출될 것입니다. backup.rake
는 더 이상 리포지터리 백업을 백업 아카이브로 패키징하지 않을 것입니다.
이 작업은 이미 진행 중이며 서버 측 백업 MVP epic로 추적됩니다.
리포지터리별 조정자
backup.rake
를 통해 한꺼번에 모든 리포지터리의 백업을 수행하는 대신, 백업 조정 작업자가 생성될 것입니다. 이 작업자는 주기적으로 모든 리포지터리를 열거하여 백업이 필요한지 결정할 것입니다. 이러한 결정은 사용 패턴 또는 리포지터리의 우선순위에 따라 결정될 수 있습니다.
복원 시, 각 리포지터리는 다른 백업 상태를 가질 것이기 때문에 사용자가 타임스탬프를 제공해야 합니다. 이 타임스탬프는 각 리포지터리의 복원할 백업을 결정하는 데 사용될 것입니다. WAL(Write-Ahead Logging) 아카이빙이 구현되면 WAL은 해당 타임스탬프까지 다시 재생될 수 있습니다.
이 더 넓은 노력은 서버 측 백업 epic에서 추적됩니다.
디자인 및 구현 세부 정보
MVP
BackupRepository
와 RestoreRepository
라는 한 쌍의 RPC가 존재할 것입니다. 이러한 RPC는 object storage로 직접 백업을 생성/복원할 것입니다. backup.rake
는 --server-side
플래그를 사용하여 여전히 gitaly-backup
을 사용할 것입니다. 각 Gitaly에는 사용할 object-storage 서비스를 지정하는 백업 구성이 필요할 것입니다.
초기에 object storage의 백업 구조는 기존의 포인터 레이아웃과 동일할 것입니다. MVP의 경우, 백업 ID는 오브젝트 스토리지의 정확한 백업 ID와 일치하여야 합니다.
오브젝트 스토리지의 구성은 새로운 config.backup.go_cloud_url
구성으로 제어됩니다.
Go Cloud Development Kit은 프로바이더별 구성 인증을 시도합니다.
이는 VM 또는 환경 변수에서 추론될 수 있습니다.
지원되는 스토리지 서비스를 참조하세요.