롱 폴링
기본적으로 GitLab Runner는 주기적으로 GitLab 인스턴스를 폴링하여 새 CI/CD 작업을 확인합니다. 실제 폴링 간격은 런너 구성 파일에서 check_interval
및 구성된 런너 수에 따라 달라집니다.
많은 러너를 처리하는 서버에서 이 폴링은 다음과 같은 여러 성능 문제로 이어질 수 있습니다:
- 대기 시간이 길어짐.
- GitLab 인스턴스에서 높은 CPU 사용량.
이러한 문제를 완화하기 위해 롱 폴링을 활성화해야 합니다.
전제 조건:
- 관리자이어야 합니다.
롱 폴링 활성화
GitLab 인스턴스에서 러너의 작업 요청을 새 작업이 준비될 때까지 롱 폴링으로 유지하도록 구성할 수 있습니다.
이를 위해 apiCiLongPollingDuration
GitLab Workhorse 롱 폴링 기간을 구성하여 롱 폴링을 활성화하세요:
-
/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
| 카운터 | Redis PubSub 채널에서 받은 총 메시지 수 | |
gitlab_workhorse_keywatcher_actions_total
| 카운터 | 다양한 키 감시자 작업 수 | action
|
gitlab_workhorse_keywatcher_received_bytes_total
| 카운터 | PubSub 채널에서 받은 총 바이트 수 |
이러한 메트릭으로 한 사용자가 롱 폴링과 관련된 문제를 발견한 예시를 확인할 수 있습니다.
롱 폴링 워크플로우
다음 다이어그램은 롱 폴링이 활성화된 단일 러너가 작업을 받는 과정을 보여줍니다:
1단계에서 러너가 새 작업을 요청하면 GitLab 서버로 POST
요청(/api/v4/jobs/request
)을 보내고, 이 요청은 먼저 Workhorse에서 처리됩니다.
Workhorse는 러너 토큰과 값을 X-GitLab-Last-Update
HTTP 헤더에서 읽고, 키를 작성하여 해당 키로 Redis PubSub 채널에 가입합니다. 키에 대한 값이 존재하지 않으면, Workhorse는 즉시 Rails로 요청을 전달합니다(3단계 및 4단계).
Rails는 작업 대기열을 확인합니다. 러너에게 사용 가능한 작업이 없는 경우 Rails는 204 작업 없음
과 함께 last_update
토큰을 러너에 반환합니다(5단계부터 7단계까지).
러너는 last_update
토큰을 사용하여 다시 작업을 요청하고, 이번에는 X-GitLab-Last-Update
HTTP 헤더를 이 토큰으로 채웁니다. 이번에는 Workhorse가 러너의 last_update
토큰이 변경되었는지 확인합니다. 변경되지 않았다면, Workhorse는 apiCiLongPollingDuration
에서 지정한 기간까지 요청을 유지합니다.
사용자가 새 파이프라인이나 작업을 트리거하면, Sidekiq의 백그라운드 작업이 해당 작업에 사용 가능한 모든 러너의 last_update
값을 업데이트합니다. 러너는 프로젝트, 그룹, 또는 인스턴스에 등록될 수 있습니다.
11단계에서의 이러한 “틱”은 Workhorse의 롱 폴링 대기열에서 작업 요청을 해제하고 요청을 Rails로 보냅니다(12단계). Rails는 사용 가능한 작업을 찾아서 러너에게 해당 작업을 할당합니다(13단계 및 14단계).
롱 폴링을 사용하면 새 작업이 사용 가능한 즉시 러너에게 알림이 전달됩니다. 이는 작업 대기 시간을 줄이고, 새로운 작업이 있을 때에만 작업 요청이 Rails에 도달하기 때문에 서버 부담을 줄이는 데 도움이 됩니다.
문제 해결
긴 폴링 작업을 수행하는 동안 다음과 같은 문제가 발생할 수 있습니다.
작업 픽업이 느린 경우
긴 폴링은 기본적으로 활성화되어 있지 않습니다. 왜냐하면 일부 러너 구성에서는 러너가 작업을 적시에 받아오지 못할 수 있기 때문입니다. 이슈 27709를 참조하세요.
런너의 config.toml
에서 concurrent
설정이 정의된 러너의 수보다 초과 낮게 설정되어 있을 수 있습니다. 이 문제를 해결하려면, concurrent
값이 러너의 수와 동일하거나 더 큰지 확인하세요.
예를 들어, config.toml
에 세 개의 [[runners]]
항목이 있다면, concurrent
가 최소한 3으로 설정되어 있는지 확인하세요.
긴 폴링이 활성화되어 있는 경우, 러너는 다음을 수행합니다.
-
concurrent
수의 고루틴을 실행합니다. - 긴 폴링 후에 고루틴의 반환을 기다립니다.
- 다른 일괄 요청을 실행합니다.
예를 들어, 단일 config.toml
파일에 다음과 같이 구성된 경우를 고려해보겠습니다.
- A 프로젝트에 대해 3개의 러너가 구성되어 있음.
- B 프로젝트에 대해 1개의 러너가 구성되어 있음.
-
concurrent
가 3으로 설정되어 있음.
이 경우, 러너는 첫 3개의 프로젝트에 대해 고루틴을 실행합니다. 최악의 경우, 러너는 B 프로젝트의 작업을 요청하기 전에 A 프로젝트에 대해 전체 긴 폴링 간격동안 대기합니다.