Direkt zum Hauptinhalt

Proxmox Backup Server auf ZFS: Datastore voll („No space left on device“)

Symptom: Backups scheitern mit No space left on device (os error 28). Garbage Collection und Prune lassen sich nicht starten, nicht einmal der Datastore lässt sich löschen. Liegt der Datastore auf dem Root-Dateisystem, funktioniert der ganze PBS nicht mehr richtig: keine Aufgaben, keine Statistiken, kein Systemlog.

Warum: ZFS schreibt jede Änderung neu (Copy-on-Write). Auch Löschen braucht deshalb etwas freien Platz. Die Garbage Collection des PBS setzt außerdem bei jedem benutzten Chunk die Zugriffszeit, und das ist ebenfalls ein Schreibvorgang.

Auf keinen Fall:
  • Dateien in .chunks/ von Hand löschen. Chunks werden über alle Backups hinweg geteilt, damit machst du beliebige Backups kaputt.
  • Zum Überbrücken mit zpool add eine Platte anhängen. Bei RAIDZ lässt sie sich nie wieder entfernen.
  • Den Datastore löschen, solange es noch einen anderen Weg gibt.

1. Lage erfassen (nur lesen)

zpool list
zfs list -o space
zfs list -t snapshot
df -h /
cat /etc/proxmox-backup/datastore.cfg          # wo liegt der Datastore (path)?
cat /etc/proxmox-backup/prune.cfg
cat /PFAD-ZUM-DATASTORE/.gc-status             # letzte GC: "pending-bytes" = wartet aufs Löschen
cat /sys/module/zfs/parameters/spa_slop_shift  # meist 5

Darauf achten:

  • Liegt der Datastore auf dem System-Pool (rpool, Pfad wie /backup auf /)?
  • Gibt es einen ungenutzten Pool?
  • Wie hoch ist pending-bytes in .gc-status? So viel gibt die nächste erfolgreiche GC ohne weiteres Zutun frei.
  • Wann sind die neuesten Backups (ls /PFAD/vm/*/ | tail)? Ein voller Speicher fällt oft erst nach Wochen auf.

2. Luft schaffen: ZFS-Reserve vorübergehend verkleinern

ZFS hält etwa 1/2spa_slop_shift des Pools zurück, beim Standardwert 5 also 1/32. Ein höherer Wert verkleinert diese Reserve und gibt sofort Platz frei. Die Änderung gilt nur bis zum nächsten Neustart.

echo 8 > /sys/module/zfs/parameters/spa_slop_shift   # Reserve 1/256 statt 1/32
df -h /                                               # sollte jetzt Platz zeigen

Beispiel: Bei einem Pool mit 2,9 TB wurden so 70 GB frei.

Gibt es ZFS-Snapshots auf dem Pool, sind sie die zweite schnelle Quelle für Platz (zfs destroy pool/dataset@snap, nur nach Prüfung). Auf rpool helfen außerdem journalctl --vacuum-size=100M und apt clean.

3. Garbage Collection laufen lassen

nohup proxmox-backup-manager garbage-collection start DATASTORE > /root/gc_$(date +%Y%m%d_%H%M).log 2>&1 &
tail -f /root/gc_*.log

Die GC löscht alles, was in pending-bytes stand. Im Beispiel waren das 252 GB bei rund einer Million Chunks, in etwa 2 Minuten.

Danach die Reserve sofort zurückstellen:

echo 5 > /sys/module/zfs/parameters/spa_slop_shift

4. Aufbewahrung herunterstellen und Prune ausführen

Neue Keep-Regeln setzen (siehe Anleitung „Aufbewahrung und Zeitpläne“). Vorher mit dem Probelauf (--dry-run) prüfen, was wegfallen würde. Dann:

proxmox-backup-manager prune-job update JOB-ID --keep-hourly 12 --keep-daily 14 --keep-weekly 4 \
  --delete keep-monthly --delete keep-yearly
proxmox-backup-manager prune-job run JOB-ID

Prune entscheidet nur, welche Backups wegfallen. Den Platz gibt erst die nächste GC frei, und dabei gibt es einen Haken:

5. Die 24-Stunden-Schutzfrist der GC

Die GC löscht nur Chunks, deren Zugriffszeit älter als 24 Stunden und 5 Minuten ist. Hat eine GC die Chunks gerade erst angefasst (Schritt 3), bleiben die Chunks, die der Prune freigegeben hat, einen Tag lang stehen. Die GC meldet dann Removed garbage: 0 B und Pending removals: … GiB.

Vorziehen (ab PBS 3.4): Die Schutzfrist lässt sich pro Datastore kurz verkürzen.

Die Schutzfrist bewahrt die Chunks gerade laufender Backups, deren Index noch nicht geschrieben ist. Läuft während einer GC mit verkürzter Frist ein Backup, kann dieses Backup kaputtgehen. Deshalb: vorher prüfen, dass keine Aufgabe läuft, und sicherstellen, dass in den nächsten Minuten kein Backup-Job startet.
cat /var/log/proxmox-backup/tasks/active                      # muss leer sein
proxmox-backup-manager datastore update DATASTORE --tuning 'gc-atime-cutoff=10'   # 10 Minuten
proxmox-backup-manager garbage-collection start DATASTORE
proxmox-backup-manager datastore update DATASTORE --delete tuning                 # ZURÜCK auf Standard!

Im Beispiel wurden dadurch sofort weitere 331 GiB frei. Die Belegung fiel von 100 % auf 80 %.

6. Danach

  • Backups wieder anwerfen. Prüfen, ob die Jobs im PVE aktiviert sind. Einmal „Run now“, dann kontrollieren, ob alle VMs ankommen. VMs, die zwischendurch dazukamen, haben oft noch nie ein Backup.
  • Verify über alles laufen lassen. Prüfungen, die bei vollem Speicher liefen, sind oft als fehlgeschlagen markiert.
  • Zeitpläne entzerren: Backups, dann Prune (01:00), dann GC (02:00).
  • Überwachung einrichten: eine Mail bei fehlgeschlagenem Backup und eine Warnung ab 80 % Belegung.
  • Strukturell: Liegt der Datastore auf dem System-Pool, kann ein voller Datastore den ganzen PBS lahmlegen. Wenn möglich, gehört der Datastore auf einen eigenen Pool oder ein eigenes Dataset mit quota, damit für das System immer Platz bleibt:
    zfs create -o quota=2.5T rpool/pbs-store   # Beispiel: Datastore begrenzt, System behält Luft

Kurzfassung

  1. echo 8 > /sys/module/zfs/parameters/spa_slop_shift
  2. proxmox-backup-manager garbage-collection start DATASTORE
  3. echo 5 > /sys/module/zfs/parameters/spa_slop_shift
  4. Keep-Regeln senken, Probelauf, Prune ausführen
  5. Optional mit Vorsicht: gc-atime-cutoff kurz senken, GC, Tuning wieder löschen
  6. Backups, Verify, Zeitpläne und Überwachung kontrollieren