롱 폴링
기본적으로 GitLab Runner는 새로운 CI/CD 작업에 대해 주기적으로 GitLab 인스턴스를 폴링합니다. 실제 폴링 간격은 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 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 |
카운터 | GitLab Workhorse가 PubSub 채널에서 수신한 총 메시지 수 | |
gitlab_workhorse_keywatcher_actions_total |
카운터 | 다양한 키 감시자 작업 수 | action |
gitlab_workhorse_keywatcher_received_bytes_total |
카운터 | PubSub 채널에서 수신된 총 바이트 수 |
이 메트릭으로 롱 폴링의 문제를 발견한 사용자의 예시를 확인할 수 있습니다.
롱 폴링 워크플로우
다이어그램은 롱 폴링이 활성화된 단일 러너가 작업을 얻는 방법을 보여줍니다:
1단계에서 러너가 새로운 작업을 요청할 때, POST
요청(/api/v4/jobs/request
)을 GitLab 서버에 전송하며, 이 요청은 먼저 워크호스에 의해 처리됩니다.
워크호스는 러너 토큰과 X-GitLab-Last-Update
HTTP 헤더의 값을 읽고, 키를 구성한 후 해당 키로 Redis PubSub 채널에 구독합니다. 키에 대한 값이 존재하지 않으면 워크호스는 즉시 Rails로 요청을 전달합니다(3단계 및 4단계).
Rails는 작업 큐를 확인합니다. 러너를 위한 작업이 없으면 Rails는 러너에게 204 작업 없음
과 last_update
토큰을 반환합니다(5단계에서 7단계).
러너는 해당 last_update
토큰을 사용하여 작업 요청을 다시 전송하며, 이 토큰으로 X-GitLab-Last-Update
HTTP 헤더를 채웁니다. 이번에는 워크호스가 러너의 last_update
토큰이 변경되었는지 확인합니다. 변경되지 않았다면, 워크호스는 요청을 apiCiLongPollingDuration
에 지정된 기간만큼 보류합니다.
사용자가 새로운 파이프라인이나 작업을 트리거하면, Sidekiq의 백그라운드 작업이 작업에 사용할 수 있는 모든 러너의 last_update
값을 업데이트합니다. 러너는 프로젝트, 그룹 및/또는 인스턴스에 등록할 수 있습니다.
10단계와 11단계에서의 이 “틱”은 작업 요청을 워크호스 롱 폴링 큐에서 해제하고, 요청이 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개의 프로젝트에 대해 고루틴을 시작합니다.
최악의 경우, 러너는 프로젝트 A에 대해 전체 롱 폴링 간격만큼 기다린 후에야 프로젝트 B에 대한 작업 요청을 진행합니다.