병렬성 제한

Gitaly의 서버를 압도하지 않기 위해 병렬성을 제한할 수 있습니다. 다음과 같은 병렬성을 제한할 수 있습니다.

  • RPCs.
  • 팩 오브젝트.

이러한 제한은 고정될 수도 있고 적응적으로 설정될 수도 있습니다.

경고: 환경에 제한을 활성화하는 것은 조심히 하고 예상치 못한 트래픽에 대비하는 등의 특정한 상황에서만 해야 합니다. 제한에 도달하면 사용자에게 부정적인 영향을 미치는 연결 해제가 발생합니다. 일관된 안정적인 성능을 위해 먼저 노드 사양을 조정하거나 대형 저장소나 작업을 검토해야 합니다.

RPC 병렬성 제한

저장소를 복제하거나 가져올 때 여러 개의 RPC가 백그라운드에서 실행됩니다. 특히, Git 팩 RPC들:

  • SSHUploadPackWithSidechannel (Git SSH용).
  • PostUploadPackWithSidechannel (Git HTTP용).

유감스러운 높은 트래픽이나 최선의 방법을 따르지 않는 대형 저장소에서 실행하는 경우와 같이 많은 리소스를 소비할 수 있습니다.

이러한 시나리오에서 이들 프로세스가 Gitaly 서버를 압도하는 것을 방지하기 위해 Gitaly 구성 파일에서 병렬성 제한을 사용할 수 있습니다. 예를 들면:

# /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개의 동시 PostUploadPackWithSidechannelSSHUploadPackWithSidechannel RPC 호출을 가질 수 있습니다.
  • 20개의 슬롯을 모두 사용한 저장소에 대한 추가 요청은 대기열에 들어갑니다.
  • 대기열에서 요청이 1초 이상 기다리면 오류가 발생합니다.
  • 대기열이 10개보다 커지면 후속 요청이 오류와 함께 거부됩니다.

참고: 이러한 제한에 도달하면 사용자가 연결이 해제됩니다.

이러한 대기열의 동작은 Gitaly 로그와 Prometheus를 사용하여 확인할 수 있습니다. 자세한 내용은 해당 문서를 참조하세요.

팩 오브젝트 병렬성 제한

  • GitLab 15.11에서 gitaly_pack_objects_limiting_remote_ip라는 플래그로 도입됨. 기본 설정은 비활성화됨.
  • GitLab 16.0에서 일반적으로 사용 가능함. gitaly_pack_objects_limiting_remote_ip 플래그가 삭제됨.

Gitaly는 SSH 및 HTTPS 트래픽을 처리할 때 git-pack-objects 프로세스를 트리거합니다. 이러한 프로세스는 pack-file을 생성하고 많은 리소스를 소비할 수 있습니다. 특히, 예상치 못한 높은 트래픽이나 대형 저장소에서 동시에 가져올 때 문제가 발생할 수 있습니다. GitLab.com에서는 느린 인터넷 연결을 가진 클라이언트로 인한 문제도 관찰되고 있습니다.

이러한 프로세스가 Gitaly 서버를 압도하지 못하도록 Gitaly 구성 파일에서 팩 오브젝트 병렬성 제한을 설정할 수 있습니다. 이 설정은 원격 IP 주소별로 동시에 진행 중인 팩 오브젝트 프로세스의 수를 제한합니다.

경고: 이러한 제한을 예상치 못한 트래픽에 대비하는 등 특정한 상황에서만 활성화해야 합니다. 제한에 도달하면 사용자가 연결이 해제됩니다. 일관된 안정적인 성능을 위해 먼저 노드 사양을 조정하거나 대형 저장소나 작업을 검토해야 합니다.

예제 구성:

# /etc/gitlab/gitlab.rb에 작성
gitaly['pack_objects_limiting'] = {
   'max_concurrency' => 15,
   'max_queue_length' => 200,
   'max_queue_wait' => '60s',
}
  • max_concurrency는 각 원격 IP당 동시 팩 오브젝트 프로세스의 최대 수입니다.
  • max_queue_length는 Gitaly에서 요청이 거부되기 전에 큐(각 키당)가 증가할 수 있는 최대 크기입니다.
  • max_queue_wait은 요청이 Gitaly에서 처리되기 전 병렬성 대기열에서 대기할 수 있는 최대 시간입니다.

위의 예제에서:

  • 각 원격 IP 주소는 Gitaly 노드에서 최대 15개의 동시 팩 오브젝트 프로세스를 가질 수 있습니다.
  • 15개의 슬롯을 모두 사용한 IP로부터의 추가 요청은 대기열에 들어갑니다.
  • 대기열에서 요청이 1분 이상 기다리면 오류가 발생합니다.
  • 대기열이 200개보다 커지면 후속 요청이 오류와 함께 거부됩니다.

팩 오브젝트 캐시가 활성화된 경우, 팩 오브젝트 제한은 캐시가 빠진 경우에만 발동합니다. 자세한 내용은 팩 오브젝트 캐시를 참조하세요.

