概要
ホストまたは memory cgroup のメモリが不足すると、Linux の OOM (out-of-memory)
キラーが SIGKILL でプロセスを強制終了します。通常は最も多くメモリを消費しているプロセスが対象となり、
専用ホストではたいてい clickhouse-server 自身です。その結果、サーバーは回復の機会を与えられないまま、
丸ごと失われてしまいます。
OOM canary は、先に終了させられる対象を変えます。小さな 犠牲用の 子プロセスを実行し、 それ自身が OOM の最優先ターゲットになることで、カーネルはサーバーではなくそのプロセスを kill します。するとサーバーはその終了を検知し、それが OOM イベントだったことを確認したうえでメモリ逼迫を緩和し、生き残れるようになります。
canary はメモリ制限を引き上げるものではなく、適切な limits の代替でもありません
(メモリオーバーコミット および
max_server_memory_usage を参照) 。これは最後の防衛線であり、少量の固定メモリと引き換えに、
一時的なメモリ急増を生き延びられる可能性を確保するものです。
仕組み
canary は、独立した clickhouse oom-canary プロセスです。自身の
oom_score_adj を最大値 (1000) に設定してカーネルが最初にこれを対象にするようにしたうえで、
oom_canary_size バイト (デフォルトでは 100 MB) を割り当て、実際にアクセスし、mlock して、
resident set が実体を持つようにします。サーバーが終了すると、自動的に終了させられます。
サーバー側では、監視スレッドが canary を (pidfd 経由で) 監視し、
canary が終了すると対応します。
SIGKILLによって kill され、かつ cgroup OOM の証拠がある → OOM 対応を実行した後、 新しい canary を再起動します。- OOM の証拠なしで kill された場合 (たとえば手動の
kill -9) 、または一時的な障害で終了した場合 → 対応は行わず、再起動のみ行います。 - 恒久的な初期化失敗、またはサーバーのシャットダウン → canary は自動的に無効化されます。
OOM の証拠として使われるのは、cgroup v2 の memory.events.local oom_kill
カウンターのみです。これは意図的に cgroup ローカルに限定されています。階層的なカウンターやホスト全体のカウンターは
無関係なプロセスによって増加する可能性があり、誤った対応をトリガーしかねないためです。
OOM が確認されると、対応として次の独立した手順が実行されます: FATAL
メッセージをログに記録する、アロケータ (jemalloc) のアリーナを purge する、実行中の
すべてのクエリをベストエフォートでキャンセルする、すべての merge と mutations をキャンセルする、そして
system.crash_log にイベントを
キューに入れます。システムログは同期的には flush されません。メモリ逼迫下で I/O を強制すると、
状況が悪化する可能性があるためです。
要件
- Linux ≥ 5.3. モニターは
pidfd_openを介して canary を管理します。古いカーネルでは、 canary は起動時に自身を無効化します。非 Linux プラットフォームでは no-op です。 - OOM 対応 には
memory.events.localを備えた cgroup v2 が必要です。 これがない場合でも、 canary はSIGKILLの後に再起動しますが、OOM を確認できないため、 対応 は実行されません (起動時に警告がログに記録されます) 。 mlockcapability (任意) 。 canary のメモリを lock するにはCAP_IPC_LOCKまたは十分なRLIMIT_MEMLOCKが必要です。失敗した場合、canary は 警告をログに記録し、そのメモリがスワップアウトされる可能性があるため、 OOM の対象としての有効性が弱まります。
設定
OOM canary はサーバー設定で制御します。 これらはサーバー設定のトップレベル要素として設定し、再起動時に適用されます。
| 設定 | 既定値 | 説明 |
|---|---|---|
oom_canary_enable |
false |
OOM canary を有効にします。 |
oom_canary_size |
104857600 (100 MB) |
canary が確保してアクセスするバイト数です。値が大きいほど、OOM の対象として選ばれやすくなります。 |
oom_canary_relaunch |
true |
canary が終了した後に再起動します (復旧不能な初期化失敗またはシャットダウンの場合を除く) 。ただし、以下の制限に従います。 |
oom_canary_max_rapid_relaunches |
10 |
自動再起動が無効になるまでの、連続する短時間での再起動の最大回数です。過剰な再起動を避けるためのものです。canary が oom_canary_max_backoff_seconds を超えて存続するとリセットされます。 |
oom_canary_initial_backoff_seconds |
1 |
再起動間の初期遅延です。最大値に達するまで、再起動のたびに 2 倍になります。 |
oom_canary_max_backoff_seconds |
60 |
再起動間の最大遅延です。 |
<clickhouse>
<oom_canary_enable>1</oom_canary_enable>
<oom_canary_size>104857600</oom_canary_size>
</clickhouse>オブザーバビリティ
OOM が確認されると、
system.crash_log に signal = 9 の
行が記録され、signal_description には OOM Canary への言及が含まれます:
SELECT event_time, signal, signal_description
FROM system.crash_log
WHERE signal = 9 AND signal_description LIKE '%OOM Canary%'
ORDER BY event_time DESC;canaryのライフサイクルと、OOM対応の各ステップもサーバーログに記録されます。