OOM canary
OOM canary
OOM canary는 실험적이며 기본적으로 비활성화되어 있습니다. 호스트나 메모리 cgroup의 메모리가 고갈되면 Linux OOM 킬러가 프로세스를 종료하는데, canary는 자신을 가장 매력적인 OOM 대상으로 만들어 서버 대신 죽게 함으로써 서버가 회복할 기회를 얻습니다.
출처: 문서
본문
OOM canary는 실험적이며 기본적으로 비활성화되어 있습니다. 프로덕션 검증이 완료될 때까지 ClickHouse 버전 사이에서 동작이 바뀔 수 있습니다.
개요 (Overview)
호스트나 메모리 cgroup의 메모리가 고갈되면 Linux OOM(out-of-memory) 킬러는 SIGKILL로 프로세스를 종료합니다 — 보통 가장 큰 소비자이며, 전용 호스트에서는 clickhouse-server 자체입니다. 회복할 기회를 주는 대신 서버 전체가 손실됩니다.
OOM canary는 누가 먼저 죽는지를 바꿉니다. 그것은 자신을 가장 매력적인 OOM 대상으로 만드는 작은 희생(sacrificial) 자식 프로세스를 실행해, 커널이 서버 대신 그것을 죽이게 합니다. 그러면 서버는 죽음을 감지하고 OOM 이벤트임을 확인한 뒤, 살아남기 위해 메모리 압력을 내려놓습니다.
Canary는 어떤 메모리 한도도 올리지 않으며 올바른 한도(Memory overcommit 및 max_server_memory_usage 참고)를 대체하지 않습니다. 그것은 작고 고정된 메모리 양을 메모리 급증에서 살아남을 기회와 맞바꾸는 최후의 방어선입니다.
동작 방식
Canary는 별도의 clickhouse oom-canary 프로세스입니다. 그것은 자신의 oom_score_adj를 최댓값(1000)으로 설정해 커널이 먼저 그것을 타깃으로 삼게 하고, 그런 다음 oom_canary_size바이트(기본 100 MB)를 할당·접촉·mlock하여 상주 집합(resident set)이 실제가 되게 합니다. 서버가 종료되면 자동으로 죽습니다.
서버의 모니터 스레드는(pidfd를 통해) canary를 지켜보다가 죽으면 반응합니다:
- cgroup OOM 증거와 함께
SIGKILL로 죽음 → OOM 응답을 실행한 후 새 canary를 재시작. - OOM 증거 없이 죽음(예: 수동
kill -9), 또는 일시적 실패로 종료 → 재시작만, 응답 없음. - 영구 설정 실패, 또는 서버 종료 → canary가 스스로 비활성화.
OOM 증거는 cgroup v2 memory.events.local oom_kill 카운터에서만 옵니다. 의도적으로 cgroup 로컬입니다: 계층적 또는 호스트 전체 카운터는 관련 없는 프로세스에 의해 증가되어 거짓 응답을 트리거할 수 있습니다.
확인된 OOM에서 응답은 다음 독립 단계를 실행합니다: FATAL 메시지 기록, 할당자(jemalloc) 아레나 정리, 실행 중인 모든 쿼리 최선 노력 취소, 모든 병합과 뮤테이션 취소, system.crash_log에 이벤트 큐. 시스템 로그는 동기적으로 플러시되지 않습니다. 메모리 압력 아래에서 I/O를 강제하면 상황을 악화시킬 수 있기 때문입니다.
요구사항
- Linux ≥ 5.3. 모니터가
pidfd_open으로 canary를 소유합니다. 오래된 커널에서는 canary가 시작 시 스스로 비활성화됩니다. 비-Linux 플랫폼에서는 no-op입니다. - OOM 응답을 위한 cgroup v2와 memory.events.local. 없으면 canary가
SIGKILL후에도 여전히 재시작하지만 OOM을 확인할 수 없어 응답이 실행되지 않습니다(시작 시 경고가 기록됨). - mlock 기능(선택). canary의 메모리를 잠그려면
CAP_IPC_LOCK또는 충분한RLIMIT_MEMLOCK이 필요합니다. 실패하면 canary가 경고를 기록하고 메모리가 스왑되어 OOM 대상으로서 약해질 수 있습니다.
memory.oom.group
서버 cgroup에 대해 cgroup v2 memory.oom.group이 활성화되면 커널이 OOM 시 전체 cgroup을 한 단위로 죽입니다 — 서버가 canary와 함께 죽고 응답이 실행되지 않습니다. 이 모드에서는 canary가 서버를 보호할 수 없습니다. 시작 시 경고가 기록됩니다.
구성
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 | 재시작 사이의 초기 지연. 최대까지 매번 두 배가 됩니다. |
| oom_canary_max_backoff_seconds | 60 | 재시작 사이의 최대 지연. |
<clickhouse>
<oom_canary_enable>1</oom_canary_enable>
<oom_canary_size>104857600</oom_canary_size>
</clickhouse>
관찰 가능성
확인된 OOM은 signal = 9와 OOM Canary를 언급하는 signal_description과 함께 system.crash_log에 행을 만듭니다:
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-응답 단계도 서버 로그에 기록됩니다.