이러한 대기열의 동작은 Gitaly 로그와 Prometheus를 사용하여 확인할 수 있습니다. 자세한 내용은 Monitor Gitaly pack-objects concurrency limiting를 참조하세요.

적응적 병렬성 제한

Gitaly는 두 가지 병렬성 제한을 지원합니다.

이러한 제한을 초과하면:

  • 요청이 대기열에 들어갑니다.
  • 대기열이 가득 차거나 요청이 너무 오랫동안 대기하면 요청이 거부됩니다.

이러한 병렬성 제한은 정적으로 구성될 수 있습니다. 정적 제한은 좋은 보호 결과를 보여줄 수 있지만 몇 가지 단점이 있습니다:

  • 정적 제한은 모든 사용 패턴에 적합하지 않습니다. 일관된 값이 없습니다. 제한이 너무 낮으면 큰 저장소에 부정적인 영향을 미칩니다. 제한이 너무 높으면 보호가 사실상 상실됩니다.
  • 각 저장소의 작업 부하가 시간이 지남에 따라 변경될 때 병렬성 제한에 대해 합리적인 값을 유지하는 것이 번거롭습니다.
  • 서버 부하를 고려하지 않고 요청을 거부할 수 있습니다.

모든 이러한 단점을 극복하고 병렬성 제한의 이점을 유지하면서 적응적 병렬성 제한을 구성하여 이 모든 단점을 극복할 수 있습니다. 적응적 병렬성 제한은 선택 사항이며 두 병렬성 제한 유형을 기반으로 작동합니다. 이는 증가 체계적/감소 체계적(Additive Increase/Multiplicative Decrease, AIMD) 알고리즘을 사용합니다. 각 적응적 제한:

  • 일반적인 프로세스 기능 중 상한선에 도달할 때까지 점진적으로 증가합니다.
  • 호스트 컴퓨터에 리소스 문제가 발생할 때 신속히 감소합니다.

이 메커니즘은 기계에 “쉬어” 기회를 제공하고 현재 진행 중인 요청을 가속화합니다.

Gitaly Adaptive Concurrency Limit

적응적 제한자는 매 30초마다 제한을 보정하고:

  • 상한에 도달할 때까지 한 번씩 증가합니다.
  • 최상위 cgroup에 메모리 사용량이 90%를 초과하는 경우 (대부분적으로 배출 가능한 페이지 캐시는 제외) 또는 관찰 시간의 50% 이상이 CPU가 스로틀링될 경우 제한을 반으로 줄입니다.

그렇지 않은 경우 상한에 도달할 때까지 계속해서 제한을 증가시킵니다. 이 시스템의 기술적 구현에 대한 자세한 내용은 관련 설계 문서를 참조하세요.

적응적 제한은 RPC별 또는 팩-오브젝트 캐시마다 활성화됩니다. 그러나 제한은 동시에 보정됩니다.

RPC 동시성에 대한 적응성 활성화

필수 조건:

  • 적응 제한은 컨트롤 그룹에 의존하기 때문에 적응 제한을 사용하기 전에 컨트롤 그룹을 활성화해야 합니다.

다음은 RPC 동시성을 구성하는 예시입니다:

# /etc/gitlab/gitlab.rb에 추가
gitaly['configuration'] = {
    # ...
    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
        },
   ],
}

이 예시에서:

  • adaptive는 적응성을 활성화할지 여부를 설정합니다. 설정하면 max_per_repo 값 대신 다음 구성을 우선합니다.
  • initial_limit은 Gitaly 시작 시 사용할 저장소당 동시성 제한입니다.
  • max_limit은 구성된 RPC의 저장소당 최소 동시성 제한입니다. Gitaly는 현재 제한을 증가시켜 이 번호에 도달할 때까지 증가시킵니다.
  • min_limit은 구성된 RPC의 최소 저장소 당 동시성 제한입니다. 호스트 머신에 리소스 문제가 발생하면 Gitaly는 이 값에 도달할 때까지 제한을 빨리 줄입니다.

더 많은 정보는 RPC 동시성을 참조하십시오.

pack-objects 동시성에 대한 적응성 활성화

필수 조건:

  • 적응 제한은 컨트롤 그룹에 의존하기 때문에 적응 제한을 사용하기 전에 컨트롤 그룹을 활성화해야 합니다.

다음은 pack-objects 동시성을 구성하는 예시입니다:

# /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
}

이 예시에서:

  • adaptive는 적응성을 활성화할지 여부를 설정합니다. 설정하면 max_concurrency 값을 무시하고 다음 구성을 우선합니다.
  • initial_limit은 Gitaly 시작 시 사용할 IP 당 동시성 제한입니다.
  • max_limit은 pack-objects의 최소 IP 당 동시성 제한입니다. Gitaly는 현재 제한을 증가시켜 이 번호에 도달할 때까지 증가시킵니다.
  • min_limit은 pack-objects의 최소 IP 당 동시성 제한입니다. 호스트 머신에 리소스 문제가 발생하면 Gitaly는 이 값에 도달할 때까지 제한을 빨리 줄입니다.

더 많은 정보는 pack-objects 동시성을 참조하십시오.