Optionale Schreibpufferung: Write-behind#

Standardmäßig ist jeder Schreibzugriff live: Die API wendet ihn in der Datenbank an und liefert danach IDs oder betroffene Zeilen. Write-behind ist optional. Es prüft Änderungen, schreibt sie in ein Journal und bestätigt zunächst queued. Die Datenbank wird später in Annahmereihenfolge aktualisiert.

Wann passt das?#

Für häufige Änderungen mit tolerierbarer Verzögerung, etwa Statistiken oder letzte Aktivität. Ungeeignet, wenn sofort eine generierte ID oder eine bestätigte Zeilenanzahl benötigt wird. Für Guthabenentscheidungen nicht allein auf einen Queue-Beleg vertrauen. Die Spielserver-Aufrufe sind bereits asynchron; Write-behind verändert vor allem Dauerhaftigkeit und Sichtbarkeit, nicht die C#-Aufrufsyntax.

Einschalten#

{
  "Ldb": {
    "WriteBehind": {
      "Enabled": true,
      "Namespaces": ["mygame"],
      "Operations": ["insert", "update", "upsert", "delete"],
      "FlushIntervalSeconds": 30,
      "FlushAt": ["04:00"],
      "TimeZone": "Europe/Berlin",
      "FlushThreshold": 1000,
      "JournalPath": "/data/write-behind.journal"
    }
  }
}

mygame durch deinen Namespace ersetzen. Unter Docker /data als dauerhaftes beschreibbares Volume einbinden. Umgebungsvariablen folgen z. B. LDB_Ldb__WriteBehind__Enabled=true und LDB_Ldb__WriteBehind__FlushAt__0=04:00.

Feld Standard Bedeutung
Enabled false Hauptschalter; aus bedeutet live
Namespaces [] Betroffene Namespaces; leer bedeutet alle
Operations alle vier Gepufferte Schreiboperationen
FlushIntervalSeconds 30 Intervall in Sekunden; 0 deaktiviert es
FlushAt [] Tageszeiten als HH:mm im 24-Stunden-Format
TimeZone UTC Zeitzone für feste Zeiten, z. B. Europe/Berlin
FlushThreshold 1000 Früher anwenden ab dieser Menge; 0 deaktiviert
MaxQueuedOperations 50000 Harte Anzahlgrenze
MaxQueuedBytes 67108864 Harte Nutzlastgrenze
JournalPath leer Dauerhafte Datei; leer bedeutet nur Arbeitsspeicher
JournalFsync true Vor Bestätigung auf Datenträger schreiben
OnError Skip Dauerfehler nach Dead Letter auslagern; Stop hält an
MaxRetries 5 Versuche bei vorübergehenden Datenbankfehlern
FlushBeforeRead false Vor Find/Count den Namespace leeren
ShutdownFlushSeconds 30 Wartezeit für Abschluss beim geordneten Stop

Ungültige Uhrzeit oder Zeitzone verhindert den Dienststart mit einer Fehlermeldung.

Antwort und Sichtbarkeit#

{"queued": true, "id": "receipt-id", "pending": 12}

id ist ein Beleg fürs Log, keine generierte Datensatz-ID. pending ist die Wartemenge. Eine Queue-Antwort hat keine endgültigen Insert-IDs oder betroffenen Zeilen. Schema, Pflichtwerte, Typen und Berechtigungen werden vor Annahme geprüft; Datenbankregeln wie Eindeutigkeit können trotzdem erst beim Flush scheitern.

Lesen sieht nur bereits angewendete Daten. Für unmittelbare Sichtbarkeit durability: "immediate" beziehungsweise im Bundle immediate: true verwenden oder vorher flushen. Ältere Änderungen des Namespaces werden vor einem Live-Schreibzugriff angewendet, damit die Reihenfolge erhalten bleibt.

Wann wird geflusht?#

Intervall, feste Tageszeiten, Mengenschwelle, explizites POST /v1/data/flush, Schemaänderungen, unmittelbare Schreibzugriffe und geordnetes Herunterfahren lösen Verarbeitung aus. Bei FlushBeforeRead auch Find/Count. Für ausschließlich zeitgesteuerte reguläre Hintergrundläufe Intervall und Schwelle auf 0 setzen; die anderen notwendigen Auslöser bleiben bestehen.

Flush-Nutzlast: {"namespace":"mygame"}. Der Key braucht Operation flush. Ergebnis:

{"flushed": 10, "deadLettered": 0, "remaining": 0, "halted": false, "enabled": true}

Nicht nur HTTP-Erfolg prüfen: halted, remaining und deadLettered entscheiden, ob die gewünschte Arbeit erledigt ist. Ohne aktiviertes Write-behind ist enabled: false. Ein fehlgeschlagenes notwendiges Flush blockiert Schemaänderung, unmittelbare Änderung oder konsistentes Lesen mit 503 write_buffer_halted.

Fehler und Wiederanlauf#

Situation Verhalten
Datenbank nicht erreichbar Mit Verzögerung wiederholen; danach pausieren und später erneut versuchen
Dauerhaft ungültige Änderung Bei Skip in <JournalPath>.dead, bei Stop am Warteschlangenanfang anhalten
Voller Puffer Neue Anfrage erhält 503 write_buffer_full
Journal nicht schreibbar 503 write_buffer_unavailable; nicht angenommen
Prozessabsturz Journal beim Neustart einlesen; ohne Journal gehen ausstehende Änderungen verloren
Geordneter Stop Abschließendes Flush; Rest bleibt im Journal

Die Zustellung ist mindestens einmal, nicht exakt einmal. Ein Absturz nach Datenbankbestätigung, aber vor Journalabschluss kann eine Änderung erneut ausführen. Stabile eindeutige Schlüssel und idempotentes Setzen/Upsert bevorzugen; inc kann doppelt zählen.

SQL-Provider können aufeinanderfolgende Inserts in dieselbe Tabelle bündeln. MongoDB bündelt getrennte Requests nicht, weil mehrzeilige Inserts teilweise erfolgreich sein können. Auch ein einzelner mehrzeiliger MongoDB-Request kann bei Fehlern teilweise angewendet sein.

Überwachen und warten#

Journal und Dead Letters enthalten Daten und brauchen restriktive Rechte und Backups. Signiertes Health liefert writeBuffer mit enabled, pending, oldestAgeSeconds, halted. Metriken: ldb_writebehind_pending, ldb_writebehind_applied_total, ldb_writebehind_dead_lettered_total im Meter Ldb.Api.

Auf wachsende Warteschlange, Stillstand und Dead Letters reagieren. Dead-Letter-Zeilen enthalten id, op, ns, p, code, message, t; Ursache korrigieren und die Nutzlast p bewusst neu senden. Vor Migration jeden Namespace flushen und remaining: 0 abwarten. Mehrere API-Instanzen haben getrennte Reihenfolgen und Journale.

Im Bundle Db.IsQueued(result) verwenden, mit Db.Flush(ns, done) leeren und für einzelne Live-Aufrufe immediate: true setzen. Das Praxisbeispiel zeigt Live-Schreiben mit sauberer Fehlerbehandlung.

Suchbegriff eingeben, um die Dokumentation zu durchsuchen.