Geo 저장소 동기화
저장소 복제(동기화 또는 sync라고도 함)는 기본 사이트에서 보조 사이트로 Git 저장소를 복제하는 핵심 Geo 기능입니다. Geo::ProjectRepositoryRegistry 클래스는 보조 사이트에서 저장소 복제 상태를 추적하는 데 사용되는 모델을 정의합니다.
저장소 복제(동기화 또는 sync라고도 함)는 기본 사이트에서 보조 사이트로 Git 저장소를 복제하는 핵심 Geo 기능입니다. 이를 통해 보조 사이트가 모든 저장소의 최신 복사본을 유지하여 재해 복구와 Git 데이터의 지리적 분산이 가능합니다.
Geo::ProjectRepositoryRegistry 클래스는 보조 사이트에서 저장소 복제 상태를 추적하는 데 사용되는 모델을 정의합니다. 주요(기본) 데이터베이스의 각 프로젝트에 대해 추적 데이터베이스에 하나의 레코드가 유지됩니다.
저장소에 대해 다음을 기록합니다:
- 마지막으로 동기화된 시간.
- 마지막으로 성공적으로 동기화된 시간.
- 재동기화가 필요한지 여부.
- 재시도 시도 시간.
- 재시도 횟수.
- 검증 여부 및 시간.
동기화 트리거#
저장소 동기화는 다양한 메커니즘을 통해 트리거될 수 있습니다.
소스 코드 보기
flowchart TD
A(["Start"])
A --> B{"What triggers the repository sync?"}
B --> C["Resync from the admin interface"]
B --> D["An update event on the repository (for example, git push)"]
B --> E["Cron worker periodic sync"]
B --> F["Rails console sync: \n 'replicator.sync'"]
C --> G["Geo::EventWorker"]
D --> G
E --> H["Geo::SyncWorker"]
F --> I["Geo::FrameworkRepositorySyncService.execute"]
H --> I
G --> I이 트리거들은 두 가지 범주로 요약됩니다: 백그라운드 동기화와 이벤트 기반 동기화.
백그라운드 동기화#
모든 저장소가 동기화되도록 보장하기 위해, Geo::RepositoryRegistrySyncWorker가 보조 사이트에서 주기적으로 백그라운드에서 실행됩니다. 구체적으로 이 워커는:
- 동기화가 필요한 레지스트리에 대해 추적 데이터베이스를 쿼리합니다. 다음과 같을 수 있습니다:
- 동기화되지 않음: 보조 사이트에서 한 번도 동기화되지 않아 아직 존재하지 않는 프로젝트.
- 최근 업데이트됨:
Geo::ProjectRepositoryRegistry모델의last_repository_successful_sync_at타임스탬프보다 최근의last_repository_updated_at타임스탬프를 가진 프로젝트. - 수동으로 재동기화됨: 관리자가 Geo 관리자 영역에서 저장소를 재동기화하도록 수동으로 플래그를 지정할 수 있습니다.
- 업데이트가 필요한 각 저장소에 대해
Geo::SyncWorker잡을 큐에 넣습니다. - 모든 저장소에 대한 기준 동기화를 제공합니다.
이벤트 기반 동기화#
이벤트 기반 동기화는 기본 사이트의 저장소 업데이트에 의해 트리거됩니다. 저장소가 업데이트되면 이 특정 저장소 업데이트에 대해 Geo 이벤트 테이블에 새 레코드가 생성됩니다. 보조 사이트에서 실행되는 Geo Log Cursor 데몬이 이벤트를 가져와 Geo::EventService를 실행하는 Geo::EventWorker 잡을 예약합니다. 이 서비스는:
- 저장소 복제기를 찾아
consume(event)메서드를 실행합니다. - 경쟁 조건을 방지하기 위해 동기화 시도 전에 레지스트리 상태를
pending으로 변경합니다 - 최신 변경 사항이 보조 사이트로 빠르게 복제되도록 합니다
시퀀스 다이어그램#
다음 다이어그램은 저장소 동기화가 시스템을 통해 흐르는 방식을 보여줍니다. 두 경로는 동일한 방식으로 끝나기 때문에 동일한 다이어그램에 표시됩니다:
소스 코드 보기
sequenceDiagram
participant Worker as Geo::EventWorker
participant Service as Geo::EventService
participant Scheduler as Geo::RepositoryRegistrySyncWorker
participant SyncWorker as Geo::SyncWorker
participant SyncService as Geo::SyncService
participant Replicator as Geo::ProjectRepositoryReplicator
participant Registry as Geo::ProjectRepositoryRegistry
participant FRSS as Geo::FrameworkRepositorySyncService
participant Primary as Primary Site
Note over Worker,Replicator: Event-driven sync path
Worker->>Service: new(replicable_name, event_name, payload)
Service->>Replicator: new(model_record_id: payload[:model_record_id])
Replicator-->>Service: Geo:ProjectRepositoryReplicator
Service->>Replicator: consume(event_name, **payload)
Replicator->>Registry: find_or_initialize_by(model_foreign_key => model_record_id)
Registry-->>Replicator: Geo::ProjectRepositoryRegistry
Replicator->>Registry: pending!
Registry-->>Replicator: true
Note over Scheduler,Replicator: Background sync path
Scheduler->>SyncWorker: enqueues
SyncWorker->>SyncService: new(replicable_name, model_record_id)
SyncService->>Replicator: new(model_record_id: payload[:model_record_id])
Replicator-->>SyncService: Geo:ProjectRepositoryReplicator
SyncService->>Replicator: sync
Note over Replicator, Primary: Common path
Replicator->>FRSS: execute
FRSS->>Replicator: registry
Replicator->>Registry: find_or_initialize_by(model_foreign_key => model_record_id)
Registry-->>Replicator: Geo::ProjectRepositoryRegistry
Replicator-->>FRSS: Geo::ProjectRepositoryRegistry
FRSS->>Registry: started!
FRSS->>Primary: Fetch repository
Primary->>FRSS: Repository data
FRSS->>Registry: synced!</code></pre></details></div>
배타적 임대 메커니즘#
배타적 임대 메커니즘은 동일한 저장소에서 동시 동기화 작업을 방지하는 중요한 구성 요소입니다. 임대는 Geo::FrameworkRepositorySyncService가 실행될 때 획득됩니다.
그 목적은:
- 여러 동기화 잡이 동일한 저장소를 동시에 업데이트하려고 할 때 경쟁 조건을 방지합니다.
- 각 저장소에 대한 동기화 작업을 직렬화하여 데이터 일관성을 보장합니다.
- 중복된 이벤트 워커와
pending 상태에 멈춘 동기화로 인한 불필요한 부하를 방지합니다.
임대 타임아웃은 3시간입니다. 임대 키 형식은 geo_sync_ssf_service:{replicable_name}:{model_record_id}입니다.
동기화 작업 중 동작#
동기화 작업이 시작될 때:
- 서비스가 저장소에 대한 배타적 임대 획득을 시도합니다
- 다른 프로세스가 이미 임대를 보유하고 있는 경우:
- 동기화는 로그 메시지 "Cannot obtain an exclusive lease"와 함께 조기에 종료됩니다.
- 동기화 작업이 수행되지 않습니다.
- 잡은 나중에 재시도됩니다.
- 임대가 획득된 경우:
- 동기화 작업이 진행됩니다.
- 동기화 완료 후
ensure 블록에서 임대가 해제됩니다.
Mermaid 다이어그램 (18줄)소스 코드 보기
sequenceDiagram
participant FRSS as FrameworkRepositorySyncService
participant Redis as Redis (Lease Store)
participant Primary as Primary Site
FRSS->>Redis: Try obtain lease<br/>(geo_sync_ssf_service:type:id, TTL=8h)
alt Lease obtained
Redis-->>FRSS: Lease granted
FRSS->>FRSS: Change state to started
FRSS->>Primary: Fetch repository
Primary-->>FRSS: Repository data
FRSS->>FRSS: Change state to synced
FRSS->>Redis: Cancel lease
else Lease taken
Redis-->>FRSS: Lease denied
Note over FRSS: Sync skipped
end</code></pre></details></div>
고아 임대 키#
고아 임대 키는 동기화 프로세스가 비정상적으로 종료될 때(예: SIGKILL 또는 프로세스 충돌) 발생할 수 있으며, 이는 프로세스가 ensure 블록이 임대를 해제하기 전에 종료됨을 의미합니다. 임대 키가 고아가 되면 해당 저장소에 대한 후속 동기화 시도는 최대 3시간 동안(임대가 만료될 때까지) 차단됩니다.
이 문제를 완화하기 위해 몇 가지 옵션이 있습니다:
- 자동 만료: 고아 임대는 3시간 후에 자동으로 만료됩니다.
- 모니터링:
geo.log에서 "Cannot obtain an exclusive lease" 메시지와 영향을 받는 잠재적 저장소를 식별하기 위한 lease_key의 geo_sync_ssf_service:{replicable_name}:{model_record_id} 값의 증가를 확인합니다.
- 수동 해제: 최후의 수단으로, Rails 콘솔을 통해 수동으로 고아 임대를 해제할 수 있습니다(문제 해결 참조)
관련 주제#
- Geo 셀프 서비스 프레임워크 - Geo 복제 프레임워크 개요
- 동기화 및 검증 문제 해결 - 고아 임대 키 해결을 포함한 문제 해결 가이드
- 이슈 #552408 - 고아 임대 키 문제를 문서화한 원래 이슈
