markdown # 동시성 제한

Gitaly를 실행하는 서버를 과부하로부터 보호하기 위해 다음의 제한 동시성을 설정할 수 있습니다:

  • RPCs.
  • Pack objects.

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

caution
환경에서 제한을 활성화하는 것은 신중히 하고 예상치 못한 트래픽으로부터 보호하기 위한 선택 사항일 때에만 수행되어야 합니다. 제한에 도달하게 되면 사용자에게 부정적인 영향을 미치는 연결 끊김이 발생합니다. 일관된 안정적인 성능을 위해, 먼저 다른 옵션을 탐색하고 노드 사양을 조정하며 대형 리포지터리나 워크로드를 검토해야 합니다.

RPC 동시성 제한

리포지터리를 복제하거나 가져올 때, 여러 RPC들이 백그라운드에서 실행됩니다. 특히, Git 팩 RPC들:

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

이러한 RPC들은 많은 리소스를 소비할 수 있으며, 다음과 같은 상황에서는 중대한 영향을 미치게 됩니다:

이러한 시나리오에서 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 호출의 동시 처리량을 제한할 수 있습니다. 이러한 제한은 리포지터리별로 적용됩니다. 위의 예에서:

  • Gitaly 서버에서 제공하는 각 리포지터리는 최대 20개의 동시 PostUploadPackWithSidechannelSSHUploadPackWithSidechannel RPC 호출을 가질 수 있습니다.
  • 20개의 슬롯을 모두 사용한 리포지터리에 대해 추가 요청이 들어오는 경우, 해당 요청은 대기열로 이동됩니다.
  • 대기열에서 요청이 1초 이상 대기하게 되면 오류로 거부됩니다.
  • 대기열이 10개를 초과하는 경우, 후속 요청은 오류로 거부됩니다.
note
이러한 한도에 도달하게 되면 사용자가 연결이 끊깁니다.

Gitaly 로그와 Prometheus를 사용하여 이 대기열의 동작을 관찰할 수 있습니다. 자세한 내용은 관련 문서를 참조하십시오.

팩 개체 동시성 제한

Gitaly는 SSH 및 HTTPS로 리포지터리를 복제하거나 가져올 때 git-pack-objects 프로세스를 트리거합니다. 이러한 프로세스는 팩-파일을 생성하며, 예상치 못한 고트래픽이나 대형 리포지터리로부터의 동시 복제 요청과 같은 상황에서 많은 리소스를 소비할 수 있습니다. GitLab.com에서는 또한 네트워크 속도가 느린 클라이언트로 인한 문제를 관찰할 수 있습니다.

백그라운드에서 실행되는 이러한 프로세스가 Gitaly 서버를 과부하로부터 보호하기 위해 Gitaly 구성 파일에서 pack-objects 동시성 제한을 설정하여 이러한 프로세스의 동시 처리량을 제한할 수 있습니다.

caution
예상치 못한 트래픽으로부터 보호하기 위한 선택 사항일 때에만, 이러한 제한을 환경에서 활성화해야 합니다. 제한에 도달하게 되면 사용자가 연결이 끊깁니다. 일관된 안정적인 성능을 위해, 먼저 다른 옵션을 탐색하고 대형 리포지터리나 워크로드를 검토해야 합니다.

예제 구성:

# in /etc/gitlab/gitlab.rb
gitaly['pack_objects_limiting'] = {
   'max_concurrency' => 15,
   'max_queue_length' => 200,
   'max_queue_wait' => '60s',
}
  • max_concurrency는 각 리모트 IP 주소당 동시에 진행되는 pack-object 프로세스의 최대 수입니다.
  • max_queue_length는 대기열(각 키당)이 요청을 거부하기 전에 확장될 수 있는 최대 크기입니다.
  • max_queue_wait는 요청이 Gitaly에 의해 처리되기 전에 대기할 수 있는 최대 시간입니다.

위의 예에서:

  • 각 리모트 IP 주소당 Gitaly 노드에서 최대 15개의 동시 pack-object 프로세스가 진행될 수 있습니다.
  • 15개의 슬롯을 모두 사용한 IP에서 추가 요청이 들어오는 경우, 해당 요청은 대기열로 이동됩니다.
  • 대기열에서 요청이 1분을 초과하여 대기하게 되면 오류로 거부됩니다.
  • 대기열이 200을 초과하는 경우, 후속 요청은 오류로 거부됩니다.

pack objects 캐시가 활성화된 경우, pack objects 제한은 캐시가 빠진 경우에만 발생합니다. 자세한 내용은 pack objects 캐시를 참조하십시오.

Gitaly 로그와 Prometheus를 사용하여 이 대기열의 동작을 관찰할 수 있습니다. 자세한 내용은 Pack-objects 동시성 제한을 참조하십시오.

적응형 동시성 제한

Gitaly는 두 가지 동시성 제한을 지원합니다:

  • RPC 동시성 제한, 각 Gitaly RPC에 대해 동시에 진행되는 요청의 최대 수를 구성할 수 있게 합니다. 이 제한은 RPC 및 리포지터리별로 적용됩니다.
  • 팩-객체 동시성 제한, IP별로 동시 Git 데이터 전송 요청 수를 제한합니다.

이러한 제한을 초과하는 경우:

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

이러한 모든 동시성 제한은 정적으로 구성될 수 있습니다. 정적 제한은 좋은 보호 결과를 낼 수 있지만 몇 가지 단점이 있습니다:

  • 정적 제한은 모든 사용 패턴에 적합하지 않습니다. 일반적인 값은 없습니다. 제한이 너무 낮으면 대형 리포지터리에 부정적인 영향을 미치게 됩니다. 제한이 너무 높으면 보호가 사실상 사라집니다.
  • 각 리포지터리의 워크로드가 시간이 지남에 따라 변경될 때, 동시성 제한의 합리적인 값을 유지하는 것이 까다로울 수 있습니다.
  • 서버의 부하를 계산하지 않은 요청이 거부될 수 있습니다.

모든 이러한 단점을 극복하고 동시성 제한의 이점을 유지하는 것은 적응형 동시성 제한을 구성함으로써 가능합니다. 적응형 동시성 제한은 선택 사항이며 두 가지 동시성 제한 유형을 기반으로 작동합니다. 추가 증가/곱셈 감소(AIMD) 알고리즘을 사용합니다. 각 적응형 제한은:

  • 일반적인 프로세스 기능 중에 특정 상한선까지 점진적으로 증가합니다.
  • 호스트 머신이 리소스 문제를 가질 때 빠르게 감소합니다.

본 메커니즘은 기계에 “호흡을 할 수 있는” 여유를 제공하고 현재 진행 중인 요청을 가속화시킵니다.

적응형 제한은 각 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 동시성을 참조하세요.