메모리 사용량 줄이기

GitLab Rails 애플리케이션 코드는 메모리 누수 문제를 겪습니다. 웹 요청에 대해서는 감시 스레드를 사용하여 관리되며, 일정 시간 동안 주어진 resident set size (RSS) 임계값을 초과하는 워커를 자동으로 다시 시작합니다. GitLab은 백그라운드 작업을 처리하기 위해 사용되는 Sidekiq 프로세스에도 동일한 방식을 적용합니다.

기본 설정에서 GitLab은 Linux 패키지 또는 Docker 설치에 대해서만 사용 가능한 RSS 제한을 모니터링합니다. 이는 GitLab이 runit을 사용하여 메모리 중단 후 Sidekiq을 다시 시작하도록 의존하기 때문이며, 직접 컴파일하거나 Helm 차트를 사용하는 설치에서는 runit이나 이와 동등한 도구를 사용하지 않기 때문입니다.

기본 설정으로는 Sidekiq은 15분에 한 번 초과하더라도 다시 시작하며, 이로 인해 들어오는 백그라운드 작업에 대해 약 1분의 지연이 발생합니다.

일부 백그라운드 작업은 오래 실행되는 외부 프로세스에 의존합니다. 따라서 Sidekiq이 다시 시작될 때 이러한 프로세스가 깔끔하게 종료되도록 각 Sidekiq 프로세스는 프로세스 그룹 리더로 실행되어야 합니다(chpst -P를 사용하여 예를 들면). Linux 패키지 설치나 runit이 설치된 bin/background_jobs 스크립트를 사용할 경우, 이것은 자동으로 처리됩니다.

제한 사항 구성

Sidekiq 메모리 제한은 환경 변수를 사용하여 제어됩니다.

  • SIDEKIQ_MEMORY_KILLER_MAX_RSS (KB): 사이드킥 프로세스의 허용된 RSS 소프트 제한을 정의합니다. Sidekiq 프로세스의 RSS(킬로바이트 단위)가 SIDEKIQ_MEMORY_KILLER_MAX_RSS를 초과하고, SIDEKIQ_MEMORY_KILLER_GRACE_TIME보다 긴 시간 동안 유지된다면 우아한 재시작이 트리거됩니다. 만약 SIDEKIQ_MEMORY_KILLER_MAX_RSS가 설정되지 않았거나 0으로 설정된 경우에는 소프트 제한이 모니터링되지 않습니다. SIDEKIQ_MEMORY_KILLER_MAX_RSS 기본값은 2000000입니다.

  • SIDEKIQ_MEMORY_KILLER_GRACE_TIME: Sidekiq 프로세스가 허용된 RSS 소프트 제한을 초과하여 실행하는 시간(초)을 정의합니다. 만약 Sidekiq 프로세스가 허용된 RSS(소프트 제한) 아래로 SIDEKIQ_MEMORY_KILLER_GRACE_TIME 안에 들어온다면 재시작은 중단됩니다. 기본값은 900초(15분)입니다.

  • SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS (KB): 사이드킥 프로세스의 허용된 RSS 하드 제한을 정의합니다. Sidekiq 프로세스의 RSS(킬로바이트 단위)가 SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS를 초과하면 Sidekiq의 즉각적인 우아한 재시작이 트리거됩니다. 이 값이 설정되지 않았거나 0으로 설정된 경우, 하드 제한은 모니터링되지 않습니다.

  • SIDEKIQ_MEMORY_KILLER_CHECK_INTERVAL: 프로세스 RSS를 확인하는 간격을 정의합니다. 기본값은 3초입니다.

  • SIDEKIQ_MEMORY_KILLER_SHUTDOWN_WAIT: 모든 Sidekiq 작업이 완료되는 데 허용된 최대 시간을 정의합니다. 해당 시간 동안 새 작업은 수락되지 않습니다. 기본값은 30초입니다.

만약 Sidekiq에 의해 프로세스 재시작이 수행되지 않으면 Sidekiq 종료 시간 제한 (기본값은 25초) +2초 이후에 Sidekiq 프로세스가 강제로 종료됩니다. 이 시간 동안 작업이 완료되지 않으면 Sidekiq 프로세스로 SIGTERM 신호가 보내져 현재 실행 중인 모든 작업이 중단됩니다.

  • GITLAB_MEMORY_WATCHDOG_ENABLED: 기본적으로 활성화됩니다. Watchdog를 실행하지 않으려면 GITLAB_MEMORY_WATCHDOG_ENABLED를 false로 설정하세요.

워커 재시작 모니터링

높은 메모리 사용으로 인해 워커가 재시작되면 GitLab이 로그 이벤트를 발생시킵니다.

다음은 /var/log/gitlab/gitlab-rails/sidekiq_client.log에서 이러한 로그 이벤트 중 하나의 예입니다:

{
  "severity": "WARN",
  "time": "2023-02-04T09:45:16.173Z",
  "correlation_id": null,
  "pid": 2725,
  "worker_id": "sidekiq_1",
  "memwd_handler_class": "Gitlab::Memory::Watchdog::SidekiqHandler",
  "memwd_sleep_time_s": 3,
  "memwd_rss_bytes": 1079683247,
  "memwd_max_rss_bytes": 629145600,
  "memwd_max_strikes": 5,
  "memwd_cur_strikes": 6,
  "message": "rss memory limit exceeded",
  "running_jobs": [
    {
      jid: "83efb701c59547ee42ff7068",
      worker_class: "Ci::DeleteObjectsWorker"
    },
    {
      jid: "c3a74503dc2637f8f9445dd3",
      worker_class: "Ci::ArchiveTraceWorker"
    }
  ]
}

여기서:

  • memwd_rss_bytes는 실제로 사용된 메모리 양입니다.
  • memwd_max_rss_bytesper_worker_max_memory_mb로 설정된 RSS 제한입니다.
  • running jobs는 프로세스가 RSS 제한을 초과하고 우아한 재시작을 시작한 시점에서 실행 중이던 작업을 나열합니다.