von einem Server zum belastbaren Cluster
Ein einzelner Server stößt bei wachsendem Traffic zwangsläufig an Grenzen, egal wie viel RAM oder CPU er bekommt. Dieser Artikel erklärt, wie Magento-Shops Web, Datenbank, Suche und Cache auf dedizierte Server verteilen, Sessions zentral über Redis halten, Medien konsistent über NFS oder S3 ausliefern und Load Balancer mit korrekten Health Checks betreiben.
Inhaltsverzeichnis
- 1. Wann ein Server nicht mehr reicht
- 2. Horizontale vs. vertikale Skalierung
- 3. Web, Datenbank, Suche und Cache trennen
- 4. Sessions im Multi-Server-Setup: warum Redis Pflicht ist
- 5. Geteilter Medienspeicher: NFS vs. S3
- 6. Load Balancer: Health Checks richtig konfigurieren
- 7. Sticky Sessions vs. zustandslose Web-Nodes
- 8. Datenbank-Skalierung: Replikation und Read-Splitting
- 9. Skalierungsstrategien im direkten Vergleich
- 10. Zusammenfassung
- 11. FAQ
1. Wann ein Server nicht mehr reicht
Solange ein Magento-Shop auf einem einzigen Server läuft, teilen sich PHP-FPM, MySQL, Elasticsearch/OpenSearch, Redis und der Webserver dieselbe CPU, denselben RAM und dieselbe Disk-I/O. Bei geringem Traffic funktioniert das gut, weil die Ressourcen selten gleichzeitig ausgelastet sind. Sobald aber gleichzeitige Bestellungen, Katalog-Indizierung und Reindexing im Hintergrund zusammenfallen, konkurrieren alle Prozesse um dieselben Ressourcen, und die Antwortzeiten steigen für alle Nutzer gleichzeitig, nicht nur für die, die die Last verursachen.
Ein klares Warnsignal ist, wenn top oder htop während normaler Lastspitzen durchgehend hohe I/O-Wait-Zeiten zeigt, während CPU und RAM noch Reserven haben. Das deutet darauf hin, dass MySQL und der Webserver sich gegenseitig um Disk-Zugriffe blockieren. Bevor man in mehr Server investiert, lohnt sich immer zuerst ein Blick auf Caching, Indexer-Modus und Query-Performance. Multi-Server-Architektur löst kein schlecht optimiertes Datenbankschema, verschiebt das Problem aber auf mehr Hardware, was teuer und auf Dauer nicht nachhaltig ist.
2. Horizontale vs. vertikale Skalierung
Vertikale Skalierung bedeutet, einem bestehenden Server mehr CPU-Kerne, mehr RAM oder schnellere Disks (NVMe statt SATA-SSD) zu geben. Der Vorteil: keine Architekturänderung nötig, Magento läuft unverändert weiter. Der Nachteil: Es gibt eine physische und wirtschaftliche Obergrenze, und ein einzelner Server bleibt ein Single Point of Failure. Fällt er aus, ist der gesamte Shop offline, unabhängig davon, wie leistungsfähig die Hardware war.
Horizontale Skalierung bedeutet, mehrere kleinere oder gleich große Server parallel zu betreiben und die Last über einen Load Balancer zu verteilen. Das erhöht nicht nur die Kapazität, sondern auch die Ausfallsicherheit: Fällt ein Web-Node aus, übernehmen die verbleibenden Nodes den Traffic automatisch. Der entscheidende Haken: Horizontale Skalierung erfordert, dass die Anwendung zustandslos (stateless) wird. Sessions, hochgeladene Dateien und Caches dürfen nicht mehr lokal auf einem einzelnen Server liegen, sondern müssen zentral erreichbar sein. Genau diese Anforderung treibt die restliche Architektur in diesem Artikel.
3. Web, Datenbank, Suche und Cache trennen
Der erste Schritt weg vom Single-Server-Setup ist selten sofort horizontale Skalierung der Webserver, sondern die funktionale Trennung der Dienste auf dedizierte Server: ein oder mehrere Application-Server für PHP-FPM und Nginx, ein dedizierter MySQL/MariaDB-Server, ein dedizierter OpenSearch/Elasticsearch-Cluster für die Katalogsuche und ein dedizierter Redis-Server für Cache und Sessions. Jeder Dienst bekommt so seine eigenen Ressourcen und kann unabhängig skaliert und überwacht werden, ohne dass ein schwerer Reindex-Job die Antwortzeiten der Webanfragen beeinträchtigt.
Diese Trennung ist auch der natürliche Vorbereitungsschritt für horizontale Skalierung, weil sie erzwingt, dass Konfiguration und Zugriffspfade bereits über Hostnamen statt localhost erfolgen. In app/etc/env.php werden Datenbank-Host, Redis-Host und Suchmaschinen-Host explizit als eigene Endpunkte eingetragen. Wichtig in der Praxis: Netzwerklatenz zwischen den Diensten sollte im Rechenzentrum unter einer Millisekunde liegen, idealerweise im selben Availability-Zone-Segment, sonst summiert sich die zusätzliche Round-Trip-Zeit pro Seitenaufruf spürbar auf, gerade bei mehreren sequenziellen Redis-Aufrufen pro Request.
# Typical service split across dedicated hosts (example inventory)
# web-01, web-02 : Nginx + PHP-FPM (application/frontend nodes)
# db-01 (primary) : MySQL/MariaDB write node
# db-02 (replica) : MySQL/MariaDB read replica
# search-01..03 : OpenSearch cluster (3 nodes, quorum for split-brain safety)
# redis-cache-01 : Redis instance for full page cache + config cache
# redis-session-01 : Separate Redis instance for session storage
# Verify connectivity from a web node before cutting over app/etc/env.php
mysql -h db-01.internal -u magento -p -e "SELECT 1;"
redis-cli -h redis-session-01.internal -p 6379 PING
curl -s http://search-01.internal:9200/_cluster/health?pretty
4. Sessions im Multi-Server-Setup: warum Redis Pflicht ist
Standardmäßig speichert PHP Sessions als Dateien im lokalen Dateisystem (/var/lib/php/sessions oder ähnlich). In einem Multi-Server-Setup ohne Sticky Sessions ist das fatal: Ein Nutzer wird bei Request 1 von Web-Node-1 bedient, seine Session-Datei liegt nur dort. Landet Request 2 durch den Load Balancer auf Web-Node-2, findet PHP dort keine Session-Datei und der Nutzer wird unerwartet ausgeloggt, der Warenkorb ist leer, oder der Checkout bricht mitten im Zahlungsprozess ab. Das ist einer der häufigsten Bugs bei naiven Migrationen von einem auf mehrere Server.
Die Lösung ist ein zentraler, von allen Web-Nodes erreichbarer Session-Speicher, in der Magento-Welt praktisch immer Redis. Alle Web-Nodes schreiben und lesen Sessions über dasselbe Redis-Backend, unabhängig davon, welcher Node den Request bedient. Magento unterstützt das nativ über den session.save_handler Eintrag in app/etc/env.php. Wichtig: Session-Redis und Cache-Redis sollten auf getrennten Redis-Instanzen oder zumindest getrennten Datenbanken laufen, damit ein FLUSHALL beim Cache-Clearing nicht versehentlich aktive Nutzer-Sessions löscht. Für Hochverfügbarkeit empfiehlt sich Redis Sentinel oder Redis Cluster, damit ein Ausfall der primären Redis-Instanz nicht alle Sessions gleichzeitig zerstört.
// app/etc/env.php - Redis for sessions, separated from cache/FPC backend
return [
'session' => [
'save' => 'redis',
'redis' => [
'host' => 'redis-session-01.internal',
'port' => '6379',
'password' => '',
'timeout' => '2.5',
'persistent_identifier' => '',
'database' => '2', // dedicated DB index, separate from cache
'compression_threshold' => '2048',
'compression_library' => 'gzip',
'log_level' => '1',
'max_concurrency' => '20', // concurrent lock holders per session
'break_after_frontend' => '5',
'break_after_adminhtml' => '30',
'first_lifetime' => '600',
'bot_first_lifetime' => '60',
'bot_lifetime' => '7200',
'disable_locking' => '0', // keep locking enabled to avoid race conditions
],
],
'cache' => [
'frontend' => [
'default' => [
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' => [
'server' => 'redis-cache-01.internal',
'port' => '6379',
'database' => '0',
],
],
'page_cache' => [
'backend' => 'Cm_Cache_Backend_Redis',
'backend_options' => [
'server' => 'redis-cache-01.internal',
'port' => '6379',
'database' => '1',
],
],
],
],
];
5. Geteilter Medienspeicher: NFS vs. S3
Produktbilder, hochgeladene Kundendateien und generierte statische Assets landen in pub/media. In einem Single-Server-Setup ist das ein lokales Verzeichnis. Sobald mehrere Web-Nodes parallel laufen, muss dieses Verzeichnis für alle Nodes identisch und konsistent sein, sonst zeigt ein frisch hochgeladenes Produktbild auf Node 1 einen 404-Fehler, wenn der nächste Request von Node 2 bedient wird. Zwei etablierte Lösungen: ein NFS-Mount, bei dem alle Web-Nodes dasselbe Netzwerk-Filesystem einhängen, oder Objektspeicher wie S3 (bzw. S3-kompatibel wie MinIO), an den Magento über ein Media-Storage-Modul angebunden wird.
NFS ist einfacher einzurichten und verhält sich für Magento wie ein normales lokales Dateisystem, hat aber Nachteile bei hoher Parallelität: Locking-Overhead und ein Single Point of Failure am NFS-Server selbst, sofern dieser nicht redundant ausgelegt ist. S3-basierte Lösungen sind von Haus aus hochverfügbar und lassen sich gut mit einem CDN kombinieren, erfordern aber ein zusätzliches Modul (z. B. magento/module-aws-s3 in Adobe Commerce oder Community-Erweiterungen für Open Source) und eine sorgfältige Migration bestehender Medien. Für neue Multi-Server-Deployments ist S3 meist die robustere Wahl, für bestehende On-Premise-Infrastrukturen ist ein redundantes NFS-Setup (z. B. über DRBD oder eine Storage-Appliance) oft der pragmatischere erste Schritt.
# Option A: NFS mount for pub/media, identical on every web node
# On the NFS server (storage-01):
# /etc/exports: /export/magento-media 10.0.1.0/24(rw,sync,no_subtree_check,no_root_squash)
# On each web node:
sudo mount -t nfs4 storage-01.internal:/export/magento-media /var/www/magento/pub/media
echo "storage-01.internal:/export/magento-media /var/www/magento/pub/media nfs4 defaults,_netdev 0 0" | sudo tee -a /etc/fstab
# Sanity check: file written on web-01 must appear instantly on web-02
touch /var/www/magento/pub/media/.nfs-writetest
ssh web-02 "ls -la /var/www/magento/pub/media/.nfs-writetest"
# Option B: S3-backed media storage (env.php snippet, module-dependent)
# 'remote_storage' => [
# 'driver' => 'aws-s3',
# 'config' => [
# 'bucket' => 'mironsoft-magento-media',
# 'region' => 'eu-central-1',
# ],
# ],
6. Load Balancer: Health Checks richtig konfigurieren
Ein Load Balancer (Nginx, HAProxy, oder ein Cloud-LB wie AWS ALB) verteilt eingehende Requests auf die verfügbaren Web-Nodes. Entscheidend ist, dass der Load Balancer defekte Nodes zuverlässig erkennt und aus der Rotation nimmt, bevor Nutzer Fehlerseiten sehen. Ein einfacher TCP-Check auf Port 443 reicht dafür nicht aus, weil ein Server, dessen PHP-FPM abgestürzt ist, den Port trotzdem noch offen halten kann (Nginx antwortet, aber liefert nur 502 Bad Gateway). Nötig ist ein Application-Level-Health-Check, der einen echten HTTP-Request gegen einen dedizierten Endpunkt schickt und den Antwortstatus sowie idealerweise auch die Antwortzeit prüft.
Ein guter Health-Check-Endpunkt in Magento antwortet schnell, prüft aber die kritischen Abhängigkeiten: Datenbankverbindung und Redis-Erreichbarkeit. Er sollte bewusst nicht den vollen Seiten-Bootstrap durchlaufen, um die Prüfung selbst nicht zur Lastquelle zu machen. Wichtig ist außerdem ein sinnvolles Intervall: Zu aggressive Health Checks (z. B. alle 1 Sekunde mit kurzem Timeout) können einen Node fälschlich als down markieren, wenn er kurzzeitig unter Last steht, was zu Flapping führt. Ein Intervall von 5 bis 10 Sekunden mit 2-3 aufeinanderfolgenden Fehlversuchen vor dem Ausschluss ist ein robuster Ausgangswert.
# nginx.conf on the load balancer: upstream with active health checks
upstream magento_backend {
zone magento_backend 64k;
server web-01.internal:8080 max_fails=3 fail_timeout=10s;
server web-02.internal:8080 max_fails=3 fail_timeout=10s;
server web-03.internal:8080 max_fails=3 fail_timeout=10s backup;
}
server {
listen 443 ssl;
server_name mironsoft.de;
location / {
proxy_pass http://magento_backend;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_next_upstream error timeout http_502 http_503;
}
# Application-level health check, not just a TCP handshake
location /health/check {
proxy_pass http://magento_backend/health_check.php;
proxy_connect_timeout 2s;
proxy_read_timeout 3s;
access_log off;
}
}
Der Endpunkt health_check.php selbst sollte ein kompaktes, maschinenlesbares JSON zurückgeben, damit sowohl der Load Balancer den HTTP-Statuscode auswerten als auch ein externes Monitoring-System die Detail-Antwort protokollieren kann. Ein Statuscode 200 signalisiert, dass alle geprüften Abhängigkeiten erreichbar sind, ein 503 nimmt den Node sofort aus der Rotation.
{
"status": "ok",
"checks": {
"database": { "status": "ok", "latency_ms": 4 },
"redis_session": { "status": "ok", "latency_ms": 1 },
"redis_cache": { "status": "ok", "latency_ms": 1 }
},
"node": "web-02.internal",
"timestamp": "2026-07-11T09:12:44+00:00"
}
7. Sticky Sessions vs. zustandslose Web-Nodes
Sticky Sessions (Session Affinity) bedeuten, dass der Load Balancer denselben Client anhand eines Cookies oder der Client-IP immer an denselben Web-Node weiterleitet. Auf den ersten Blick eine einfache Lösung für das Session-Problem, aber sie bringt eigene Nachteile mit: Fällt der zugewiesene Node aus, verliert der Nutzer trotzdem seine Session, weil sie ja lokal auf genau diesem Node lag. Außerdem verteilt sich die Last ungleichmäßiger, weil Nutzer mit langen Sitzungen dauerhaft an einem Node kleben, statt dynamisch auf freie Kapazität verteilt zu werden.
Die robustere Architektur, wie in Abschnitt 4 beschrieben, macht Web-Nodes komplett zustandslos: Sessions liegen in Redis, Medien in NFS/S3, und jeder Request kann von jedem beliebigen Node bedient werden. Damit wird Sticky Session Affinity überflüssig, der Load Balancer kann echtes Round-Robin oder Least-Connections-Balancing ohne Einschränkung nutzen, und ein ausfallender Node beeinträchtigt keinen einzigen aktiven Nutzer, weil der nächste Request einfach von einem anderen Node übernommen wird. In der Praxis ist zustandslose Architektur mit zentralem Redis-Session-Storage fast immer die bessere Wahl gegenüber Sticky Sessions, außer in Szenarien mit sehr speziellen WebSocket- oder Long-Polling-Anforderungen.
8. Datenbank-Skalierung: Replikation und Read-Splitting
Während Web-Nodes relativ einfach horizontal skaliert werden können, ist die Datenbank meist der schwierigste Teil der Architektur, weil MySQL/MariaDB von Haus aus nicht für horizontales Schreiben über mehrere Knoten gleichzeitig ausgelegt ist. Der gängige Ansatz: ein primärer Server für Schreiboperationen und ein oder mehrere Read-Replicas für Leseoperationen, verbunden über asynchrone oder semi-synchrone Replikation. Magento unterstützt Read/Write-Splitting nativ über die db-Konfiguration in app/etc/env.php, wo separate Connection-Definitionen für default (Schreiben) und checkout/sales (Lesen) definiert werden können.
Wichtig zu verstehen: Asynchrone Replikation bedeutet, dass Read-Replicas leicht hinter dem Primärserver zurückliegen können (Replication Lag). Für unkritische Leseoperationen wie Katalogabfragen ist das meist unproblematisch, für Prozesse direkt nach einem Schreibvorgang, etwa das sofortige Auslesen einer gerade erstellten Bestellung im Checkout-Flow, kann es zu inkonsistenten Ergebnissen führen, wenn diese Leseoperation versehentlich auf die Replica statt den Primärserver zielt. Kritische Lesevorgänge im Checkout sollten deshalb explizit gegen die primäre Verbindung laufen, nicht gegen die Replica.
| Ansatz | Problem | Empfohlene Lösung | Effekt |
|---|---|---|---|
| Session-Speicher | Lokale PHP-Dateisessions | Zentrales Redis-Backend | Nutzer bleibt eingeloggt, egal welcher Node antwortet |
| Medienspeicher | Lokales pub/media pro Server | NFS-Mount oder S3-Backend | Konsistente Bilder auf allen Nodes |
| Load Balancing | Sticky Sessions per Cookie/IP | Zustandslose Nodes, freies Balancing | Gleichmäßigere Lastverteilung, kein Session-Verlust |
| Health Check | Reiner TCP-Port-Check | HTTP-Health-Endpunkt mit DB/Redis-Prüfung | Defekte Nodes werden zuverlässig erkannt |
| Datenbank | Ein einzelner MySQL-Server | Primary + Read-Replicas, Read/Write-Splitting | Höherer Lesedurchsatz, weniger Single Point of Failure |
Die Tabelle zeigt ein wiederkehrendes Muster: Fast jedes Skalierungsproblem in Magento entsteht aus einer stillschweigenden Annahme, dass ein Server für alles genügt. Die Lösung ist fast immer dieselbe Grundidee, nämlich Zustand zu zentralisieren und den Rest der Architektur zustandslos zu halten, damit horizontale Skalierung ohne versteckte Nebenwirkungen funktioniert.
Mironsoft
Cluster-Architektur, Redis-Sessions und Load-Balancer-Konfiguration für Magento
Bereit für mehr als einen Server?
Wir planen und bauen eure Multi-Server-Architektur: Session-Storage, Shared Media, Load-Balancer-Health-Checks und Datenbank-Replikation, sauber getrennt und ohne versteckte Single Points of Failure.
Architektur-Audit
Analyse bestehender Infrastruktur und Skalierungsengpässe
Session & Storage Migration
Redis-Sessions, NFS/S3-Medienspeicher ohne Downtime einführen
Load-Balancer-Setup
Health Checks, Failover-Strategien und Kapazitätsplanung
10. Zusammenfassung
Die Multi-Server- und Scaling-Architektur für Magento löst ein zentrales Problem: Ein einzelner Server hat eine harte Kapazitätsgrenze und ist gleichzeitig ein Single Point of Failure. Vertikale Skalierung verschiebt diese Grenze nach oben, horizontale Skalierung entfernt sie strukturell, erfordert aber, dass Web-Nodes zustandslos werden. Sessions gehören zentral in Redis, Medien in einen geteilten Speicher wie NFS oder S3, und die Datenbank profitiert von Read-Replicas mit sauberem Read/Write-Splitting für Leseoperationen abseits kritischer Checkout-Pfade.
Der Load Balancer ist das Bindeglied dieser Architektur und muss über echte Application-Level-Health-Checks verfügen, nicht nur einen TCP-Port-Check, damit defekte Nodes zuverlässig aus der Rotation genommen werden. Sticky Sessions sind bei korrekt zentralisiertem Session-Storage nicht mehr nötig und sollten vermieden werden, weil sie die Lastverteilung ungleichmäßig machen und im Fehlerfall trotzdem Sitzungen verlieren. Wer diese Bausteine sauber umsetzt, kann Web-Nodes bei Bedarf beliebig hinzufügen oder entfernen, ohne dass Nutzer davon etwas merken.
Multi-Server- und Scaling-Architektur für Magento - Das Wichtigste auf einen Blick
Horizontal statt vertikal
Mehr gleichartige Server statt ein immer größerer Server. Erfordert zustandslose Web-Nodes.
Sessions zentral in Redis
Nie lokale PHP-Dateisessions im Multi-Server-Setup verwenden. Separate Redis-Instanz oder DB-Index für Sessions.
Shared Media Storage
NFS-Mount oder S3-Backend für pub/media, damit alle Nodes dieselben Bilder sehen.
Health Checks & Read-Replicas
Application-Level-Health-Checks statt reinem TCP-Check. Read/Write-Splitting für Datenbank-Skalierung.