Gladys se bloquea al guardar GladysPlus

Llevo varias semanas con problemas con mi copia de seguridad de Gladys, pero no había tenido tiempo de hacer las comprobaciones necesarias.

De hecho, cada noche cuando se activa la copia de seguridad, Gladys se bloquea (no hay visualización del panel de control, no se activan escenas, etc.), esto dura aproximadamente 2 horas, luego recibo en Telegram el mensaje « Gladys acaba de reiniciarse » (es el resultado de una escena cuyo disparador es « Gladys arranca »), y todo funciona de nuevo.

Con la ayuda de Claude esta mañana, exploré el problema. En un paso de su análisis, respondí que tenía « una base media (algunos gigas) », pero no estoy seguro de haber respondido correctamente. En el historial de mis copias de seguridad, veo esto:

Como primera acción, Claude me sugirió modificar la RAM asignada a Gladys (con el comando sudo docker update --memory="6g" --memory-swap="8g" gladys), para que mi problema no provoque un bloqueo durante varias horas. Y efectivamente, cuando inicié manualmente una copia de seguridad, el fallo y el reinicio se produjeron en 3-4 minutos. Es mejor para no bloquear mi domótica, pero aún no resuelve el problema de la copia de seguridad fallida :wink:

Estoy ejecutando en un mini-PC Intel NUC5PPYB, procesador N3700 4 núcleos 1.6GHz, 8GB de RAM, bajo Ubuntu 22.04, y Gladys se instaló con el comando « docker run » estándar. No tengo nada más que Gladys en este servidor.

Aquí está el informe final de Claude:

Pico de memoria / OOM-kill durante la copia de seguridad GladysPlus

Resumen

Cada copia de seguridad GladysPlus (automática 2h-4h o manual) hace que la RAM del
contenedor Gladys aumente hasta el punto de desencadenar un OOM-kill del proceso Node, seguido de un
reinicio automático del contenedor.

Entorno

  • Gladys en Docker en Mini PC/NUC
  • RAM total del host: 7,7 GB (8 GB no ampliable)
  • Base de datos: tamaño medio (algunos GB)
  • Contenedor gladys limitado manualmente a 6 GB de RAM (docker update --memory)
    para evitar que el OOM desestabilice todo el host (swap-thrashing observado antes
    de la implementación de este límite)

Reproducción

Copia de seguridad manual iniciada a las 09:36.

  • 09:36:01 - RSS antes del backup: 4388,77 MB, Heap 233,97/392,50 MB
  • 09:36:01 - DuckDB antes del backup: Total 2248,75 MB (BASE_TABLE: 2246,00 MB,
    IN_MEMORY_TABLE: 2,75 MB)
  • 09:36:04 - Apertura de una segunda instancia DuckDB dedicada al backup
    (duckDbCreateBackupInstance, memory_limit=1024MB, threads=2, READ_ONLY)
    para exportar a una carpeta Parquet
  • 09:38 - RAM del contenedor: ~6 GB (límite alcanzado)
  • 09:40 - Out of memory: Killed process ... (MainThread)
  • 09:41 - Contenedor reiniciado, Gladys de nuevo funcional

Sin el límite de 6 GB establecido manualmente a nivel Docker, el mismo fenómeno en
condiciones reales (copia de seguridad nocturna automática) provocó un episodio de
swap-thrashing en todo el host de 02:23 a 04:44 (panel de control y escenas
inutilizables), el RSS del proceso alcanzó 6774,54 MB antes del kill (dmesg :
Out of memory: Killed process 1542 (MainThread) total-vm:30424440kB, anon-rss:6774536kB).

Hipótesis

La nueva instancia DuckDB creada para el backup (limitada a 1024 MB) parece
sumarse a la memoria ya ocupada por la instancia DuckDB principal
(~2,25 GB), en lugar de compartir/respetar un presupuesto de memoria global del proceso.
En una máquina donde el proceso ya funciona a ~4,4 GB en reposo, la adición de
~1 GB adicional es suficiente para superar la RAM disponible.

