롱 폴링
기본적으로 GitLab Runner는 주기적으로 GitLab 인스턴스를 폴링하여 새 CI/CD 작업을 가져옵니다. 실제 폴링 간격은 런너 구성 파일의 check_interval
및 설정된 러너 수에 따라 다릅니다.
많은 러너를 처리하는 서버에서 이 폴링은 여러 성능 문제로 이어질 수 있습니다:
- 대기 시간이 길어짐.
- GitLab 인스턴스의 CPU 사용량이 높아짐.
이러한 문제를 완화하기 위해 롱 폴링을 활성화해야 합니다.
사전 요구 사항:
- 관리자여야 합니다.
롱 폴링 활성화
GitLab 인스턴스를 구성하여 러너의 작업 요청을 새 작업이 준비될 때까지 롱 폴링하는 방식으로 할 수 있습니다.
이를 위해 GitLab Workhorse 롱 폴링 기간(apiCiLongPollingDuration
)을 구성하여 롱 폴링을 활성화합니다:
-
/etc/gitlab/gitlab.rb
파일 편집:gitlab_workhorse['api_ci_long_polling_duration'] = "50s"
-
파일 저장 및 GitLab 재구성:
sudo gitlab-ctl reconfigure
gitlab.webservice.workhorse.extraArgs
설정으로 롱 폴링을 활성화합니다.
-
Helm 값 내보내기:
helm get values gitlab > gitlab_values.yaml
-
gitlab_values.yaml
편집:gitlab: webservice: workhorse: extraArgs: "-apiCiLongPollingDuration 50s"
-
파일 저장 및 새 값 적용:
helm upgrade -f gitlab_values.yaml gitlab gitlab/gitlab
-
docker-compose.yml
파일 편집:version: "3.6" services: gitlab: image: 'gitlab/gitlab-ee:latest' restart: always hostname: 'gitlab.example.com' environment: GITLAB_OMNIBUS_CONFIG: | gitlab_workhorse['api_ci_long_polling_duration'] = "50s"
-
파일 저장 및 GitLab 재시작:
docker compose up -d
메트릭
롱 폴링이 활성화되면, GitLab Workhorse는 Redis PubSub 채널에 구독하고 알림을 기다립니다. 러너 키가 변경되거나 apiCiLongPollingDuration
이 도달되면 롱 폴에서 작업 요청이 해제됩니다.
모니터링할 수 있는 여러 Prometheus 메트릭이 있습니다:
메트릭 | 타입 | 설명 | 레이블 |
---|---|---|---|
gitlab_workhorse_keywatcher_keywatchers
| 게이지 | GitLab Workhorse가 감시 중인 키의 수 | |
gitlab_workhorse_keywatcher_redis_subscriptions
| 게이지 | Redis PubSub 구독 수 | |
gitlab_workhorse_keywatcher_total_messages
| 카운터 | PubSub 채널에서 수신한 총 메시지 수 | |
gitlab_workhorse_keywatcher_actions_total
| 카운터 | 다양한 키 감시 동작 수 | action
|
gitlab_workhorse_keywatcher_received_bytes_total
| 카운터 | PubSub 채널에서 받은 총 바이트 수 |
이러한 메트릭을 사용하여 어떤 사용자가 이러한 메트릭을 사용하여 롱 폴링과 관련된 문제를 발견했던 사례를 확인할 수 있습니다.
롱 폴링 워크플로우
다음 다이어그램은 롱 폴링이 활성화된 상태에서 단일 러너가 작업을 수행하는 과정을 보여줍니다:
1단계에서 러너가 새 작업을 요청하면, GitLab 서버에 /api/v4/jobs/request
로 POST
요청을 보내어 먼저 이를 Workhorse가 처리합니다.
Workhorse는 X-GitLab-Last-Update
HTTP 헤더에서 러너 토큰 및 값, 키를 생성하고 해당 키로 Redis PubSub 채널을 구독합니다. 키에 대한 값이 없는 경우, Workhorse는 즉시 요청을 Rails로 전달합니다 (3단계 및 4단계).
Rails는 작업 대기열을 확인합니다. 러너에 대해 사용 가능한 작업이 없는 경우, Rails는 러너에게 204 No job
및 last_update
토큰으로 응답합니다 (5단계부터 7단계).
러너는 이 last_update
토큰을 사용하여 작업을 요청하고, 이번에는 X-GitLab-Last-Update
HTTP 헤더를 이 토큰으로 채웁니다. 이번에는 Workhorse가 러너의 last_update
토큰이 변경되었는지 확인합니다. 변경되지 않은 경우, Workhorse는 apiCiLongPollingDuration
로 지정된 기간 동안 요청을 유지합니다.
사용자가 새로운 파이프라인 또는 작업을 트리거하면 Sidekiq의 백그라운드 작업이 해당 작업에 대해 사용 가능한 모든 러너를 위해 last_update
값을 업데이트합니다. 러너는 프로젝트, 그룹 및/또는 인스턴스에 등록될 수 있습니다.
10단계 및 11단계의 “틱”에서 Workhorse의 롱 폴 큐에서 작업 요청이 해제되고, 요청이 Rails로 전송됩니다 (12단계). Rails는 사용 가능한 작업을 찾고, 해당 작업에 러너를 할당합니다 (13단계 및 14단계).
롱 폴링을 통해 러너는 새 작업이 가능해지자마자 즉시 알림을 받습니다. 이는 작업 대기 시간을 줄이고, 새로운 작업이 있을 때에만 리소스를 사용하도록 함으로써 서버 부하를 줄이는 데 도움이 됩니다.
문제 해결
긴 폴링을 사용할 때 다음과 같은 문제가 발생할 수 있습니다.
작업 픽업이 느림
일부 러너 구성에서는 러너가 적시에 작업을 수행하지 않기 때문에 긴 폴링이 기본적으로 활성화되지 않습니다. 이슈 27709를 확인하세요.
러너 config.toml
의 concurrent
설정이 정의된 러너 수보다 낮게 설정된 경우에 발생할 수 있습니다. 이 문제를 해결하려면 concurrent
의 값이 러너의 수와 동일하거나 그 이상으로 설정되어 있는지 확인하십시오.
예를 들어, config.toml
에 3개의 [[runners]]
항목이 있는 경우, concurrent
가 적어도 3으로 설정되어 있는지 확인하십시오.
긴 폴링이 활성화되면 러너는 다음과 같이 동작합니다.
-
concurrent
개수의 고루틴을 시작합니다. - 긴 폴링 후에 고루틴이 반환될 때까지 기다립니다.
- 다른 일괄 요청을 실행합니다.
예를 들어, 단일 config.toml
이 다음과 같이 구성된 경우를 생각해보겠습니다.
- 프로젝트 A의 러너가 3개입니다.
- 프로젝트 B의 러너가 1개입니다.
-
concurrent
가 3으로 설정되어 있습니다.
이 예에서 러너는 처음 3개 프로젝트에 대해 고루틴을 시작합니다. 최악의 경우, 러너는 프로젝트 A의 작업을 요청하기 전에 프로젝트 B의 긴 폴링 간격 전체를 기다리게 됩니다.