동시성 제한

Gitaly를 실행하는 서버를 과부하로부터 보호하기 위해 다음과 같은 작업의 동시성을 제한할 수 있습니다.

  • RPCs.
  • Pack 객체.

이러한 제한은 고정되어 있을 수도 있고, 적응적으로 설정할 수도 있습니다.

caution
환경에서 제한을 활성화하는 것은 신중히 하며 단순히 예기치 않은 트래픽에 대비하기 위한 경우와 같이 특정한 상황에서만 해야 합니다. 제한이 도달되면 사용자에게 부정적인 영향을 미치는 연결 끊김이 발생합니다. 일관된 안정적인 성능을 위해 먼저 노드 사양을 조정하고, 대형 리포지터리나 워크로드를 검토하는 등 다른 옵션을 먼저 살펴보는 것이 좋습니다.

RPC 동시성 제한

리포지터리를 복제하거나 풀링할 때 여러 가지 RPCs가 백그라운드에서 실행됩니다. 특히 Git pack RPCs는 다음과 같습니다.

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

이러한 RPCs는 상당량의 리소스를 소비할 수 있으며, 특히 다음과 같은 상황에서 상당한 영향을 미칠 수 있습니다.

이러한 시나리오에서 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는 대기열(각 RPC 방법당)이 Gitaly에 의해 거부되기 전에 성장할 수 있는 최대 크기입니다.

이러한 제한은 주어진 RPCs의 대기 중 RPC 호출 수를 제한합니다. 이 제한은 리포지터리당 적용됩니다. 위 예시에서:

  • Gitaly 서버에서 제공하는 각 리포지터리마다 최대 20개의 동시 PostUploadPackWithSidechannelSSHUploadPackWithSidechannel RPC 호출이 허용됩니다.
  • 다른 리포지터리의 요청이 20개의 슬롯을 모두 사용한 경우 해당 요청이 대기열에 들어갑니다.
  • 대기열에 대기 중인 요청이 1초 이상 지속되면 에러가 발생합니다.
  • 대기열이 10을 초과하면 후속 요청이 에러로 거부됩니다.
note
이러한 제한이 도달되면 사용자의 연결이 끊깁니다.

이 대기열에 대한 동작은 Gitaly 로그와 Prometheus를 사용하여 확인할 수 있습니다. 자세한 정보는 관련 문서를 참조하십시오.

pack-objects 동시성 제한

Gitaly는 SSH 및 HTTPS 트래픽을 처리할 때 git-pack-objects 프로세스를 트리거합니다. 이러한 프로세스는 pack-file을 생성하고, 특히 예상치 못한 높은 트래픽 또는 대형 리포지터리에서 동시에 풀링하는 경우에는 상당한 양의 리소스를 소비할 수 있습니다. 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는 키 당 동시에 진행 중인 pack-object 프로세스의 최대 수입니다.
  • max_queue_length는 대기열(각 키당)이 Gitaly에 의해 거부되기 전에 성장할 수 있는 최대 크기입니다.
  • max_queue_wait는 요청이 Gitaly에 의해 처리되기 전에 대기열에서 대기할 수 있는 최대 시간입니다.

위 예시에서:

  • 각 원격 IP는 Gitaly 노드에서 최대 15개의 동시 pack-objects 프로세스를 진행할 수 있습니다.
  • 다른 IP에서 15개의 슬롯을 사용한 요청이 들어오면 해당 요청이 대기열에 들어갑니다.
  • 요청이 대기열에서 1분 이상 대기하면 에러로 거부됩니다.
  • 대기열이 200을 초과하면 후속 요청이 에러로 거부됩니다.

pack-object 캐시가 활성화된 경우, pack-objects 제한은 캐시가 미스될 경우에만 적용됩니다. 자세한 내용은 Pack-objects 캐시를 참조하십시오.

이 대기열에 대한 동작은 Gitaly 로그 및 Prometheus를 사용하여 확인할 수 있습니다. 자세한 정보는 Monitor Gitaly pack-objects 동시성 제한를 참조하십시오.

적응적 동시성 제한

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

이러한 제한이 초과되면 다음 중 하나가 발생합니다.

  • 요청이 대기열에 들어갑니다.
  • 대기열이 가득 차 있거나 요청이 너무 오래 기다린 경우 요청이 거부됩니다.

이러한 두 가지 동시성 제한은 정적으로 구성할 수 있습니다. 정적 제한은 네 가지 보호 결과를 제공할 수 있지만 몇 가지 문제가 있습니다.

  • 정적 제한은 모든 사용 패턴에 적합하지 않습니다. 일괄값이 없습니다. 제한이 너무 낮으면 대형 리포지터리에 부정적인 영향을 미칠 수 있습니다. 제한이 너무 높으면 보호하는 것 자체가 상실됩니다.
  • 각 리포지터리의 작업 부하가 시간이 지남에 따라 변하는 경우에도 정적 제한의 합리적인 값을 유지하는 것은 고된 작업입니다.
  • 서버가 비워져 있는 상태에서도 요청이 거부될 수 있습니다.

모든 이러한 단점을 극복하고 동시성 제한의 이점을 유지하려면 적응적 동시성 제한을 구성함으로써 가능합니다. 적응적 동시성 제한은 선택적이며 두 동시성 제한 유형을 바탕으로 구축됩니다. 추가 증가/곱셈 감소(AIMD) 알고리즘을 사용합니다. 각 적응 제한은 다음을 수행합니다.

  • 일반적인 프로세스 기능 중에 특정 상위 한도까지 점진적으로 증가합니다.
  • 호스트 머신에 리소스 문제가 발생하면 빠르게 감소합니다.

이 메커니즘은 기계에 여유 공간을 제공하며 현재 진행 중인 요청을 가속화합니다. Adaptive concurrency limits are optional and build on the two concurrency limiting types. It uses the Additive Increase/Multiplicative Decrease (AIMD) algorithm. Each adaptive limit:

  • 격자는 일반적인 프로세스 운영 중도 일정 상위 수준까지 점진적으로 증가합니다.
  • 호스트 머신의 상위 cgroup에 메모리 사용량이 90%를 초과하거나 고도로 삭제 가능한 페이지 캐시를 제외한 경우 또는 감시 시간의 50% 이상에서 CPU가 단계적으로 제한될 때 약소, 최대한 한도를 낮춥니다.

그렇지 않은 경우 제한은 일정 상위 한도치까지 하나씩 증가합니다. 이 시스템의 기술적 구현에 대한 자세한 내용은 이 설계안을 참조하십시오.

적응 제한은 각 RPC 또는 pack-objects 캐시에 대해 별도로 활성화됩니다. 그러나 제한은 동시에 조정됩니다.

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 동시성을 참조하세요.