Gladys stürzt beim Speichern von GladysPlus ab

Ich habe seit mehreren Wochen Probleme mit meinem Gladys-Backup, aber ich hatte keine Zeit, die notwendigen Überprüfungen durchzuführen.

Tatsächlich blockiert Gladys jede Nacht, wenn das Backup ausgelöst wird (keine Dashboard-Anzeige mehr, keine Szenenauslösung, …), und das dauert etwa 2 Stunden. Dann erhalte ich in Telegram die Nachricht « Gladys wurde gerade neu gestartet » (das ist das Ergebnis einer Szene, die durch « Gladys startet » ausgelöst wird), und alles funktioniert wieder.

Mit Hilfe von Claude habe ich heute Morgen das Problem untersucht. Bei einem Schritt seiner Analyse habe ich geantwortet, dass ich « eine mittlere Datenbank (einige Gigas) » habe, aber ich bin mir nicht sicher, ob ich richtig geantwortet habe. In der Historie meiner Backups sehe ich das:

Als erste Maßnahme schlug Claude mir vor, den Gladys zugewiesenen RAM zu ändern (mit dem Befehl sudo docker update --memory="6g" --memory-swap="8g" gladys), damit mein Problem nicht mehr zu einer Blockade für mehrere Stunden führt. Und tatsächlich, als ich manuell ein Backup gestartet habe, erfolgte der Absturz und das Neustarten in 3-4 Minuten. Das ist besser, um meine Hausautomation nicht zu blockieren, aber es löst das Problem des fehlgeschlagenen Backups noch nicht :wink:

Ich nutze einen Intel NUC5PPYB Mini-PC, Prozessor N3700 4 Kerne 1.6GHz, 8GB RAM, unter Ubuntu 22.04, und Gladys wurde mit dem Standard-Befehl « docker run » installiert. Ich habe nichts anderes als Gladys auf diesem Server.

Hier ist der abschließende Bericht von Claude:

Speicherpeak / OOM-Kill während des GladysPlus-Backups

Zusammenfassung

Jedes GladysPlus-Backup (automatisch 2h-4h oder manuell) lässt den RAM des
Gladys-Containers so stark ansteigen, dass ein OOM-Kill des Node-Prozesses
ausgelöst wird, gefolgt von einem automatischen Neustart des Containers.

Umgebung

  • Gladys in Docker auf Mini-PC/NUC
  • Gesamter RAM des Hosts: 7,7 GB (8 GB nicht erweiterbar)
  • Datenbank: mittlere Größe (einige GB)
  • Container gladys manuell auf 6 GB RAM begrenzt (docker update --memory)
    um zu verhindern, dass der OOM den gesamten Host destabilisiert (Swap-Thrashing wurde vor
    der Einrichtung dieser Grenze beobachtet)

Reproduktion

Manuelles Backup ausgelöst um 09:36 Uhr.

  • 09:36:01 - RSS vor Backup: 4388,77 MB, Heap 233,97/392,50 MB
  • 09:36:01 - DuckDB vor Backup: Gesamt 2248,75 MB (BASE_TABLE: 2246,00 MB,
    IN_MEMORY_TABLE: 2,75 MB)
  • 09:36:04 - Öffnen einer zweiten DuckDB-Instanz, die dem Backup gewidmet ist
    (duckDbCreateBackupInstance, memory_limit=1024MB, threads=2, READ_ONLY)
    zum Exportieren in einen Parquet-Ordner
  • 09:38 - RAM des Containers: ~6 GB (Grenze erreicht)
  • 09:40 - Out of memory: Killed process ... (MainThread)
  • 09:41 - Container neu gestartet, Gladys wieder funktionsfähig

Ohne die manuell festgelegte 6-GB-Grenze auf Docker-Ebene hat derselbe Vorgang
unter realen Bedingungen (automatisches nächtliches Backup) einen Swap-Thrashing-Episoden
auf dem gesamten Host von 02:23 bis 04:44 (Dashboard und Szenen nicht nutzbar) verursacht,
der RSS des Prozesses hatte 6774,54 MB vor dem Kill erreicht (dmesg:
Out of memory: Killed process 1542 (MainThread) total-vm:30424440kB, anon-rss:6774536kB).

Hypothese

Die neue DuckDB-Instanz, die für das Backup erstellt wurde (begrenzt auf 1024 MB), scheint
sich zur bereits von der Haupt-DuckDB-Instanz belegten Speicher (ca. 2,25 GB) zu addieren,
statt einen globalen Speicherbudget des Prozesses zu teilen/respektieren. Auf einer Maschine, auf der der Prozess bereits mit ~4,4 GB im Leerlauf läuft, reicht die zusätzliche Belastung von
~1 GB aus, um den verfügbaren RAM zu überschreiten.

