classique. glibc et les threads python ça fait pas bon ménage sur la gestion des arènes. par défaut glibc crée jusqu'à 8 arènes par cœur cpu. ça fragmente à mort.
t'as essayé de limiter les arènes avec une variable d'environnement ?
j'ai testé ça ce matin sans grand succès :
export MALLOC_ARENA_MAX=2le RSS monte moins vite mais ça finit toujours par péter. j'ai l'impression que la mémoire est jamais rendue à l'OS.
regarde tes smaps. faut voir si t'as beaucoup de trous dans les mappings. fais un dump de /proc/PID/smaps_rollups pour voir l'état global.
voilà le retour du rollup :
Rss: 1245672 kB
Pss: 1210432 kB
Shared_Clean: 512 kB
Shared_Dirty: 0 kB
Private_Clean: 124 kB
Private_Dirty: 1245036 kB
Referenced: 1245672 kB
Anonymous: 1245012 kB
LazyFree: 0 kB
AnonHugePages: 0 kB
ShmemPmdMapped: 0 kB
Shared_Hugetlb: 0 kB
Private_Hugetlb: 0 kB
Swap: 0 kB
SwapPss: 0 kB
Locked: 0 kBpresque tout est en private dirty. c'est pas du leak de lib externe on dirait.
si ton heap python est stable c'est forcément la glibc qui retient les pages. elle utilise brk() ou mmap() pour tes allocs ?
si c'est du brk() et que t'as un objet long-lived tout en haut du tas ça bloque toute la libération en dessous.
on a pas mal de petits objets qui restent en cache (LRU). ça doit être ça qui fait chier. comment je force glibc à être plus agressive sur le free ?
tu peux pas vraiment. glibc est naze pour ça. passe sur jemalloc ou mimalloc. jemalloc gère vachement mieux la fragmentation sur les long-running processes.
fais un test rapide en injectant la lib via LD_PRELOAD dans ton container.
je vais tenter jemalloc. faut que je l'installe dans mon dockerfile d'abord. t'as une config spécifique pour les dirty pages ?
ajoute ça pour que jemalloc rende la mémoire plus vite :
MALLOC_CONF="dirty_decay_ms:1000,muzzy_decay_ms:1000"
installe le paquet libjemalloc2. dans ton dockerfile :
RUN apt-get update && apt-get install -y libjemalloc2
ENV LD_PRELOAD="/usr/lib/x86_64-linux-gnu/libjemalloc.so.2"
c'est en prod sur un noeud de test. j'observe le graph prometheus là. la courbe est radicalement différente. le RSS reste plat après la phase de warmup.
check quand même tes latences. jemalloc peut rajouter un peu d'overhead sur les allocs très fréquentes mais normalement sur du python ça se voit pas.
les p99 ont pas bougé. par contre la conso ram est passée de 1.2GB à 450MB stable. glibc nous volait 800MB de ghost memory par worker.
c'est classique sur les runtimes asynchrones ou multithreadés. glibc garde les pages au cas où pour la perf mais ça finit en carnage sur k8s.
incroyable. j'ai passé tout le cluster sous jemalloc. plus aucun OOM sur les 4 dernières heures. merci les gars pour le coup de main sur l'allocateur c'était pile ça.
Vous devez être connecté pour poster un message !
Recevoir les derniers articles gratuitement en créant un compte !
S'inscrire
zgaillard
Membre depuis le 16/11/2024hello. on a un souci de fuite mémoire sur nos workers python en prod. l'appli tourne sur debian bullseye. le RSS monte linéairement jusqu'au OOM-kill du pod sans jamais redescendre même après un cycle GC complet.
on a déjà checké avec tracemalloc et objgraph. l'heap python est stable. le souci semble être au niveau de l'allocateur système. c'est une horreur à debugger.