OOM-канарейка является экспериментальной и по умолчанию отключена. Её поведение может меняться
между версиями ClickHouse до завершения валидации в продакшне.
Обзор
SIGKILL — обычно самого крупного потребителя,
которым на выделенном хосте является сам clickhouse-server. В результате
вместо шанса на восстановление сервер целиком выходит из строя.
OOM-канарейка меняет то, кто погибает первым. Она запускает небольшой
жертвенный дочерний процесс, который делает себя наиболее привлекательной
целью для OOM, чтобы ядро убило его, а не сервер. Затем сервер обнаруживает
его завершение, подтверждает, что причиной был OOM, и сбрасывает давление
на память, чтобы выжить.
Канарейка не увеличивает никакой лимит памяти и не заменяет корректно настроенные
ограничения (см. Оверкоммит памяти и
max_server_memory_usage). Это последний рубеж защиты: за небольшой,
фиксированный объём памяти она даёт шанс пережить резкий всплеск потребления памяти.
Как это работает
clickhouse oom-canary. Он устанавливает для себя
oom_score_adj на максимум (1000), чтобы ядро выбрало его первой целью, затем
выделяет oom_canary_size байт (по умолчанию 100 МБ), обращается к этой памяти и вызывает mlock,
чтобы его резидентный объём памяти был реальным. Этот процесс автоматически завершается, если сервер останавливается.
На сервере поток мониторинга следит за канарейкой (через pidfd) и реагирует, когда
она завершается:
- Завершена сигналом
SIGKILLпри наличии признаков OOM в cgroup → выполнить реакцию на OOM, затем заново запустить новую канарейку. - Завершена без признаков OOM (например, при ручном
kill -9) или завершилась из-за временного сбоя → только перезапуск, без реакции. - Постоянная ошибка инициализации или остановка сервера → канарейка отключается сама.
oom_kill в memory.events.local cgroup v2.
Это намеренно ограничено текущей cgroup: иерархические или общесистемные счётчики могут
увеличиваться из-за несвязанных процессов и вызывать ложные срабатывания.
При подтверждённом OOM реакция выполняет следующие независимые шаги: записывает сообщение FATAL
в журнал, очищает арены аллокатора (jemalloc), по возможности отменяет все выполняющиеся
запросы, отменяет все слияния и мутации и ставит событие в очередь
system.crash_log. Системные журналы не
сбрасываются на диск синхронно, потому что принудительный I/O при нехватке памяти может только ухудшить ситуацию.
Требования
- Linux ≥ 5.3. Монитор управляет канарейкой через
pidfd_open; на более старых ядрах канарейка отключается при запуске. На платформах, отличных от Linux, это не даёт никакого эффекта. - cgroup v2 с
memory.events.localдля реакции на OOM. Без этого канарейка всё равно перезапускается послеSIGKILL, но не может подтвердить OOM, поэтому реакция не запускается (при запуске в журнал записывается предупреждение). - Привилегия
mlock(необязательно). Чтобы заблокировать память канарейки, требуетсяCAP_IPC_LOCKили достаточныйRLIMIT_MEMLOCK; если это не удаётся, канарейка записывает предупреждение, а её память может быть выгружена в swap, что снижает её эффективность как цели OOM.
Конфигурация
Обсервабилити
system.crash_log с signal = 9 и
signal_description, где упоминается OOM Canary: