Concurrency limiting
Gitaly를 실행하는 서버의 과부하를 방지하기 위해 다음의 동시성을 제한할 수 있습니다: 이러한 제한은 고정하거나 적응형으로 설정할 수 있습니다. 환경에 대한 제한 활성화는 예상치 못한 트래픽으로부터 보호하는 등 특정 상황에서만 주의하여 수행해야 합니다.
Gitaly를 실행하는 서버의 과부하를 방지하기 위해 다음의 동시성을 제한할 수 있습니다:
- RPC.
- Pack objects.
이러한 제한은 고정하거나 적응형으로 설정할 수 있습니다.
환경에 대한 제한 활성화는 예상치 못한 트래픽으로부터 보호하는 등 특정 상황에서만 주의하여 수행해야 합니다. 제한에 도달하면 사용자에게 부정적인 영향을 미치는 연결 끊김이 발생합니다. 일관되고 안정적인 성능을 위해 먼저 노드 사양 조정이나 대형 저장소 검토 또는 워크로드와 같은 다른 옵션을 탐색해야 합니다.
RPC 동시성 제한#
저장소를 클론하거나 풀할 때 다양한 RPC가 백그라운드에서 실행됩니다. 특히 Git pack RPC는:
SSHUploadPackWithSidechannel(Git SSH용).PostUploadPackWithSidechannel(Git HTTP용).
이러한 RPC는 다음과 같은 상황에서 상당한 영향을 미칠 수 있는 많은 양의 리소스를 소비할 수 있습니다:
- 예상치 못한 높은 트래픽.
- 모범 사례를 따르지 않는 대형 저장소 대상 실행.
Gitaly 구성 파일의 동시성 제한을 사용하여 이러한 시나리오에서 Gitaly 서버가 압도되는 것을 방지할 수 있습니다. 예를 들어:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
concurrency: [
{
rpc: '/gitaly.SmartHTTPService/PostUploadPackWithSidechannel',
max_per_repo: 20,
max_queue_wait: '1s',
max_queue_size: 10,
},
{
rpc: '/gitaly.SSHService/SSHUploadPackWithSidechannel',
max_per_repo: 20,
max_queue_wait: '1s',
max_queue_size: 10,
},
],
}
rpc는 저장소당 동시성 제한을 설정할 RPC의 이름입니다.max_per_repo는 저장소당 주어진 RPC에 대한 최대 진행 중 RPC 호출 수입니다.max_queue_wait는 요청이 Gitaly에 의해 처리되기 전에 동시성 큐에서 대기할 수 있는 최대 시간입니다.max_queue_size는 Gitaly가 요청을 거부하기 전에 동시성 큐(RPC 메서드당)가 증가할 수 있는 최대 크기입니다.
이것은 주어진 RPC에 대한 진행 중 RPC 호출 수를 제한합니다. 제한은 저장소당 적용됩니다. 이전 예제에서:
- Gitaly 서버가 제공하는 각 저장소는 동시에 최대 20개의
PostUploadPackWithSidechannel및SSHUploadPackWithSidechannelRPC 호출을 가질 수 있습니다. - 20개의 슬롯을 모두 사용한 저장소에 다른 요청이 들어오면 해당 요청은 큐에 들어갑니다.
- 요청이 큐에서 1초 이상 기다리면 오류로 거부됩니다.
- 큐가 10을 초과하면 후속 요청은 오류로 거부됩니다.
이러한 제한에 도달하면 사용자가 연결 끊김을 경험합니다.
Gitaly 로그와 Prometheus를 사용하여 이 큐의 동작을 관찰할 수 있습니다. 자세한 내용은 관련 문서를 참조하세요.
인증되지 않은 요청에 대한 별도 제한#
히스토리
- GitLab 18.7에서
gitaly_limit_unauthenticated라는 플래그와 함께 도입되었습니다. 기본적으로 비활성화되어 있습니다.
이 기능의 사용 가능 여부는 기능 플래그에 의해 제어됩니다. 자세한 내용은 기록을 참조하세요. 이 기능은 테스트용으로 제공되지만 프로덕션 사용에는 준비되지 않았습니다.
기본적으로 RPC 동시성 제한은 인증 상태에 관계없이 모든 요청에 적용됩니다. 그러나 익명 트래픽으로 인한 잠재적인 남용 또는 리소스 고갈로부터 Gitaly 서버를 보호하기 위해 인증되지 않은 요청에 대한 별도의 더 제한적인 제한을 구성할 수 있습니다.
RPC에 대해 unauthenticated 필드를 구성하면 Gitaly는 별도의 제한기를 사용합니다:
- 인증된 요청은 주요 동시성 제한(RPC 구성의 최상위 수준에서 구성됨)을 사용합니다.
- 인증되지 않은 요청은
unauthenticated필드에 지정된 제한을 사용합니다.
이 분리를 통해:
- 인증된 사용자의 더 높은 처리량을 유지하면서 인증되지 않은 트래픽에 더 엄격한 제한을 적용할 수 있습니다.
- 익명 클론 또는 풀로 인한 서비스 거부 시나리오를 방지할 수 있습니다.
- 인증된 사용자가 Gitaly 리소스에 우선적으로 액세스할 수 있도록 합니다.
unauthenticated 필드를 구성하지 않으면 모든 요청(인증 및 인증되지 않은 요청 모두)이 동일한 동시성 제한을 공유합니다.
별도의 인증되지 않은 제한을 사용하는 경우#
다음의 경우 별도의 인증되지 않은 제한 구성을 고려하세요:
- GitLab 인스턴스가 공개 저장소 액세스를 허용하고 높은 익명 트래픽을 경험하는 경우.
- 높은 부하 기간에 인증된 사용자에게 우선권을 주고 싶은 경우.
- 인증되지 않은 소스로부터의 잠재적인 남용을 방지해야 하는 경우.
- 인증된 요청과 인증되지 않은 요청 사이에서 리소스 경합을 관찰하는 경우.
인증되지 않은 요청에 대한 정적 제한 구성#
다음 예시는 인증된 요청과 인증되지 않은 요청에 대한 별도의 정적 제한을 구성하는 방법을 보여줍니다:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
concurrency: [
{
rpc: '/gitaly.SmartHTTPService/PostUploadPackWithSidechannel',
# 인증된 요청에 대한 제한
max_per_repo: 20,
max_queue_wait: '1s',
max_queue_size: 10,
# 인증되지 않은 요청에 대한 별도 제한
unauthenticated: {
max_per_repo: 5,
max_queue_wait: '500ms',
max_queue_size: 5,
},
},
],
}
이 예시에서:
- 인증된 요청은 저장소당 최대 20개의 동시 작업을 가질 수 있습니다.
- 인증되지 않은 요청은 저장소당 5개의 동시 작업으로 제한됩니다.
- 인증되지 않은 요청은 더 짧은 큐 대기 시간(500ms vs 1s)과 더 작은 큐(5 vs 10)를 가집니다.
인증되지 않은 요청에 대한 적응형 제한 구성#
unauthenticated 필드는 주요 구성과 마찬가지로 정적 및 적응형 동시성 제한을 모두 지원합니다. 인증되지 않은 요청에 대한 적응형 제한을 구성할 수 있습니다:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
concurrency: [
{
rpc: '/gitaly.SmartHTTPService/PostUploadPackWithSidechannel',
# 인증된 요청에 대한 적응형 제한
adaptive: true,
min_limit: 10,
initial_limit: 20,
max_limit: 40,
max_queue_wait: '1s',
max_queue_size: 10,
# 인증되지 않은 요청에 대한 적응형 제한
unauthenticated: {
adaptive: true,
min_limit: 2,
initial_limit: 5,
max_limit: 10,
max_queue_wait: '500ms',
max_queue_size: 5,
},
},
],
}
이 구성을 통해 인증된 제한과 인증되지 않은 제한이 두 트래픽 유형 간의 분리를 유지하면서 시스템 리소스 사용량에 따라 독립적으로 적응할 수 있습니다.
pack-objects 동시성 제한#
Gitaly는 SSH 및 HTTPS 트래픽 모두를 처리하여 저장소를 클론하거나 풀할 때 git-pack-objects 프로세스를 트리거합니다. 이러한 프로세스는 pack-file을 생성하며 예상치 못한 높은 트래픽이나 대형 저장소에서의 동시 풀과 같은 상황에서 특히 상당한 양의 리소스를 소비할 수 있습니다. GitLab.com에서는 인터넷 연결이 느린 클라이언트와 관련된 문제도 관찰됩니다.
Gitaly 구성 파일에서 pack-objects 동시성 제한을 설정하여 이러한 프로세스가 Gitaly 서버를 압도하는 것을 방지할 수 있습니다. 이 설정은 원격 IP 주소당 진행 중인 pack-object 프로세스 수를 제한합니다.
예상치 못한 트래픽으로부터 보호하는 등 특정 상황에서만 주의하여 환경에서 이러한 제한을 활성화하세요. 제한에 도달하면 사용자가 연결 끊김을 경험합니다. 일관되고 안정적인 성능을 위해 먼저 노드 사양 조정이나 대형 저장소 검토 또는 워크로드와 같은 다른 옵션을 탐색해야 합니다.
구성 예시:
# in /etc/gitlab/gitlab.rb
gitaly['pack_objects_limiting'] = {
'max_concurrency' => 15,
'max_queue_length' => 200,
'max_queue_wait' => '60s',
}
max_concurrency는 키당 최대 진행 중 pack-object 프로세스 수입니다.max_queue_length는 Gitaly가 요청을 거부하기 전에 동시성 큐(키당)가 증가할 수 있는 최대 크기입니다.max_queue_wait는 요청이 Gitaly에 의해 처리되기 전에 동시성 큐에서 대기할 수 있는 최대 시간입니다.
이전 예제에서:
- 각 원격 IP는 Gitaly 노드에서 동시에 최대 15개의 pack-object 프로세스를 가질 수 있습니다.
- 15개의 슬롯을 모두 사용한 IP에서 다른 요청이 들어오면 해당 요청은 큐에 들어갑니다.
- 요청이 큐에서 1분 이상 기다리면 오류로 거부됩니다.
- 큐가 200을 초과하면 후속 요청은 오류로 거부됩니다.
pack-object 캐시가 활성화된 경우 캐시 미스가 발생할 때만 pack-objects 제한이 작동합니다. 자세한 내용은 Pack-objects 캐시를 참조하세요.
Gitaly 로그와 Prometheus를 사용하여 이 큐의 동작을 관찰할 수 있습니다. 자세한 내용은 Gitaly pack-objects 동시성 제한 모니터링을 참조하세요.
동시성 제한 조정#
동시성 제한을 설정할 때 특정 워크로드 패턴에 따라 적절한 값을 선택해야 합니다. 이 섹션은 이러한 제한을 효과적으로 조정하는 방법에 대한 지침을 제공합니다.
조정을 위한 Prometheus 메트릭과 로그 사용#
Prometheus 메트릭은 사용 패턴과 각 RPC 유형이 Gitaly 노드 리소스에 미치는 영향에 대한 정량적 통찰력을 제공합니다. 이 분석에 특히 유용한 몇 가지 주요 메트릭이 있습니다:
- RPC별 리소스 소비 메트릭. Gitaly는 대부분의 무거운 작업을
git프로세스로 오프로드하므로 일반적으로 셸 아웃되는 명령은 Git 바이너리입니다. Gitaly는 이러한 명령에서 수집된 메트릭을 로그 및 Prometheus 메트릭으로 노출합니다.gitaly_command_cpu_seconds_total-grpc_service,grpc_method,cmd,subcmd레이블과 함께 셸 아웃에 소비된 CPU 시간의 합계.gitaly_command_real_seconds_total- 유사한 레이블과 함께 셸 아웃에 소비된 실제 시간의 합계.
- RPC별 최근 제한 메트릭:
gitaly_concurrency_limiting_in_progress- 처리 중인 동시 요청 수.gitaly_concurrency_limiting_queued- 특정 저장소의 RPC에 대해 대기 상태인 요청 수.gitaly_concurrency_limiting_acquiring_seconds- 처리 전 동시성 제한으로 인해 요청이 기다리는 시간.
이러한 메트릭은 특정 시점의 리소스 활용도에 대한 높은 수준의 뷰를 제공합니다. gitaly_command_cpu_seconds_total 메트릭은 상당한 CPU 리소스를 소비하는 특정 RPC를 식별하는 데 특히 효과적입니다. Gitaly 모니터링에 설명된 더 자세한 분석을 위한 추가 메트릭도 있습니다.
메트릭은 전체 리소스 사용 패턴을 캡처하지만 일반적으로 저장소별 분석을 제공하지 않습니다. 따라서 로그는 보완적인 데이터 소스 역할을 합니다. 로그를 분석하려면:
- 식별된 높은 영향 RPC로 로그를 필터링합니다.
- 필터링된 로그를 저장소 또는 프로젝트별로 집계합니다.
- 집계된 결과를 시계열 그래프로 시각화합니다.
메트릭과 로그를 모두 사용하는 이 결합 접근 방식은 시스템 전체 리소스 사용량과 저장소별 패턴에 대한 포괄적인 가시성을 제공합니다. Kibana나 유사한 로그 집계 플랫폼과 같은 분석 도구가 이 프로세스를 용이하게 할 수 있습니다.
제한 조정#
초기 제한이 충분히 효율적이지 않다고 판단되면 조정이 필요할 수 있습니다. 적응형 제한을 사용하면 시스템이 리소스 사용량에 따라 자동으로 조정하므로 정밀한 제한이 덜 중요합니다.
동시성 제한은 저장소별로 범위가 지정된다는 점을 기억하세요. 30의 제한은 저장소당 최대 30개의 동시 진행 중 요청을 허용한다는 의미입니다. 제한에 도달하면 요청이 큐에 들어가고 큐가 가득 차거나 최대 대기 시간에 도달한 경우에만 거부됩니다.
적응형 동시성 제한#
히스토리
- GitLab 16.6에서 도입되었습니다.
Gitaly는 두 가지 동시성 제한을 지원합니다:
- RPC 동시성 제한: 각 Gitaly RPC에 대한 최대 동시 진행 중 요청 수를 구성할 수 있습니다. 제한은 RPC와 저장소로 범위가 지정됩니다.
- Pack-objects 동시성 제한: IP당 동시 Git 데이터 전송 요청 수를 제한합니다.
이 제한이 초과되면:
- 요청이 큐에 들어갑니다.
- 큐가 가득 차거나 요청이 너무 오랫동안 큐에 남아 있으면 요청이 거부됩니다.
이 두 가지 동시성 제한은 정적으로 구성할 수 있습니다. 정적 제한은 좋은 보호 결과를 낼 수 있지만 몇 가지 단점이 있습니다:
- 정적 제한은 모든 사용 패턴에 적합하지 않습니다. 모든 경우에 맞는 단일 값이 없습니다. 제한이 너무 낮으면 대형 저장소가 부정적인 영향을 받습니다. 제한이 너무 높으면 보호가 사실상 의미가 없어집니다.
- 특히 각 저장소의 워크로드가 시간이 지남에 따라 변할 때 동시성 제한에 대한 적절한 값을 유지하는 것은 번거롭습니다.
- 서버가 유휴 상태임에도 불구하고 요청이 거부될 수 있습니다. 비율이 서버의 부하를 고려하지 않기 때문입니다.
적응형 동시성 제한을 구성하여 이러한 단점을 모두 극복하고 동시성 제한의 이점을 유지할 수 있습니다. 적응형 동시성 제한은 선택 사항이며 두 가지 동시성 제한 유형을 기반으로 합니다. AIMD(Additive Increase/Multiplicative Decrease) 알고리즘을 사용합니다. 각 적응형 제한은:
- 일반적인 프로세스 기능 중에 특정 상한선까지 점진적으로 증가합니다.
- 호스트 시스템에 리소스 문제가 있을 때 빠르게 감소합니다.
이 메커니즘은 기계가 "숨쉴" 공간을 제공하고 현재 진행 중인 요청을 가속화합니다.