Frage an die Entwickler

  • Ist es normal, dass BASE_TABLE fast vollständig im Speicher bleibt (2,25 GB)
    im Leerlauf, außerhalb des Backups, für eine Datenbank mittlerer Größe?
  • Kann der memory_limit=1024MB der Backup-Instanz reduziert werden, oder kann der
    Backup-Prozess streamen/batchweise verarbeiten, anstatt so viel in den Speicher zu laden, um innerhalb einer vernünftigen Gesamtgröße zu bleiben, selbst auf Hardware mit 8 GB RAM?

@pierre-gilles ich bin mir nicht sicher, ob du Zeit haben wirst, dir das vor deinen Ferien anzusehen… Es kann bis zu deiner Rückkehr warten, falls es nicht möglich ist :wink:

Ich lasse @mutmut dir helfen :slight_smile: (oder jemand anderes!)

@StephaneB
Ich habe hier ein paar meiner Probleme: Migration intégration Netatmo : plantage de Gladys - #4 par mutmut
et dann hier: Surconsommation de mémoire par le backup de gateway? - #18 par mutmut

Bisher ist die einzige Lösung, die ich gefunden habe, um nicht mehr belästigt zu werden, den RAM zu erhöhen :confused:
Aber da es sich um ein Proxmox-Cluster handelt, wenn der Host abstürzt, wird der LXC mit Gladys auf einen anderen Host umgeschaltet, und dann habe ich Probleme mit dem geteilten RAM…
Jedenfalls, als es einfror, konnte ich die Situation lösen, indem ich den RAM live erhöhte (danke LXC!), und alle anstehenden Aufgaben wurden erfolgreich abgeschlossen.

Danke für dein Feedback @mutmut.

Ich habe gerade überprüft, meine DuckDB-Datenbank ist 8 GB groß. Und da ich leider keine RAM hinzufügen kann (8 GB max auf diesem Mini-PC), bin ich festgefahren…

Gibt es Dienste, von denen bekannt ist, dass sie RAM verbrauchen und die ich in der „Dienste“-Seite von Gladys stoppen könnte, um manuell ein Backup zu starten?

Okay, ich habe es geschafft, ein Backup zu erstellen, indem ich alle Dienste außer Node-Red und MQTT deaktiviert habe, da ich weiterhin den RAM- und CPU-Verbrauch verfolgen wollte, den ich in Node-Red laufen habe (ja, ich werde auf die externe Integration umstellen müssen…).

Das hat den RAM-Verbrauch um etwa -10% reduziert, von etwa 80% auf 70%. Dann habe ich manuell ein Backup gestartet. Gladys hat es nicht geschafft, OOM-Crash. Aber beim Neustart wurde nur etwa 10% des RAMs verwendet! Also habe ich sofort ein Backup ausgelöst, das erfolgreich war.

Daher habe ich alle Dienste neu gestartet und einen Neustart des Mini-PCs verursacht. Der RAM-Verbrauch stabilisierte sich bei etwa 20%, perfekt. Es war 19:20 Uhr.
Aber um 19:30 Uhr hatte ich einen CPU-Spitzenwert, aber vor allem einen Anstieg des RAM-Verbrauchs auf 60%, der seitdem nicht mehr gesunken ist!

Verbraucht die Energieverbrauchsberechnung viel RAM (warum nicht) und gibt sie nicht wieder frei?

Das ist kein Leak, sondern der Buffer Pool von DuckDB, der sich einmal füllt und nie an das Betriebssystem zurückgegeben wird.

DuckDB wird mit memory_limit = 30 % des RAM geöffnet (models/index.js:214). Sein Buffer-Manager nimmt den Speicher bis zu dieser Grenze beim ersten großen Scan und stößt ihn nur unter eigenem Druck aus, nie um die RAM an das Betriebssystem zurückzugeben.
20 % Basis + ~30 % Buffer Pool + der Node-Heap, der gewachsen ist ≈ die beobachteten 60 %. Der Job um 19:30 Uhr ist einfach der erste, der schwere Scans durchführt (getDeviceFeatureStates über einen weiten Bereich nach dem Neustart, plus das DELETE + Wiedereinsetzen von calculateCostFrom).

Du kannst sehen, wie viel DuckDB sich beim Start zuweist, mit diesem Befehl:
docker logs gladys 2>&1 | grep "DuckDB initialized with memory_limit"

Du kannst eine niedrigere Grenze mit der Variable DUCKDB_MEMORY_LIMIT=512MB in deinem docker-compose testen. Aber ich weiß nicht, ob das negative Auswirkungen auf den Rest haben kann.

Aber die zweite Instanz (die das Backup durchführt) kann unter dieser Nicht-Ausschleusung leiden.
Ich denke, man sollte den Hauptpool während des Backups reduzieren (um die Ausschleusung zu erzwingen und Platz für das Backup zu lassen).
Das ist Entwicklung, die gemacht werden muss.