Wie man Lesezugriffe horizontal verteilt, ohne die Konsistenz aus den Augen zu verlieren
Die meisten Webanwendungen lesen deutlich häufiger aus der Datenbank, als sie schreiben, wodurch der Primary-Server oft zum Flaschenhals wird, obwohl Schreibzugriffe nur einen kleinen Teil der Last ausmachen. Read-Replicas verteilen Lesezugriffe auf zusätzliche Server-Kopien und entlasten so den Primary spürbar.
Inhaltsverzeichnis
- 1. Was sind Read-Replicas
- 2. Warum Skalierung über Replicas sinnvoll ist
- 3. Replikationsmechanismen im Überblick
- 4. Replikations-Lag als praktische Herausforderung
- 5. Strategien gegen Lag-bedingte Inkonsistenzen
- 6. Read-Write-Splitting in der Anwendungsschicht
- 7. Monitoring von Replikations-Lag
- 8. Grenzen und Fallstricke
- 9. Zusammenfassung und Praxisempfehlung
- 10. Zusammenfassung
- 11. FAQ
1. Was sind Read-Replicas
Eine Read-Replica ist eine fortlaufend synchronisierte Kopie einer Datenbank, die ausschliesslich Lesezugriffe bedient, während alle Schreibzugriffe weiterhin auf dem sogenannten Primary-Server landen. Die Replica empfängt kontinuierlich Änderungen vom Primary, meist über einen Replikationsstream, und wendet diese in derselben Reihenfolge an, in der sie auf dem Primary entstanden sind, um denselben Datenstand nachzubilden.
Für die Anwendung bedeutet das, dass ein und dieselbe logische Datenbank aus Sicht der Applikation plötzlich aus mehreren physischen Servern besteht: einem Primary für Schreiboperationen und einer beliebigen Anzahl Replicas für Leseoperationen. Diese Architektur ist besonders wirkungsvoll bei Anwendungen mit einem Lese-Schreib-Verhältnis von zehn zu eins oder stärker, wie es bei den meisten Onlineshops, Content-Websites und Reporting-Systemen typisch ist.
2. Warum Skalierung über Replicas sinnvoll ist
Ein einzelner Datenbankserver hat eine harte Obergrenze bei CPU, Arbeitsspeicher und I/O-Durchsatz, und vertikales Skalieren durch größere Hardware stößt irgendwann an technische und wirtschaftliche Grenzen. Horizontales Skalieren durch das Hinzufügen weiterer Replicas erlaubt es dagegen, Leselast nahezu linear auf beliebig viele zusätzliche Server zu verteilen, solange die Anwendung die Leseanfragen entsprechend aufteilt.
Besonders bei Lastspitzen, etwa während eines Sale-Events in einem Onlineshop, zeigt sich der Vorteil deutlich: Statt einen einzelnen, immer teurer werdenden Primary-Server hochzurüsten, lassen sich temporär weitere Replicas hinzuschalten, die ausschliesslich Produktseiten und Kategorielisten ausliefern, während der Primary sich auf Bestellungen und Warenkorb-Änderungen konzentriert. Das senkt die Infrastrukturkosten im Normalbetrieb und bietet dennoch Reserven für Spitzenlast.
3. Replikationsmechanismen im Überblick
Bei MySQL und MariaDB basiert Replikation typischerweise auf dem Binary Log, in dem der Primary jede datenverändernde Operation protokolliert. Die Replica liest diesen Log kontinuierlich aus und wendet die Änderungen lokal an, wobei zwischen asynchroner, semi-synchroner und, bei manchen Systemen wie Galera Cluster, synchroner Replikation unterschieden wird. Bei PostgreSQL übernimmt der Write-Ahead-Log dieselbe Rolle und wird per Streaming Replication an die Replicas übertragen.
Asynchrone Replikation ist der Standardfall und bietet die beste Schreibperformance auf dem Primary, da dieser nicht auf die Bestätigung der Replica warten muss, bevor er einen Schreibvorgang als abgeschlossen meldet. Der Preis dafür ist ein möglicher zeitlicher Versatz zwischen Primary und Replica, während semi-synchrone Replikation zumindest die Bestätigung des Log-Empfangs abwartet und so das Risiko von Datenverlust bei einem Primary-Ausfall reduziert, allerdings auf Kosten leicht höherer Schreiblatenz.
4. Replikations-Lag als praktische Herausforderung
Der wichtigste Stolperstein beim Einsatz von Read-Replicas ist der Replikations-Lag, also die Zeitspanne zwischen dem Abschluss eines Schreibvorgangs auf dem Primary und dessen Sichtbarwerden auf der Replica. Unter normaler Last liegt dieser Lag oft im Bereich weniger Millisekunden, kann aber bei hoher Schreiblast, langsamen Transaktionen oder Netzwerkproblemen auf mehrere Sekunden oder sogar Minuten anwachsen.
Praktisch äußert sich das etwa so, dass ein Nutzer nach dem Absenden eines Kontaktformulars sofort auf eine Bestätigungsseite weitergeleitet wird, die den soeben gespeicherten Datensatz von einer Replica laden soll, dieser dort aber noch nicht angekommen ist. Das Ergebnis wäre eine verwirrende leere Seite oder eine Fehlermeldung, obwohl der Schreibvorgang technisch erfolgreich war, was aus Nutzersicht wie ein Fehler in der Anwendung wirkt.
5. Strategien gegen Lag-bedingte Inkonsistenzen
Eine verbreitete Lösung ist das sogenannte Read-Your-Writes-Muster, bei dem die Anwendung sich merkt, dass ein Nutzer kürzlich geschrieben hat, und für eine kurze Zeitspanne, etwa die nächsten paar Sekunden, ausschliesslich vom Primary liest statt von einer Replica. Diese Markierung kann in der Session gespeichert werden und läuft automatisch ab, sobald ausreichend Zeit für die Replikation vergangen ist.
Alternativ unterstützen manche Datenbanksysteme das Abfragen einer konkreten Replikationsposition, sodass eine Leseanfrage explizit warten kann, bis die Replica mindestens diesen Stand erreicht hat, bevor sie antwortet. Dieser Ansatz ist präziser als eine feste Zeitspanne, führt aber zu variabler Latenz und sollte nur für Anfragen eingesetzt werden, bei denen Konsistenz wichtiger ist als eine garantiert kurze Antwortzeit.
6. Read-Write-Splitting in der Anwendungsschicht
Read-Write-Splitting bezeichnet die Logik, die entscheidet, ob eine konkrete Datenbankanfrage an den Primary oder an eine Replica geschickt wird. Diese Entscheidung kann entweder in einem dedizierten Proxy wie ProxySQL oder HAProxy getroffen werden, der SQL-Statements analysiert und automatisch weiterleitet, oder direkt im Anwendungscode, wo jede Verbindung explizit als Lese- oder Schreibverbindung markiert wird.
Der Vorteil einer Implementierung in der Anwendungsschicht liegt in der Kontrolle über Sonderfälle wie das eingangs beschriebene Read-Your-Writes-Muster, das ein reiner SQL-Parser im Proxy nur schwer korrekt abbilden kann. Das folgende PHP-Beispiel zeigt eine einfache Verbindungs-Fabrik, die anhand des Statement-Typs und eines Session-Flags entscheidet, welche Verbindung verwendet wird.
final class ReadWriteConnectionRouter
{
public function __construct(
private readonly PDO $primaryConnection,
private readonly PDO $replicaConnection,
private readonly SessionInterface $session,
) {
}
public function getConnectionFor(string $sqlStatement): PDO
{
$isWrite = (bool) preg_match(
'/^\s*(INSERT|UPDATE|DELETE|REPLACE)\b/i',
$sqlStatement
);
if ($isWrite) {
// Nach einem Schreibvorgang für kurze Zeit vom Primary lesen
$this->session->set('recent_write_until', time() + 5);
return $this->primaryConnection;
}
$recentWriteUntil = (int) $this->session->get('recent_write_until', 0);
if ($recentWriteUntil > time()) {
return $this->primaryConnection;
}
return $this->replicaConnection;
}
}
7. Monitoring von Replikations-Lag
Ohne kontinuierliches Monitoring bleibt Replikations-Lag unsichtbar, bis er sich als konkretes Nutzerproblem äußert, weshalb ein dediziertes Alerting unverzichtbar ist. Bei MySQL liefert der Befehl SHOW REPLICA STATUS den Wert Seconds_Behind_Source, der als grobe Näherung des aktuellen Lags dient, während PostgreSQL über die Systemsicht pg_stat_replication vergleichbare Kennzahlen bereitstellt.
Für produktive Systeme empfiehlt sich, diese Metrik regelmäßig an ein Monitoring-System wie Prometheus zu senden und einen Schwellenwert zu definieren, ab dem eine Replica automatisch aus dem Lastverteiler entfernt wird. So verhindert man, dass Nutzer auf einer stark hinterherhinkenden Replica veraltete Daten sehen, während die übrigen, aktuelleren Replicas die Last automatisch mit übernehmen.
8. Grenzen und Fallstricke
Read-Replicas skalieren nicht jede Art von Last gleichermassen gut: Komplexe Analyse-Abfragen mit vielen Joins oder Aggregationen belasten eine Replica genauso stark wie den Primary und profitieren eher von einem dedizierten Reporting-System oder einem Data Warehouse als von zusätzlichen Replicas. Auch Schreiblast selbst lässt sich durch Replicas nicht reduzieren, da jede Replica dieselbe Schreiblast des Primary zusätzlich replizieren und anwenden muss.
Ein oft unterschätzter Aspekt ist die operative Komplexität: Failover-Szenarien, bei denen eine Replica zum neuen Primary befördert wird, müssen sorgfältig getestet werden, da falsch konfigurierte Anwendungen sonst weiterhin auf den alten, möglicherweise inkonsistenten Primary schreiben könnten. Zusätzlich steigen mit jeder weiteren Replica die Infrastrukturkosten und der Wartungsaufwand für Backups, Patches und Versionsupdates linear mit.
9. Zusammenfassung und Praxisempfehlung
Read-Replicas sind ein bewährtes Mittel, um lesehungrige Anwendungen horizontal zu skalieren, ohne die Komplexität eines vollständig verteilten, sharded Datenbanksystems in Kauf nehmen zu müssen. Der entscheidende Erfolgsfaktor liegt darin, Replikations-Lag von Anfang an als normalen Bestandteil der Architektur einzuplanen, statt ihn als seltenen Ausnahmefall zu behandeln, der erst nach dem ersten Nutzer-Ticket auffällt.
Wer Read-Write-Splitting einführt, sollte zunächst unkritische Leseanfragen wie Produktlisten oder Blogartikel auf Replicas verlagern und erst danach schrittweise weitere Bereiche folgen lassen, während konsistenzkritische Abschnitte wie Checkout und Kontostand bewusst beim Primary bleiben. So entsteht eine Architektur, die Performance gewinnt, ohne an Verlässlichkeit einzubüßen.
| Replikationsart | Schreiblatenz auf Primary | Datenverlust-Risiko bei Ausfall | Typischer Einsatz |
|---|---|---|---|
| Asynchron | Sehr niedrig | Möglich (letzte Änderungen) | Standardfall für Lese-Skalierung |
| Semi-synchron | Leicht erhöht | Gering | Wenn Datensicherheit wichtiger als Latenz ist |
| Synchron (z.B. Galera) | Deutlich erhöht | Praktisch keins | Hochverfügbare Cluster-Setups |
| Read-Your-Writes über Primary | Unverändert | Nicht relevant | Formulare mit sofortiger Bestätigungsseite |
Mironsoft
Web Performance, Core Web Vitals und Ladezeit-Optimierung
Ladezeiten, die Nutzer nicht abspringen lassen, bevor die Seite überhaupt sichtbar ist?
Wir prüfen bestehende Webseiten auf langsame Core Web Vitals, aufgeblähte JavaScript-Bundles und ungenutzte Render-Blocker und bauen daraus eine Performance-Grundlage, die messbar bleibt statt nur einmalig gut auszusehen.
Performance-Audit
Core Web Vitals, Ladewasserfall und Render-Blocker systematisch messen und beheben.
Bundle-Optimierung
JavaScript- und CSS-Bundle-Größe sowie Code-Splitting gezielt reduzieren.
Monitoring-Aufbau
Kontinuierliches Performance-Monitoring statt einmaliger Momentaufnahme etablieren.
10. Zusammenfassung
Datenbank-Read-Replicas
Technik
Lesezugriffe auf synchronisierte Server-Kopien verteilen
Effekt
Horizontale Skalierung leselastiger Anwendungen
Herausforderung
Replikations-Lag zwischen Primary und Replica
Lösung
Read-Write-Splitting mit Read-Your-Writes-Muster