적응형 제한기는 30초마다 제한을 조정하며:
- 상한에 도달할 때까지 제한을 하나씩 증가시킵니다.
- 최상위 cgroup의 메모리 사용량이 높은 퇴출 가능 페이지 캐시를 제외하고 90%를 초과하거나 관찰 시간의 50% 이상 CPU가 스로틀되는 경우 제한을 절반으로 감소시킵니다.
그렇지 않으면 제한이 상한에 도달할 때까지 하나씩 증가합니다.
적응형 제한은 각 RPC 또는 pack-objects 캐시에 대해 개별적으로 활성화됩니다. 그러나 제한은 동시에 조정됩니다. 적응형 제한의 구성은 다음과 같습니다:
adaptive는 적응성 활성화 여부를 설정합니다.max_limit는 최대 동시성 제한입니다. Gitaly는 이 숫자에 도달할 때까지 현재 제한을 증가시킵니다. 이는 일반적인 조건에서 시스템이 완전히 지원할 수 있는 넉넉한 값이어야 합니다.min_limit는 구성된 RPC의 최소 동시성 제한입니다. 호스트 시스템에 리소스 문제가 있을 때 Gitaly는 이 값에 도달할 때까지 제한을 빠르게 줄입니다.min_limit를 0으로 설정하면 처리가 완전히 중단될 수 있으므로 일반적으로 바람직하지 않습니다.initial_limit는 이러한 극단값 사이의 합리적인 시작점을 제공합니다.
RPC 동시성에 대한 적응성 활성화#
사전 조건:
- 적응형 제한은 컨트롤 그룹에 의존하므로 적응형 제한을 사용하기 전에 컨트롤 그룹이 활성화되어 있어야 합니다.
다음은 RPC 동시성에 대한 적응형 제한을 구성하는 예시입니다:
# in /etc/gitlab/gitlab.rb
gitaly['configuration'] = {
# ...
cgroups: {
# cgroups 지원을 활성화하는 데 필요한 최소 구성.
repositories: {
count: 1
},
},
concurrency: [
{
rpc: '/gitaly.SmartHTTPService/PostUploadPackWithSidechannel',
max_queue_wait: '1s',
max_queue_size: 10,
adaptive: true,
min_limit: 10,
initial_limit: 20,
max_limit: 40
},
{
rpc: '/gitaly.SSHService/SSHUploadPackWithSidechannel',
max_queue_wait: '10s',
max_queue_size: 20,
adaptive: true,
min_limit: 10,
initial_limit: 50,
max_limit: 100
},
],
}
자세한 내용은 RPC 동시성을 참조하세요.
pack-objects 동시성에 대한 적응성 활성화#
사전 조건:
- 적응형 제한은 컨트롤 그룹에 의존하므로 적응형 제한을 사용하기 전에 컨트롤 그룹이 활성화되어 있어야 합니다.
다음은 pack-objects 동시성에 대한 적응형 제한을 구성하는 예시입니다:
# in /etc/gitlab/gitlab.rb
gitaly['pack_objects_limiting'] = {
'max_queue_length' => 200,
'max_queue_wait' => '60s',
'adaptive' => true,
'min_limit' => 10,
'initial_limit' => 20,
'max_limit' => 40
}
자세한 내용은 pack-objects 동시성을 참조하세요.
적응형 동시성 제한 조정#
적응형 동시성 제한은 GitLab이 Gitaly 리소스를 보호하는 일반적인 방식과 매우 다릅니다. 너무 제한적이거나 너무 허용적일 수 있는 정적 임계값에 의존하는 대신, 적응형 제한은 실제 리소스 조건에 지능적으로 실시간으로 반응합니다.
이 접근 방식은 동시성 제한 조정에 설명된 것처럼 광범위한 조정을 통해 "완벽한" 임계값을 찾을 필요성을 없애줍니다. 장애 시나리오 중에 적응형 제한기는 제한을 기하급수적으로 줄이고(예: 60 → 30 → 15 → 10) 시스템이 안정화되면 제한을 점진적으로 올려 자동으로 복구됩니다.
적응형 제한을 조정할 때 정밀도보다 유연성을 우선시할 수 있습니다.
RPC 범주 및 구성 예시#
보호해야 하는 비싼 Gitaly RPC는 두 가지 일반적인 유형으로 분류할 수 있습니다:
- 순수 Git 데이터 작업.
- 시간에 민감한 RPC.
각 유형은 동시성 제한을 구성하는 방법에 영향을 미치는 고유한 특성이 있습니다. 다음 예시는 제한 구성 뒤의 이유를 설명합니다. 시작점으로도 사용할 수 있습니다.
순수 Git 데이터 작업#
이러한 RPC는 Git pull, push, fetch 작업을 포함하며 다음과 같은 특성이 있습니다:
- 장기 실행 프로세스.
- 상당한 리소스 활용.
- 계산 비용이 많이 드는 작업.
- 시간에 민감하지 않음. 추가적인 지연은 일반적으로 허용 가능.
SmartHTTPService와 SSHService의 RPC는 순수 Git 데이터 작업 범주에 속합니다. 구성 예시:
{
rpc: "/gitaly.SmartHTTPService/PostUploadPackWithSidechannel", # 또는 `/gitaly.SmartHTTPService/SSHUploadPackWithSidechannel`
adaptive: true,
min_limit: 10, # 극도의 부하에서도 유지할 최소 동시성
initial_limit: 40, # 서비스 초기화 시 시작 동시성
max_limit: 60, # 이상적인 조건에서의 최대 동시성
max_queue_wait: "60s",
max_queue_size: 300
}
시간에 민감한 RPC#
이러한 RPC는 다양한 특성을 가진 GitLab 자체 및 다른 클라이언트에 서비스를 제공합니다:
- 일반적으로 온라인 HTTP 요청 또는 Sidekiq 백그라운드 작업의 일부.
- 더 짧은 지연 프로파일.
- 일반적으로 리소스 집약도가 낮음.
이러한 RPC의 경우, GitLab의 타임아웃 구성이 max_queue_wait 매개변수를 결정해야 합니다. 예를 들어, get_tree_entries는 일반적으로 GitLab에서 30초의 중간 타임아웃을 가집니다:
{
rpc: "/gitaly.CommitService/GetTreeEntries",
adaptive: true,
min_limit: 5, # 리소스 압박 하에서 유지되는 최소 처리량
initial_limit: 10, # 초기 동시성 설정
max_limit: 20, # 최적 조건에서의 최대 동시성
max_queue_size: 50,
max_queue_wait: "30s"
}
적응형 제한 모니터링#
프로덕션 환경에서 적응형 제한이 어떻게 작동하는지 관찰하려면 Gitaly 적응형 동시성 제한 모니터링에 설명된 모니터링 도구와 메트릭을 참조하세요. 적응형 제한 동작을 관찰하면 제한이 리소스 압박에 적절히 반응하고 예상대로 조정되는지 확인하는 데 도움이 됩니다.
