メモリ使用量の削減

GitLab Railsアプリケーションコードはメモリリークに悩まされています。ウェブリクエストの場合、この問題は監視スレッドを使うことで対処可能です。このスレッドは、ワーカーが与えられた常駐セットサイズ(RSS) のしきい値を一定時間超えると自動的に再起動します。GitLabがバックグラウンドジョブを処理するために使うSidekiqプロセスにも同じアプローチを使います。

GitLabは、LinuxパッケージまたはDockerインストールに対してのみ、デフォルトで利用可能なRSSの上限を監視します。その理由は、GitLabはメモリによるシャットダウン後にSidekiqを再起動するためにrunitに依存しており、セルフコンパイルやHelmチャートのインストールではrunitや同等のツールを使用しないためです。

デフォルトの設定では、Sidekiqは15分に1回以上の頻度で再起動することはなく、再起動は着信バックグラウンドジョブに約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_TIMESIDEKIQ_MEMORY_KILLER_MAX_RSS 超える場合 SIDEKIQ_MEMORY_KILLER_MAX_RSS、グレースフル・リスタートがトリガーされます。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プロセスハードリミットを定義します。SidekiqプロセスのRSS(キロバイトで表示) SIDEKIQ_MEMORY_KILLER_HARD_LIMIT_RSSが、この値をSIDEKIQ_MEMORY_KILLER_HARD_LIMIT_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秒後に強制終了されます。その間にジョブが終了しない場合、SidekiqプロセスにSIGTERM シグナルが送信され、現在実行中のすべてのジョブが中断されます。

  • GITLAB_MEMORY_WATCHDOG_ENABLEDデフォルトで有効。 GITLAB_MEMORY_WATCHDOG_ENABLEDウォッチドッグの実行を無効にするには、falseにGITLAB_MEMORY_WATCHDOG_ENABLED設定 GITLAB_MEMORY_WATCHDOG_ENABLEDします。

ワーカーの再起動を監視

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制限を超過し、グレースフル・リスタートを開始した時点で実行されていたジョブを一覧表示します。