Pregunta para los mantenedores

  • ¿Es normal que BASE_TABLE permanezca casi íntegramente en memoria (2,25 GB)
    en reposo, fuera de la copia de seguridad, para una base de tamaño medio ?
  • ¿Se puede reducir el memory_limit=1024MB de la instancia de backup, o el
    proceso de backup puede transmitir/procesar por lotes en lugar de cargar tanto
    en memoria, para mantenerse dentro de un límite total razonable incluso en hardware con
    8 GB de RAM ?

@pierre-gilles no estoy seguro de que tengas tiempo de mirar esto antes de tus vacaciones… Si no es posible, puede esperar a tu regreso :wink:

Dejo que @mutmut te ayude :slight_smile: (¡o alguien más!)

@StephaneB
Tengo un poco de mis problemas aquí: Migration intégration Netatmo : plantage de Gladys - #4 par mutmut
y luego aquí: Surconsommation de mémoire par le backup de gateway? - #18 par mutmut

Por ahora, la única solución que he encontrado para no tener más problemas es aumentar la RAM :confused:
Pero como es un clúster de Proxmox, si el host falla, el contenedor LXC con Gladys se trasladará a otro host y ahí podría tener problemas de RAM compartida…
En cualquier caso, cuando se congelaba, podía desbloquear la situación aumentando la RAM en vivo (¡gracias a los LXC!), y todas las tareas pendientes se completaron correctamente.

Gracias por tu respuesta @mutmut.

Acabo de verificar, mi base de datos duckdb tiene 8 GB. Y como, lamentablemente, no puedo añadir más RAM (máximo 8 GB en este mini PC), estoy atascado…

¿Hay algún servicio que sepa que consume RAM y que pueda detener en la página ‹ servicios › de Gladys, el tiempo suficiente para lanzar manualmente una copia de seguridad?

Bueno, logré hacer una copia de seguridad deteniendo todos los servicios excepto node-red y mqtt, porque quería seguir rastreando el uso de RAM y CPU que ejecuto en Node-Red (sí, tendré que migrar a la integración externa…).

Esto redujo el uso de RAM en aproximadamente un 10%, pasando de alrededor del 80% al 70%. Luego, inicié manualmente una copia de seguridad. Gladys no pudo manejarlo, se estrelló por falta de memoria. Pero al reiniciar, la RAM solo se utilizaba al 10% aproximadamente. Por lo tanto, inmediatamente inicié una copia de seguridad que se realizó correctamente.

A continuación, reinicié todos los servicios y provoqué un reinicio del mini-PC. El uso de RAM se estabilizó alrededor del 20%, genial. Eran las 19:20.
Sin embargo, a las 19:30, tuve un pico de CPU, pero sobre todo un aumento en el uso de RAM al 60%, que no ha bajado desde entonces.

¿Es el cálculo del seguimiento de energía el que consume mucha RAM (¿por qué no?) pero ‹ no la libera ›?

No es una fuga, es el buffer pool de DuckDB que se llena una vez y nunca se devuelve al sistema operativo.

DuckDB se abre con memory_limit = 30 % de la RAM (models/index.js:214). Su administrador de búferes toma la memoria hasta este límite en el primer escaneo grande y no la expulsa a menos que haya presión propia, nunca para devolver la RAM al sistema operativo.
20 % base + ~30 % de buffer pool + el heap de Node que ha crecido ≈ los 60 % observados. El trabajo de las 19:30 es simplemente el primero en hacer escaneos pesados (getDeviceFeatureStates en un rango amplio después del reinicio, más el DELETE + reinserción de calculateCostFrom).

Puedes ver cuánto se asigna DuckDB al inicio con este comando:
docker logs gladys 2>&1 | grep "DuckDB initialized with memory_limit"

Puedes probar un límite más bajo con la variable DUCKDB_MEMORY_LIMIT=512MB en tu docker-compose. Pero no sé si esto puede tener impactos negativos en el resto.

Pero la segunda instancia (la que hace la copia de seguridad) puede sufrir por esta no expulsión.
Creo que sería necesario reducir el pool principal durante la copia de seguridad (para forzar la expulsión y dejar espacio para la copia de seguridad).
Es desarrollo a hacer