Ein Backup-Job meldet Erfolg, doch bei der Wiederherstellung lassen sich Dateien nicht mehr lesen: Die Ursache kann ein Speicherschaden sein, der erst nach Abschluss der Sicherung aufgetreten ist. Die Anzahl der Snapshots zu kontrollieren, hilft bei der Frage, ob der Job ausgeführt wurde. Die Unversehrtheit der Datenpakete lässt sich damit jedoch nicht belegen. Speicheradministratoren benötigen drei voneinander unabhängige Nachweise: Die Repository-Struktur ist korrekt, sämtliche Daten lassen sich lesen und die wiederhergestellten Inhalte stimmen mit der Referenz überein.
Dieser Artikel verwendet Debian 12, restic und Python 3, um in einem temporären Verzeichnis sowohl ein intaktes Repository zu prüfen als auch Schäden nachzuweisen. Dabei werden weder Produktivdaten gelesen noch Datenträger formatiert oder bestehende Backup-Repositories verändert. Das Verfahren eignet sich für dateibasierte Backups auf Dedicated Servern. Bei laufenden Datenbanken muss zunächst mit den datenbankeigenen Mechanismen eine konsistente Sicherung erstellt werden, die anschließend in das Dateibackup eingeht.
1. Zunächst klären, was die Prüfungen tatsächlich nachweisen
restic organisiert Dateiinhalte in verschlüsselten Datenpaketen und verwaltet Snapshots, Indizes sowie deren Referenzen. Ein gewöhnlicher Aufruf von check prüft vor allem die Repository-Struktur. check --read-data liest und überprüft zusätzlich sämtliche Datenpakete. Die beiden Prüfungen sind nicht austauschbar; auch ein Wiederherstellungstest bleibt erforderlich.
Beim Vergleich nach einer Wiederherstellung geht es darum, ob sich aus dem ausgewählten Snapshot die erwarteten Dateien in einem leeren Verzeichnis rekonstruieren lassen. Er belegt nicht, dass jedes historische Datenpaket im Repository intakt ist. Umgekehrt beweist ein erfolgreicher vollständiger Lesetest weder, dass beim Backup die richtigen Verzeichnisse ausgewählt wurden, noch, dass Ausschlussregeln keine benötigten Daten erfasst haben oder die Anwendungsdaten selbst konsistent waren.
Spiegelung ermöglicht bei bestimmten Geräteausfällen den fortgesetzten Zugriff, Backups bewahren historische Versionen und Integritätsprüfungen erkennen Unregelmäßigkeiten. Keine dieser Maßnahmen ersetzt eine tatsächliche Wiederherstellung.
Die AMD Dedicated Server von OnuCloud sind standardmäßig mit zwei direkt angebundenen NVMe-Laufwerken mit jeweils 1TB ausgestattet, ohne Hardware-RAID. Liegen Quellverzeichnis und Backup-Repository auf den beiden getrennten Laufwerken desselben Servers, lassen sich bestimmte Auswirkungen eines einzelnen Laufwerksausfalls voneinander abgrenzen. Ein externes Backup in einer unabhängigen Ausfalldomäne ist das jedoch nicht. Das folgende lokale Repository dient ausschließlich dazu, den Ablauf zu überprüfen.
2. Einen reproduzierbaren, isolierten Testbestand anlegen
Installieren Sie zunächst die Werkzeuge. Führen Sie die anschließenden Testbefehle in derselben Bash-Sitzung aus, damit die temporären Variablen erhalten bleiben. Die Installation erfordert Administratorrechte; für den eigentlichen Test genügt ein normales Benutzerkonto.
sudo apt-get update
sudo apt-get install restic python3
umask 077
LAB=$(mktemp -d /var/tmp/restic-lab.XXXXXXXX)
export LAB
export RESTIC_REPOSITORY="$LAB/repository"
export RESTIC_PASSWORD_FILE="$LAB/password"
mkdir -p "$LAB/source"
python3 - <<'PY'
import os
import secrets
from pathlib import Path
root = Path(os.environ["LAB"])
(root / "password").write_text(secrets.token_hex(32) + "\n")
(root / "source" / "record.txt").write_text(
"backup verification\n", encoding="utf-8"
)
(root / "source" / "payload.bin").write_bytes(os.urandom(1024 * 1024))
PY
restic version
restic init
(
cd "$LAB"
restic backup source
)
restic snapshots
Die Zufallsdatei verhindert, dass sich der gesamte Testbestand auf eine sehr kleine Datenmenge komprimieren lässt, und sorgt dafür, dass das Repository tatsächlich Dateninhalt enthält. Die Passwortdatei liegt außerhalb des Repository-Verzeichnisses. Beim Kopieren des Repositorys werden die Zugangsdaten zur Entschlüsselung daher nicht mitkopiert.
Da hier nur ein Snapshot vorhanden ist, kann im weiteren Verlauf latest verwendet werden. In Produktivumgebungen sollte eine konkrete Snapshot-ID festgehalten werden. Andernfalls kann sich das Wiederherstellungsziel ändern, wenn während der Prüfung ein neues Backup abgeschlossen wird. Das temporäre Testpasswort ist außerdem kein Ersatz für eine geregelte Schlüsselverwahrung: Die Zugangsdaten zur Entschlüsselung eines produktiven Repositorys müssen separat aufbewahrt werden und zuverlässig abrufbar sein.
3. Vollständiges Lesen und wiederhergestellte Inhalte getrennt abnehmen
Prüfen Sie zuerst die Struktur und lesen Sie anschließend sämtliche Datenpakete. Leiten Sie die Ausgabe nicht direkt in eine Pipeline, deren Exitcodes nicht ausdrücklich ausgewertet werden. Sonst kann ein erfolgreicher letzter Befehl einen vorherigen Prüffehler verdecken.
restic check
restic check --read-data
restic restore latest --target "$LAB/restored"
diff -r -- "$LAB/source" "$LAB/restored/source"
Alle vier Schritte müssen mit Exitcode null enden. Bei übereinstimmenden Inhalten gibt diff keine Unterschiede aus. Der Testbestand enthält ausschließlich reguläre Dateien, daher genügt hier ein Vergleich der Inhalte und Verzeichnisse. Bei echten Backups müssen zusätzlich Eigentümer, Berechtigungen, Verknüpfungsbeziehungen und die von der Anwendung benötigten erweiterten Attribute geprüft werden.
Die Wiederherstellung muss in ein neues, leeres Verzeichnis erfolgen und darf keine Quelldateien überschreiben. Vorhandene Dateien könnten sonst fehlende Sicherungsinhalte verdecken; neu wiederhergestellte Daten könnten wiederum produktive Verzeichnisse verändern. Bewahren Sie anschließend Snapshot-ID, Werkzeugversionen, Prüfausgaben und Vergleichsergebnisse auf. Ein einzelner Screenshot mit der Meldung „Job erfolgreich“ reicht nicht aus, um später nachzuvollziehen, welches Objekt tatsächlich wiederhergestellt wurde.
Schlägt bereits check fehl, brechen Sie die weitere reguläre Abnahme ab und sichern Sie den vorgefundenen Zustand. Ist die Strukturprüfung erfolgreich, der vollständige Lesetest aber nicht, sollten die Lesbarkeit und Integrität der Datenpakete im Mittelpunkt der Untersuchung stehen. Eine unauffällige Snapshot-Liste ist kein Grund, das Repository trotzdem weiterzuverwenden.
4. Nur eine Kopie beschädigen und die Erkennung bestätigen
Der Negativtest soll belegen, dass die Prüfkette Fehler tatsächlich erkennt. Beenden Sie zunächst alle Schreibzugriffe auf das Test-Repository und erstellen Sie anschließend eine unabhängige Kopie. Verwenden Sie keine Hardlinks: Änderungen an der Kopie könnten sonst zugleich das ursprüngliche Repository verändern. Der folgende Befehl deaktiviert Copy-on-Write ausdrücklich. Der kleine Testbestand macht die Trennung zwischen den beiden Datenbeständen leicht nachvollziehbar.
cp -a --reflink=never "$LAB/repository" "$LAB/damaged"
python3 - <<'PY'
import os
from pathlib import Path
data = Path(os.environ["LAB"]) / "damaged" / "data"
pack = next(p for p in sorted(data.rglob("*")) if p.is_file())
with pack.open("r+b") as f:
f.seek(pack.stat().st_size // 2)
pos = f.tell()
original = f.read(1)
if not original:
raise RuntimeError("Empty data pack")
f.seek(pos)
f.write(bytes([original[0] ^ 1]))
print(pack.name)
PY
if restic -r "$LAB/damaged" check --read-data \
>"$LAB/damaged-check.log" 2>&1; then
printf '%s\n' 'UNEXPECTED_SUCCESS'
else
printf '%s\n' 'EXPECTED_FAILURE'
fi
cat "$LAB/damaged-check.log"
restic check --read-data
Erwartet wird, dass die Prüfung der Kopie mit einem Exitcode ungleich null endet und das Protokoll auf ein beschädigtes Datenpaket hinweist. Die Prüfung des ursprünglichen Repositorys muss weiterhin erfolgreich sein. Verlassen Sie sich nicht allein auf die vom Skript ausgegebene Fehlermarkierung. Prüfen Sie auch, ob tatsächlich die Beschädigung die Ursache ist und nicht etwa ein falsches Passwort, ein falscher Pfad oder fehlende Berechtigungen.
Dieser Schritt weist nach, dass ein Schaden erkannt werden kann, nicht, dass er sich reparieren lässt. Die Änderung eines einzelnen Bytes in einem Datenpaket kann ein oder mehrere darin enthaltene Objekte betreffen. Daraus lässt sich kein Anteil betroffener Daten bei einem produktiven Vorfall ableiten. Verwenden Sie die beschädigte Kopie auch nicht erneut als Backup-Ziel.
5. Aus dem Test klare Grenzen für Produktionsprüfungen ableiten
Ein vollständiger Lesetest beansprucht den Datenträgerdurchsatz und bei entfernten Repositories zusätzlich Netzwerkbandbreite. Dokumentieren Sie vor Beginn die Repository-Größe, den Prüfumfang und die produktive Last. Wählen Sie ein Zeitfenster mit geringer Auslastung und beobachten Sie die Latenz der produktiven Dienste. Unbegrenztes Transfervolumen bedeutet weder unbegrenzte Übertragungsgeschwindigkeit noch einen Integritätsscan ohne Ressourcenverbrauch.
Bei großen Repositories können Datenpakete in mehreren Durchläufen gelesen werden. Dafür muss der jeweilige Abdeckungsbereich dokumentiert werden, damit am Ende alle Daten erfasst sind. Eine erfolgreiche Stichprobe darf nicht als erfolgreiche Prüfung des gesamten Repositorys ausgewiesen werden. Prüfjobs sollten außerdem nicht ungeplant gleichzeitig mit Bereinigungen, Reparaturen oder anderen Vorgängen laufen, die den Repository-Inhalt verändern.
Wird ein Schaden entdeckt, pausieren Sie zunächst alle Jobs, die das Repository verändern. Sichern Sie Protokolle und Kopien und untersuchen Sie danach Dateisystem, Geräte und Übertragungsweg. Führen Sie nicht sofort forget, prune oder Reparaturbefehle aus, da dadurch für eine Wiederherstellung relevante Belege verloren gehen könnten.
Für die abschließende Abnahme müssen drei Ergebnisse vorliegen: Das intakte Repository lässt sich vollständig lesen, der festgelegte Snapshot lässt sich wiederherstellen und besteht den Inhaltsvergleich, und die beschädigte Kopie wird eindeutig zurückgewiesen. Nach dem Sichern der Aufzeichnungen können die Testdateien gelöscht werden, nachdem die Pfade manuell geprüft wurden. Passwörter, Protokolle und wiederhergestellte Testdaten müssen dabei kontrolliert behandelt werden.
Häufig gestellte Fragen
Liest restic check sämtliche gesicherten Daten?
Nein. Der normale Aufruf prüft vor allem Struktur und Referenzen. Erst --read-data liest und prüft alle Datenpakete. Eine isolierte Wiederherstellung mit Inhaltsvergleich bleibt ein eigener Test.
Soll ein beschädigtes Repository sofort bereinigt werden?
Nein. Zuerst schreibende Aufgaben pausieren, Protokolle und eine Repository-Kopie sichern und den Speicher- sowie Übertragungsweg untersuchen. forget, prune und Reparaturen nicht unvorbereitet ausführen.
AMD EPYC 7543P Dedicated Server
ab $472/Monat