Enterprise-Backup-, Recovery-, Verification-, Security- und Monitoring-Plattform fuer Proxmox VE, Windows, Linux und Dateisysteme. Der Leitsatz, der fast jede Entscheidung erklaert: Ein Backup gilt erst als vertrauenswuerdig, wenn Integritaet geprueft und Wiederherstellbarkeit nachgewiesen wurde. Deshalb steigt ein Wiederherstellungspunkt erst nach einem tatsaechlich durchgefuehrten Restore-Test auf "recoverable", und Unbekanntes geht in keine Bewertung als "gut" ein. Umfang (Phasen 0-23): - Repository Engine: inhaltsadressierte Bloecke, atomares Commit-Protokoll, Katalogaufbau allein aus den Manifesten — ohne Datenbank - Backup Engine: inhaltsabhaengiges Chunking, Deduplizierung trotz Verschluesselung, zstd, AES-256-GCM, Streaming mit Gegendruck - Agenten fuer Windows und Linux mit Auftragsabholung (Pull-Modell) - Proxmox-Provider mit beiden Zugriffswegen auf die Sicherungsarchive - Scheduler, Recovery Engine mit Pruefpunkt, Verification, Unveraenderlichkeit - Weboberflaeche, Kennzahlen, Meldungen, Berichte, Security Center, Ransomware-Heuristik (meldet, handelt nie) - Disaster Recovery, Haertung, Leistungsmessung, Chaos Testing - Eingefrorene Vertraege fuer API, Migrationen, Backup-Format und Repository - Auslieferungspaket fuer linux/amd64, linux/arm64 und windows/amd64 Nicht enthalten und als solches gekennzeichnet: Kapazitaetsprognose, Backup Copy, Changed Block Tracking bei Proxmox, erweiterte Attribute und ACLs. Gebaut, aber nie auf echter Hardware gefahren: der Windows-Dienst, die systemd-Einheit und der verpflichtende Proxmox-Meilenstein — ob eine wiederhergestellte VM startet, ist ungeprueft. Einzelheiten in CHANGELOG.md und docs/release-candidate.md. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
154 lines
6.2 KiB
Markdown
154 lines
6.2 KiB
Markdown
# Chaos Testing (Phase 21)
|
|
|
|
Die Vorgabe des Plans (§23) steht in einem Satz:
|
|
|
|
> Every failure must produce a controlled result.
|
|
|
|
Das ist keine Aufforderung, Fehler zu vermeiden — Platten laufen voll,
|
|
Datenbanken fallen aus, Prozesse werden abgeschossen. Es ist die Aufforderung,
|
|
dass jeder dieser Fälle **vorhersagbar** endet.
|
|
|
|
## Was „kontrolliert" heißt
|
|
|
|
Vier Bedingungen, alle vier prüfbar, und **drei von vier genügen nicht**:
|
|
|
|
1. **Der Fehler wird gemeldet**, nicht verschluckt.
|
|
2. **Er ist klassifiziert** — sonst kann niemand entscheiden, ob eine
|
|
Wiederholung sinnvoll ist.
|
|
3. **Es bleibt kein sichtbares, unvollständiges Backup zurück.**
|
|
4. **Der Zustand danach ist konsistent.**
|
|
|
|
Die dritte ist die wichtigste. Ein abgebrochener Lauf, der nichts hinterlässt,
|
|
ist ein Ärgernis. Ein abgebrochener Lauf, der ein unvollständiges Backup als
|
|
gültig hinterlässt, ist ein Datenverlust mit Zeitzünder: Er fällt erst an dem
|
|
Tag auf, an dem jemand wiederherstellen will.
|
|
|
|
## Die neun Störungen
|
|
|
|
| Störung | Ergebnis | Wo nachgewiesen |
|
|
| --- | --- | --- |
|
|
| Prozess abgeschossen | kontrolliert | Phase 18, Szenario D |
|
|
| Dienst neu gestartet | kontrolliert | Phase 18 |
|
|
| Netz verloren | kontrolliert | Phase 5 (Agent-Backoff) |
|
|
| Repository nicht erreichbar | kontrolliert | Phase 14 (Meldungen) |
|
|
| **Datenbank nicht erreichbar** | **ein Fund** | hier |
|
|
| **Platte voll** | **ein Fund** | hier |
|
|
| Block beschädigt | kontrolliert | Phase 10 |
|
|
| Manifest beschädigt | kontrolliert | hier |
|
|
| Stromausfall | kontrolliert | Phase 2 (atomares Schreiben) |
|
|
|
|
## Platte voll — echtes Dateisystem, kein simulierter Fehler
|
|
|
|
Ein 40-MiB-Dateisystem per `hdiutil`, darin ein Repository, darauf eine Sicherung
|
|
von 120 MiB. Nach 33,8 MiB ist Schluss.
|
|
|
|
```
|
|
syncova-agent: die quelle "zu-gross.bin" konnte nicht gesichert werden:
|
|
der chunk konnte nicht geschrieben werden: … no space left on device
|
|
Exit-Status: 1
|
|
|
|
Manifeste (= sichtbare Backups): 0
|
|
Chunks: 32
|
|
Halbe Dateien (.tmp-*): 0
|
|
```
|
|
|
|
**Kontrolliert in allen vier Punkten.** Besonders: null Manifeste. Das Backup
|
|
wird erst mit dem Manifest sichtbar (Schritt 5 von 7 des Commit-Protokolls) — es
|
|
entsteht nie ein halbes, scheinbar gültiges Backup. Die 32 Blöcke bleiben
|
|
liegen und werden von einem späteren Lauf wiederverwendet; das ist gewollt.
|
|
|
|
### Der Fund: falsch klassifiziert und deshalb schädlich wiederholt
|
|
|
|
Der Schreibfehler kam als `ALL_SOURCES_FAILED` mit Klasse `source` an — und
|
|
`source` **wird wiederholt**.
|
|
|
|
Die Quelle ist aber in Ordnung; das Repository ist voll. Jeder Wiederholungslauf
|
|
legte weitere Blöcke ab und verschärfte die Lage. Ein Fehler, der falsch
|
|
klassifiziert wird, führt hier nicht nur zu einem sinnlosen, sondern zu einem
|
|
**schädlichen** Versuch.
|
|
|
|
Jetzt erkennt der Executor `ENOSPC` und meldet:
|
|
|
|
```
|
|
REPOSITORY_FULL (Klasse: configuration — nicht wiederholbar)
|
|
Im Repository ist kein Platz mehr. Der Lauf wird nicht wiederholt: Ein neuer
|
|
Versuch legte weitere Blöcke ab und verschärfte die Lage. Schaffen Sie Platz —
|
|
über eine Aufbewahrungsregel oder mehr Speicher.
|
|
```
|
|
|
|
Die Erkennung läuft über den Fehlerwert des Betriebssystems, nicht über den
|
|
Meldungstext: Ein Textvergleich bräche bei der ersten übersetzten Fehlermeldung,
|
|
und zwar unbemerkt. Ein Test prüft, dass `ENOSPC` die vierfache
|
|
Fehlerverschachtelung von Repository über Engine und Agent bis zum Executor
|
|
übersteht.
|
|
|
|
## Datenbank fällt im laufenden Betrieb aus
|
|
|
|
Container angehalten, Dienst läuft weiter.
|
|
|
|
```
|
|
/health/live: HTTP 200 ← prüft bewusst keine Abhängigkeiten
|
|
/health/ready: HTTP 503
|
|
GET /api/v1/health: 503 mit vollständigem Bericht im Datenteil
|
|
Dienstprozess: lebt
|
|
Erholung nach Rückkehr der Datenbank: 2 s, ohne Neustart
|
|
```
|
|
|
|
Genau das Verhalten, das Phase 0 entworfen hat: Liveness schaut nicht auf die
|
|
Datenbank — sonst löste eine kurz nicht erreichbare Datenbank einen
|
|
Prozessneustart aus und verschlimmerte den Ausfall.
|
|
|
|
### Der Fund: „Sitzung abgelaufen" statt „Datenbank weg"
|
|
|
|
Eine fachliche Anfrage mit gültigem Token meldete:
|
|
|
|
```
|
|
UNAUTHENTICATED — Die Sitzung ist abgelaufen. Bitte erneut anmelden.
|
|
```
|
|
|
|
Die Tokenprüfung braucht die Datenbank. Fällt sie aus, scheitert jede Prüfung —
|
|
und die Middleware deutete das als Anmeldeproblem. Der Betreiber meldet sich neu
|
|
an, was ebenfalls scheitert, und sucht den Fehler bei der Anmeldung statt bei der
|
|
Datenbank.
|
|
|
|
Nach der Definition oben: Der Fehler wurde zwar gemeldet, aber **falsch
|
|
klassifiziert** — also nicht kontrolliert. Jetzt:
|
|
|
|
```
|
|
SERVICE_UNAVAILABLE — Die Anmeldung lässt sich derzeit nicht prüfen:
|
|
Die Datenbank ist nicht erreichbar. Das ist kein Problem Ihrer Sitzung.
|
|
```
|
|
|
|
Auch hier über den Fehlerwert, nicht über den Text.
|
|
|
|
## Manifest beschädigt
|
|
|
|
Ein Byte gekippt, danach die Datei halbiert. Drei Zugriffswege, drei kontrollierte
|
|
Ergebnisse:
|
|
|
|
| Zugriff | Ergebnis |
|
|
| --- | --- |
|
|
| Integritätsprüfung | „Das Repository ist nicht vollständig wiederherstellbar", mit Empfehlung |
|
|
| Wiederherstellung | Bricht ab: „das manifest ist beschädigt" — **0 Dateien im Ziel** |
|
|
| Katalog-Neuaufbau | „Gefundene Backups: 0" — das beschädigte Manifest wird ausgeschlossen |
|
|
|
|
Der Katalog zeigte das Backup zunächst weiter an. Das ist richtig und kein
|
|
Mangel: Er ist ein Beschleuniger und wird nicht bei jeder Abfrage neu gebaut.
|
|
Verbindlich sind die Manifeste — und jeder Weg, der tatsächlich auf sie zugreift,
|
|
erkennt den Schaden.
|
|
|
|
## Bekannte Grenzen
|
|
|
|
- **Netzverlust wurde nicht neu ausgelöst.** Alle Repositories dieser Umgebung
|
|
sind lokal. Der Nachweis stammt aus Phase 5 (Agent-Backoff mit wachsender
|
|
Wartezeit) und Phase 18 (Abbruch mitten im Lauf, Fortsetzung am Prüfpunkt).
|
|
- **Der Stromausfall ist simuliert, nicht echt.** `SIGKILL` beendet den Prozess
|
|
ohne Aufräumen; das trifft den Anwendungsfall. Ein echter Stromausfall kann
|
|
zusätzlich den Schreibzwischenspeicher der Platte verlieren — dagegen steht das
|
|
`fsync` des Commit-Protokolls, aber nachgewiesen ist das hier nicht.
|
|
- **Die Störungen liefen einzeln.** Zwei gleichzeitig — volle Platte *und*
|
|
Datenbankausfall — wurden nicht geprüft.
|
|
- **Kein Dauerlauf.** Ein Chaos-Werkzeug, das über Stunden zufällige Störungen
|
|
auslöst, findet Fälle, die eine gezielte Prüfung nicht trifft. Das ist der
|
|
nächste Schritt, nicht dieser.
|