메모리 사용량 줄이기

GitLab Rails 어플리케이션 코드는 메모리 누수로 인해 고통 받습니다. 웹 요청에 대해, 지도 스레드를 사용하여 문제를 관리하며, 이를 통해 특정 기간 동안 주어진 주거 세트 크기 (RSS) 임계값을 초과하는 경우 작업자를 자동으로 다시 시작합니다. GitLab이 사용하는 Sidekiq 프로세스에도 동일한 방식을 사용하여 백그라운드 작업을 처리합니다.

GitLab은 기본적으로 Linux 패키지 또는 Docker 설치에 대해서만 RSS 제한을 모니터링합니다. 이것은 GitLab이 runit을 사용하여 메모리로 인한 종료 후 Sidekiq을 다시 시작하며, self-compiled 및 Helm 차트 설치는 runit이나 동등한 도구를 사용하지 않기 때문입니다.

기본 설정에서 Sidekiq은 하루에 한 번을 넘어 다시 시작되지 않으며, 다시 시작으로 인해 들어오는 백그라운드 작업에 약 1분의 지연이 발생합니다.

몇 가지 백그라운드 작업은 장기간 실행되는 외부 프로세스에 의존합니다. Sidekiq을 다시 시작할 때 이러한 프로세스가 정상적으로 종료되도록 하기 위해 각 Sidekiq 프로세스는 프로세스 그룹 리더로 실행되어야 합니다 (예: chpst -P를 사용). Linux 패키지 설치 또는 runit이 설치된 bin/background_jobs 스크립트를 사용하는 경우, 이것은 자동으로 처리됩니다.

제한 사항 구성

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

  • SIDEKIQ_MEMORY_KILLER_MAX_RSS (KB): 허용된 RSS에 대한 Sidekiq 프로세스의 소프트 제한을 정의합니다. 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: 허용된 RSS 소프트 제한을 초과한 경우 Sidekiq 프로세스가 허용된 RSS (소프트 제한) 아래로 내려가면 재시작이 중단되는 우아한 시간 기간을 정의합니다. 기본값은 900초 (15분)입니다.

  • SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSS (KB): 허용된 RSS에 대한 Sidekiq 프로세스의 하드 제한을 정의합니다. 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 프로세스는 강제로 종료됩니다. Sidekiq 종료 시간 제한 (기본값은 25초) +2초 후입니다. 해당 시간 동안 작업을 완료하지 않으면 현재 실행 중인 모든 작업이 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 제한을 초과하고 우아한 재시작을 시작한 시간에 실행 중이던 작업을 나열합니다.