Vue d’ensemble
Lorsqu’un hôte ou un cgroup mémoire tombe à court de mémoire, le killer OOM
(out-of-memory) de Linux termine un processus avec SIGKILL — généralement le plus gros consommateur, qui,
sur un hôte dédié, est clickhouse-server lui-même. On perd alors l’ensemble du serveur
au lieu de lui laisser une chance de se rétablir.
L’OOM canary change l’ordre des victimes. Il exécute un petit processus enfant sacrificiel qui se rend lui-même prioritaire pour l’OOM killer, afin que le noyau le tue à la place du serveur. Le serveur détecte alors sa mort, confirme qu’il s’agissait d’un événement OOM, puis réduit la pression mémoire pour pouvoir survivre.
Le canary n’augmente aucune limite mémoire et ne remplace pas des
limites correctement définies (voir Memory overcommit et
max_server_memory_usage). Il constitue une dernière ligne de défense qui échange une petite quantité
fixe de mémoire contre une chance de survivre à un pic de consommation mémoire.
Comment cela fonctionne
Le canary est un processus clickhouse oom-canary distinct. Il définit son propre
oom_score_adj au maximum (1000) pour que le noyau le cible en premier, puis
alloue, touche et applique mlock à oom_canary_size octets (100 Mo par défaut) afin que
sa mémoire résidente soit bien réelle. Il est automatiquement tué si le serveur s'arrête.
Dans le serveur, un thread de surveillance observe le canary (via pidfd) et réagit lorsqu'il
meurt :
- Tué par
SIGKILLavec preuve d'OOM au niveau du cgroup → exécuter la réponse OOM, puis relancer un nouveau canary. - Tué sans preuve d'OOM (par exemple, un
kill -9manuel), ou arrêté après une défaillance transitoire → relance uniquement, sans réponse. - Échec permanent de l'initialisation, ou arrêt du serveur → le canary se désactive.
La preuve d'OOM provient uniquement du compteur oom_kill de memory.events.local du cgroup v2.
Elle est volontairement locale au cgroup : des compteurs hiérarchiques ou à l'échelle de l'hôte peuvent
être incrémentés par des processus sans rapport et déclencheraient de fausses réponses.
Lorsqu'un OOM est confirmé, la réponse exécute ces étapes indépendantes : consigner un message FATAL,
purger les arènes de l'allocator (jemalloc), annuler dans la mesure du possible toutes les
queries en cours d'exécution, annuler tous les merges et mutations, et mettre en
file d'attente un événement dans
system.crash_log. Les log système ne sont pas
vidés de manière synchrone, car forcer des E/S sous pression mémoire peut aggraver
la situation.
Exigences
- Linux ≥ 5.3. Le moniteur détient le canari via
pidfd_open; sur les noyaux plus anciens, le canari se désactive au démarrage. Cela est sans effet sur les plateformes non Linux. cgroup v2avecmemory.events.localpour la réponse OOM. Sans cela, le canari se relance bien après unSIGKILL, mais ne peut pas confirmer un OOM ; la réponse n'est donc jamais exécutée (un avertissement est consigné au démarrage).- Capacité
mlock(facultative). Le verrouillage de la mémoire du canari nécessiteCAP_IPC_LOCKou une valeurRLIMIT_MEMLOCKsuffisante ; en cas d'échec, le canari consigne un avertissement et sa mémoire peut être paginée sur disque, ce qui le rend moins efficace comme cible OOM.
Configuration
Le canary est contrôlé par les paramètres du serveur, définis comme éléments de premier niveau de la configuration du serveur et appliqués au redémarrage.
| Setting | Default | Description |
|---|---|---|
oom_canary_enable |
false |
Active le OOM canary. |
oom_canary_size |
104857600 (100 MB) |
Nombre d’octets que le canary alloue et utilise. Des valeurs plus élevées en font une cible OOM plus probable. |
oom_canary_relaunch |
true |
Relance le canary après sa terminaison (sauf en cas d’échec permanent lors de l’initialisation ou d’arrêt), sous réserve des limites ci-dessous. |
oom_canary_max_rapid_relaunches |
10 |
Nombre maximal de relances rapides consécutives avant la désactivation de la relance automatique, afin d’éviter les redémarrages en boucle. Le compteur se réinitialise dès qu’un canary survit plus longtemps que oom_canary_max_backoff_seconds. |
oom_canary_initial_backoff_seconds |
1 |
Délai initial entre les relances ; il double à chaque fois jusqu’à la valeur maximale. |
oom_canary_max_backoff_seconds |
60 |
Délai maximal entre les relances. |
<clickhouse>
<oom_canary_enable>1</oom_canary_enable>
<oom_canary_size>104857600</oom_canary_size>
</clickhouse>Observabilité
Un OOM confirmé génère une ligne dans
system.crash_log avec signal = 9 et un
signal_description mentionnant 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;Le cycle de vie du canary et chaque étape de la réponse aux OOM sont également consignés dans le journal du serveur.