Synchron gegen asynchron: die Konsequenzen
Write-Through schreibt synchron in Cache und Datenbank und garantiert damit Konsistenz um den Preis zusaetzlicher Latenz. Write-Back schreibt nur in den Cache und verzoegert die Datenbank asynchron, was Latenz spart, aber ein reales Risiko fuer Datenverlust bei einem Ausfall des Cache-Servers erzeugt. Welche Strategie passt, haengt von den Konsistenzanforderungen der jeweiligen Daten ab.
Inhaltsverzeichnis
- 1. Zwei grundverschiedene Schreibstrategien
- 2. Write-Through: synchrones Schreiben im Detail
- 3. Write-Through in PHP implementieren
- 4. Write-Back: asynchrones Schreiben im Detail
- 5. Write-Back mit einer Queue umsetzen
- 6. Das Datenverlustrisiko bei Write-Back einordnen
- 7. Latenzmessung: der reale Unterschied
- 8. Entscheidungskriterien fuer die Praxis
- 9. Write-Through und Write-Back im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Zwei grundverschiedene Schreibstrategien
Wer Redis nicht nur zum Lesen, sondern auch als Ziel von Schreiboperationen einsetzt, muss sich zwischen zwei fundamental unterschiedlichen Strategien entscheiden: Write-Through Caching und Write-Back Caching. Beide Strategien lösen dasselbe Problem, nämlich wie der Cache bei einer Änderung der Ursprungsdaten aktuell gehalten wird, aber sie treffen dabei entgegengesetzte Kompromisse zwischen Konsistenz, Latenz und Ausfallsicherheit.
Der fundamentale Unterschied liegt in der Reihenfolge und Synchronität der Schreiboperationen. Write-Through schreibt in Cache und Datenbank im selben Request und wartet auf beide Bestätigungen, bevor die Operation als abgeschlossen gilt. Write-Back schreibt nur in den Cache und verschiebt die Datenbankschreibung in einen späteren, asynchronen Schritt. Diese scheinbar kleine Verschiebung hat weitreichende Folgen für Latenz, Konsistenzgarantien und das Verhalten bei einem Ausfall.
2. Write-Through: synchrones Schreiben im Detail
Beim Write-Through Caching löst jede Schreiboperation der Anwendung zwei synchrone Schreibvorgänge aus: zuerst in die Datenbank, danach in Redis, oder in umgekehrter Reihenfolge je nach Implementierung. Die Anwendung wartet auf die Bestätigung beider Systeme, bevor sie die Operation als erfolgreich zurückmeldet. Das Ergebnis ist eine Garantie, die viele andere Caching-Strategien nicht bieten: Cache und Datenbank sind zu jedem Zeitpunkt konsistent, es existiert kein Zeitfenster mit veralteten Daten im Cache.
Der Preis dieser Garantie ist Latenz. Jede Schreiboperation dauert mindestens so lange wie die langsamere der beiden Zielsysteme, in der Praxis meist die Datenbank. Bei einer typischen relationalen Datenbank mit 5 bis 15 Millisekunden Schreiblatenz addiert sich diese Zeit vollständig zur Antwortzeit des Nutzers, Redis liefert dabei kaum Beschleunigung, weil es ohnehin auf die Datenbank warten muss. Write-Through lohnt sich also nicht für die Schreiblatenz selbst, sondern ausschließlich für die nachfolgenden Leseoperationen, die dann garantiert aktuelle Daten aus dem Cache erhalten.
3. Write-Through in PHP implementieren
Die Implementierung von Write-Through in PHP folgt einem klaren Muster: Eine Transaktion schreibt zuerst in die Datenbank, und nur wenn dieser Schritt erfolgreich war, wird der Cache aktualisiert. Wird die Reihenfolge vertauscht und die Datenbankschreibung schlägt fehl, enthält der Cache Daten, die in der Datenbank gar nicht existieren, ein deutlich gefährlicherer Zustand als ein einfacher Cache Miss.
Wichtig ist außerdem, dass ein Fehler bei der Cache-Aktualisierung die Transaktion nicht rückgängig macht. Wenn die Datenbankschreibung erfolgreich war, aber Redis nicht erreichbar ist, sollte die Operation dennoch als erfolgreich gelten und der veraltete Cache-Eintrag stattdessen aktiv gelöscht statt fehlerhaft aktualisiert werden.
<?php
declare(strict_types=1);
final class WriteThroughProductRepository
{
public function __construct(
private readonly \Predis\Client $redis,
private readonly \PDO $pdo,
private readonly int $ttlSeconds = 3600
) {
}
/**
* Write-through update: database first, then cache, synchronously.
*/
public function updatePrice(int $productId, float $price): void
{
$stmt = $this->pdo->prepare(
'UPDATE products SET price = :price WHERE id = :id'
);
$stmt->execute(['price' => $price, 'id' => $productId]);
$key = "product:{$productId}";
try {
$product = $this->loadFromDatabase($productId);
$this->redis->setex($key, $this->ttlSeconds, json_encode($product));
} catch (\Predis\Connection\ConnectionException $e) {
// Database write succeeded; drop the stale cache entry instead
$this->redis->del([$key]);
}
}
private function loadFromDatabase(int $productId): array
{
$stmt = $this->pdo->prepare('SELECT * FROM products WHERE id = :id');
$stmt->execute(['id' => $productId]);
return $stmt->fetch(\PDO::FETCH_ASSOC);
}
}
4. Write-Back: asynchrones Schreiben im Detail
Beim Write-Back Caching, teilweise auch Write-Behind genannt, schreibt die Anwendung ausschließlich in Redis und meldet die Operation sofort als abgeschlossen zurück. Die Übertragung in die Datenbank erfolgt später, entweder über einen Hintergrundprozess, der geänderte Schlüssel periodisch synchronisiert, oder über eine Warteschlange, die Schreiboperationen asynchron abarbeitet. Redis selbst wird damit für einen Moment zur alleinigen Quelle der Wahrheit für die geschriebenen Daten.
Der Vorteil ist dramatisch geringere Latenz, weil eine Schreiboperation nur auf Redis wartet und Redis-Schreibvorgänge typischerweise im niedrigen einstelligen Millisekundenbereich liegen, oft sogar darunter. Zusätzlich lassen sich bei Write-Back mehrere Änderungen an demselben Datensatz zu einer einzigen Datenbankschreibung zusammenfassen, was bei Zählern, Bewertungspunkten oder Sitzungsdaten die effektive Schreiblast auf die Datenbank drastisch reduziert. Diese Effizienz erkauft sich Write-Back allerdings mit einem strukturellen Risiko, das im nächsten Abschnitt im Detail behandelt wird.
# Write-Back: Schreiboperation landet zunaechst nur in Redis
redis-cli SET counter:pageviews:4711 8420
redis-cli SADD dirty:products 4711
# Hintergrundprozess liest periodisch die "dirty" Menge
redis-cli SMEMBERS dirty:products
# 1) "4711"
# Nach erfolgreicher DB-Synchronisation wird der Marker entfernt
redis-cli SREM dirty:products 4711
5. Write-Back mit einer Queue umsetzen
In der Praxis wird Write-Back meist über eine Kombination aus Redis-Schreibvorgang und einer separaten Warteschlange realisiert, die die Synchronisation in die Datenbank übernimmt. Die Anwendung schreibt den neuen Wert in Redis und markiert den betroffenen Schlüssel gleichzeitig als "dirty", etwa in einem Redis-Set. Ein separater Worker-Prozess liest diese Menge periodisch aus, überträgt die Änderungen in die Datenbank und entfernt den Marker erst nach erfolgreicher Bestätigung.
Dieses Muster erfordert Idempotenz auf Seiten des Workers, denn ein Absturz zwischen Datenbankschreibung und Marker-Entfernung führt dazu, dass derselbe Wert beim nächsten Lauf erneut synchronisiert wird. Für additive Operationen wie Zähler ist das unkritisch, für absolute Werte wie Preise muss der Worker mit "letzter Wert gewinnt"-Semantik arbeiten, um doppelte Verarbeitung sicher zu handhaben.
<?php
declare(strict_types=1);
final class WriteBackSyncWorker
{
public function __construct(
private readonly \Predis\Client $redis,
private readonly \PDO $pdo
) {
}
/**
* Periodically flush dirty keys from Redis into the database.
*/
public function flushDirtyProducts(): void
{
$dirtyIds = $this->redis->smembers('dirty:products');
foreach ($dirtyIds as $productId) {
$raw = $this->redis->get("product:{$productId}");
if ($raw === null) {
$this->redis->srem('dirty:products', [$productId]);
continue;
}
$product = json_decode($raw, true);
$stmt = $this->pdo->prepare(
'UPDATE products SET price = :price WHERE id = :id'
);
$stmt->execute(['price' => $product['price'], 'id' => $productId]);
// Only remove the marker after a confirmed database write
$this->redis->srem('dirty:products', [$productId]);
}
}
}
6. Das Datenverlustrisiko bei Write-Back einordnen
Das zentrale Risiko von Write-Back Caching ist Datenverlust bei einem Ausfall des Redis-Servers, bevor die asynchrone Synchronisation in die Datenbank abgeschlossen ist. Alle Änderungen, die nur in Redis existieren und noch nicht persistiert wurden, sind in diesem Moment verloren, selbst wenn Redis mit AOF-Persistenz konfiguriert ist, da ein Zeitfenster zwischen Schreiboperation und Disk-Flush bestehen bleibt. Dieses Risiko ist der Hauptgrund, warum Write-Back nicht für jede Art von Daten geeignet ist.
Die Größe des Risikos lässt sich über das Zeitfenster zwischen Schreiboperation und Synchronisation steuern: Ein Worker, der alle 500 Millisekunden synchronisiert, riskiert im schlimmsten Fall den Verlust von 500 Millisekunden an Änderungen. Für Zähler wie Seitenaufrufe oder Klickstatistiken ist dieses Risiko meist akzeptabel, weil der Verlust weniger Datenpunkte die Gesamtstatistik kaum verzerrt. Für Zahlungsdaten oder Bestellstatus ist dasselbe Risiko inakzeptabel, hier ist Write-Through oder eine direkte, synchrone Datenbankschreibung ohne Cache-Umweg die richtige Wahl.
7. Latenzmessung: der reale Unterschied
Der Latenzunterschied zwischen den beiden Strategien lässt sich direkt messen und ist oft größer, als Entwickler zunächst annehmen. Eine Write-Through-Operation gegen eine MySQL-Instanz im selben Rechenzentrum liegt typischerweise bei 8 bis 20 Millisekunden, dominiert vom Disk-Commit der Datenbank. Eine reine Write-Back-Operation gegen Redis liegt meist bei unter einer Millisekunde, da Redis In-Memory arbeitet und der AOF-Flush standardmäßig gepuffert erfolgt.
Diese Differenz von Faktor 10 bis 20 macht Write-Back besonders attraktiv für Schreiboperationen mit hoher Frequenz, etwa Live-Zähler, Rate-Limiting-Zustände oder Sitzungsdaten, bei denen Nutzer die Latenz jeder einzelnen Schreiboperation direkt spüren würden. Bei seltenen Schreiboperationen, etwa einer Bestelländerung einmal pro Minute, spielt der Latenzunterschied dagegen kaum eine Rolle, sodass sich der zusätzliche Implementierungsaufwand von Write-Back dort selten lohnt.
# Redis-Schreiblatenz direkt messen
redis-cli --latency -i 1
# min: 0, max: 1, avg: 0.12 (ms) ueber 1 Sekunde
# Langsame Kommandos im Slowlog identifizieren
redis-cli SLOWLOG GET 10
# AOF-Konfiguration pruefen, relevant fuer Write-Back Risiko
redis-cli CONFIG GET appendfsync
# 1) "appendfsync"
# 2) "everysec"
8. Entscheidungskriterien fuer die Praxis
Die Wahl zwischen Write-Through und Write-Back sollte anhand von drei Fragen getroffen werden. Erstens: Wie kritisch ist Datenverlust für diesen konkreten Datentyp? Finanzdaten und Bestellstatus verlangen Write-Through oder direkte Datenbankschreibung, Zähler und Metriken vertragen das Risiko von Write-Back. Zweitens: Wie hoch ist die Schreibfrequenz? Bei seltenen Schreiboperationen überwiegt der Implementierungsaufwand von Write-Back den Nutzen. Drittens: Wie wichtig ist die Latenz der Schreiboperation selbst für die Nutzererfahrung?
In vielen realen Systemen kommen beide Strategien parallel zum Einsatz, je nach Datentyp. Ein E-Commerce-System nutzt typischerweise Write-Through für Bestellungen und Zahlungsstatus, während Produktansichten-Zähler und Warenkorb-Interaktionsdaten über Write-Back laufen. Diese hybride Herangehensweise nutzt die Stärken beider Muster gezielt, statt eine einzige Strategie über das gesamte System zu erzwingen.
# Kritischer Datentyp: synchron mit Write-Through schreiben
redis-cli SET order:8842:status "paid" EX 86400
# Unkritischer Zaehler: mit Write-Back nur in Redis, Sync per Worker
redis-cli INCR pageviews:product:4711
redis-cli SADD dirty:pageviews 4711
# Beide Strategien im selben System, getrennt nach Datentyp
redis-cli TYPE order:8842:status
redis-cli TYPE pageviews:product:4711
9. Write-Through und Write-Back im direkten Vergleich
Die folgende Tabelle fasst die wichtigsten Unterschiede zwischen den beiden Schreibstrategien zusammen und dient als schnelle Entscheidungshilfe für die Praxis.
| Kriterium | Write-Through | Write-Back |
|---|---|---|
| Schreiblatenz | Hoch, dominiert von der Datenbank | Niedrig, nur Redis im kritischen Pfad |
| Konsistenz | Immer aktuell, keine Verzoegerung | Kurzfristig inkonsistent bis zur Synchronisation |
| Datenverlustrisiko | Sehr gering | Real bei Redis-Ausfall vor Synchronisation |
| Implementierungsaufwand | Gering, zwei synchrone Schreibvorgaenge | Hoeher, Worker und Idempotenz noetig |
| Typischer Einsatz | Bestellungen, Zahlungsdaten | Zaehler, Sitzungsdaten, Metriken |
Diese Gegenüberstellung zeigt: Es gibt keine universell überlegene Strategie zwischen Write-Through und Write-Back, sondern nur eine passende Wahl für den jeweiligen Datentyp. Wer beide Muster kennt und gezielt kombiniert, vermeidet sowohl unnötige Latenz bei kritischen Daten als auch unnötiges Datenverlustrisiko bei Daten, die eigentlich synchron geschrieben werden sollten.
Mironsoft
Redis-Architektur, Caching-Strategien und Backend-Performance
Die richtige Schreibstrategie fuer eure Daten finden?
Wir bewerten eure Datentypen nach Konsistenzanforderungen und Schreibfrequenz und implementieren die passende Kombination aus Write-Through und Write-Back mit sauberer Fehlerbehandlung.
Datenklassifizierung
Konsistenzanforderungen und Risikoprofil je Datentyp bewerten
Implementierung
Write-Through und Write-Back mit Worker-Prozessen sauber umsetzen
Ausfallsicherheit
Persistenz-Konfiguration und Datenverlustrisiko gezielt reduzieren
10. Zusammenfassung
Write-Through Caching und Write-Back Caching lösen dasselbe Problem mit gegensätzlichen Kompromissen. Write-Through garantiert Konsistenz durch synchrones Schreiben in Cache und Datenbank, bezahlt diese Garantie aber mit Latenz, die von der langsameren Datenbank dominiert wird. Write-Back reduziert die Schreiblatenz drastisch, indem nur Redis synchron beschrieben wird, nimmt dafür aber ein reales Datenverlustrisiko in Kauf, falls Redis ausfällt, bevor die asynchrone Synchronisation abgeschlossen ist.
Die richtige Entscheidung hängt vom konkreten Datentyp ab: Kritische, konsistenzabhängige Daten wie Zahlungen gehören zu Write-Through, hochfrequente, verlustolerante Daten wie Zähler profitieren von Write-Back. Die meisten produktiven Systeme kombinieren beide Strategien gezielt, statt eine einzige Lösung über alle Datentypen hinweg zu erzwingen.
Write-Through vs. Write-Back Caching, das Wichtigste auf einen Blick
Write-Through
Synchrones Schreiben in Datenbank und Cache. Immer konsistent, aber Latenz durch die langsamere Datenbank.
Write-Back
Schreiben nur in Redis, Datenbank asynchron via Worker. Niedrige Latenz, aber reales Datenverlustrisiko.
Entscheidungskriterium
Kritikalitaet von Datenverlust, Schreibfrequenz und Latenzsensitivitaet der Nutzererfahrung bewerten.
Hybrider Einsatz
Write-Through fuer Zahlungen und Bestellungen, Write-Back fuer Zaehler und Sitzungsdaten kombinieren.