Hallo,
Ich weiß nicht, ob ich der Einzige bin, aber ich habe regelmäßig OOM-Fehler, wenn ich Gladys 8 GB zuweise. Dadurch startet Gladys jede Nacht neu.
Nach Tagen des Debuggens, ohne die Ursache zu verstehen, habe ich Claude verwendet, um voranzukommen und eine bessere Hypothese zu identifizieren. Und in den folgenden Tagen wurde das Problem identifiziert: die Art und Weise, wie die Datenbank gesichert wird.
Kontext: Ich speichere alle Zustände unendlich lange, solange ich Festplattenspeicher habe.
Bin ich der Einzige, dem das passiert?
Fehler: Der Backup-Gateway kann einen OOM-Kill des Node-Prozesses verursachen
Betroffene Komponenten:
server/lib/gateway/gateway.backup.js
server/models/index.js (Funktion duckDbCreateBackupInstance)
Das Problem: duckDbCreateBackupInstance() öffnet eine separate DuckDB-Instanz auf derselben .duckdb-Datei wie die Hauptinstanz (bereits aktiv im Lese-/Schreibmodus):
const backupDatabase = await DuckDBInstance.create(duckDbFilePath, {
memory_limit: duckDbMemoryLimit,
access_mode: 'READ_ONLY',
});
Die offizielle Dokumentation des Node.js-Clients „Neo“ von DuckDB sagt jedoch ausdrücklich:
« Mehrere Instanzen im selben Prozess sollten nicht dieselbe Datenbank anhängen. »
Der vorgesehene Mechanismus, um dies zu vermeiden, ist DuckDBInstanceCache.getOrCreateInstance(path), der dieselbe Instanz (daher denselben Pufferpool / memory_limit) für dieselbe Datei wiederverwendet. Der aktuelle Code ruft DuckDBInstance.create() direkt auf, was zwei unabhängige Pufferpools erstellt, jeweils begrenzt auf denselben DUCKDB_MEMORY_LIMIT.
Ergebnis: Der schlechteste Speicherfall von DuckDB allein wird zu 2 × memory_limit statt 1 × memory_limit.
Verschlimmernd: Die DuckDB-Dokumentation weist auch darauf hin, dass memory_limit « nur für den Puffer-Manager gilt » — die Kompressionspuffer (COMPRESSION GZIP, das im EXPORT DATABASE verwendet wird) können zusätzlich zu dieser Grenze verbrauchen.
Beweis in der Produktion (2 identische Abstürze, Logs als Beweis):
- RSS stabil ~2,5 GB vor dem Backup (davon ~1,2 GB BASE_TABLE DuckDB)
- Übergang zu ~4,6 GB in weniger als einer Minute, direkt nach dem Log « Backing up DuckDB into a Parquet folder »
- Prozess getötet (ExitCode=137) bevor der Log « Closing DuckDB backup instance to release memory » im finally erreicht wird — daher tritt der Absturz tatsächlich während des Aufrufs EXPORT DATABASE … FORMAT PARQUET COMPRESSION GZIP auf, nicht danach.
- Reproduziert identisch zwei Tage hintereinander, immer zur Zeit des täglichen Gateway-Backups.
Was gefordert wird:
- Stellen Sie sicher, dass duckDbCreateBackupInstance() DuckDBInstanceCache.getOrCreateInstance() verwendet, anstatt DuckDBInstance.create(), damit das Backup den Pufferpool der Hauptinstanz teilt, anstatt einen zweiten zu öffnen.
- Überlegen Sie, COMPRESSION GZIP durch ZSTD oder SNAPPY im EXPORT DATABASE zu ersetzen (weniger Kompressionspuffer, schnellerer Export).
- Eventuell dokumentieren, dass DUCKDB_MEMORY_LIMIT so dimensioniert werden muss, dass zwei Instanzen während eines Backups koexistieren können (daher eine empfohlene Größe ≤ 25% des dem Container zugewiesenen RAMs, nicht 30-50%), solange Punkt 1 nicht behoben ist.
Kontext zur Einordnung der Auswirkungen: Installation mit ~8 GB, die dem Container zugewiesen sind, BASE_TABLE mit etwa 1,1-1,2 GB Sensorgeschichte — also kein extremer Fall, dieses Verhalten kann wahrscheinlich auch andere Installationen mit einer erheblichen Historie betreffen.







