Hash-Tags richtig einsetzen, ohne die Sharding-Verteilung zu ruinieren
Wer eine bestehende Redis-Anwendung erstmals gegen einen Redis Cluster betreibt, stößt fast zwangsläufig auf die Fehlermeldung CROSSSLOT keys in request don't hash to the same slot, sobald ein Multi-Key-Befehl wie MGET oder eine Transaktion mehrere Schlüssel gleichzeitig anfasst, die auf unterschiedliche Hash-Slots verteilt sind. Dieser Artikel erklärt, warum dieses Verhalten eine bewusste Design-Entscheidung von Redis Cluster ist, wie sich Hash-Tags gezielt zur Kolokation zusammengehöriger Schlüssel einsetzen lassen und welchen Preis diese Lösung in Form eingeschränkter Sharding-Gleichverteilung kostet.
Inhaltsverzeichnis
- 1. Grundproblem: Redis Cluster und die 16384 Hash-Slots
- 2. Warum Multi-Key-Befehle über verschiedene Slots hinweg standardmäßig scheitern
- 3. Der CROSSSLOT-Fehler in der Praxis: Beispiel und typische Auslöser
- 4. Hash-Tags zur gezielten Slot-Kolokation: die geschweifte Klammer-Syntax
- 5. Praxisbeispiel: Key-Design mit Hash-Tags für Magento-Session-Daten
- 6. Trade-off: Kolokation reduziert die Sharding-Gleichverteilung
- 7. Lua-Skripte im Cluster-Modus: auch EVAL benötigt Slot-Kolokation
- 8. Alternativen: Client-seitiges Fan-out statt Hash-Tags
- 9. Best Practices und Monitoring von Hot Slots im laufenden Betrieb
- 10. Zusammenfassung
- 11. FAQ
1. Grundproblem: Redis Cluster und die 16384 Hash-Slots
Redis Cluster verteilt den gesamten Schlüsselraum auf genau 16384 feste Hash-Slots, wobei jeder Schlüssel über eine CRC16-Prüfsumme seines Namens, modulo 16384, deterministisch genau einem Slot zugeordnet wird. Jeder Knoten im Cluster ist für eine bestimmte Teilmenge dieser Slots verantwortlich, und diese Zuordnung lässt sich über CLUSTER SLOTS oder CLUSTER SHARDS jederzeit einsehen.
Diese Architektur erlaubt horizontale Skalierung, indem sich Slots und damit Daten auf beliebig viele Knoten verteilen lassen, sie bringt aber eine wichtige Einschränkung mit sich: Ein einzelner Befehl wird von genau dem Knoten bearbeitet, der für den betroffenen Slot zuständig ist, ohne dass Redis Cluster selbst eine verteilte Transaktion über mehrere Knoten hinweg koordiniert, wie es etwa eine klassische relationale Datenbank mit einem Zwei-Phasen-Commit tun würde.
2. Warum Multi-Key-Befehle über verschiedene Slots hinweg standardmäßig scheitern
Sobald ein Befehl wie MGET key1 key2 mehrere Schlüssel gleichzeitig referenziert, die unterschiedlichen Slots und damit potenziell unterschiedlichen Knoten zugeordnet sind, kann der angefragte Knoten den Befehl nicht mehr lokal und atomar ausführen. Redis Cluster verweigert solche Befehle deshalb von vornherein, statt intern eine aufwendige, möglicherweise inkonsistente Koordination über mehrere Knoten zu versuchen, und gibt stattdessen einen klaren Fehler zurück.
Dieselbe Einschränkung gilt für Transaktionsblöcke über MULTI und EXEC sowie für Lua-Skripte über EVAL, sobald diese auf Schlüssel verschiedener Slots zugreifen, da Redis für beide Mechanismen dieselbe Atomaritätsgarantie auf einem einzelnen Knoten voraussetzt. Diese bewusste Design-Entscheidung verhindert stille Inkonsistenzen zugunsten eines klaren, sofort sichtbaren Fehlers zur Entwicklungszeit.
3. Der CROSSSLOT-Fehler in der Praxis: Beispiel und typische Auslöser
In der Praxis tritt der Fehler häufig überraschend erst beim Umstieg von einer einzelnen Redis-Instanz oder Sentinel-Topologie auf einen echten Cluster-Modus auf, da Anwendungscode, der zuvor problemlos mehrere Schlüssel in einem MGET zusammenfasste, plötzlich fehlschlägt, obwohl sich am Anwendungscode selbst nichts geändert hat. Besonders betroffen sind Batch-Operationen, die bewusst mehrere Werte in einem einzigen Roundtrip abfragen wollen, um Netzwerklatenz zu sparen.
Auch klassische Muster wie das gemeinsame Sperren und Aktualisieren mehrerer zusammengehöriger Schlüssel innerhalb einer Transaktion, etwa ein Warenkorb-Objekt und ein zugehöriger Zähler, führen ohne gezielte Vorbereitung regelmäßig zu diesem Fehler, sobald beide Schlüssel zufällig auf unterschiedliche Slots gehasht werden.
# Typischer Fehler bei zwei Schlüsseln in unterschiedlichen Slots
redis-cli -c MGET cart:1001 cart:1001:total
# (error) CROSSSLOT Keys in request don't hash to the same slot
# Den Slot eines einzelnen Schlüssels prüfen
redis-cli CLUSTER KEYSLOT cart:1001
redis-cli CLUSTER KEYSLOT cart:1001:total
4. Hash-Tags zur gezielten Slot-Kolokation: die geschweifte Klammer-Syntax
Redis Cluster berechnet den Hash-Slot eines Schlüssels standardmäßig über den vollständigen Schlüsselnamen. Enthält der Schlüsselname jedoch einen Abschnitt in geschweiften Klammern, einen sogenannten Hash-Tag, berechnet Redis den Slot ausschließlich über den Inhalt dieser Klammern und ignoriert den restlichen Schlüsselnamen vollständig bei der Slot-Berechnung.
Damit lassen sich beliebig viele Schlüssel gezielt auf denselben Slot zwingen, indem man ihnen denselben Hash-Tag-Abschnitt voranstellt: cart:{1001} und cart:{1001}:total landen dank des identischen Tags 1001 garantiert im selben Slot und damit auf demselben Knoten, wodurch MGET, Transaktionen und Lua-Skripte über beide Schlüssel hinweg wieder funktionieren.
5. Praxisbeispiel: Key-Design mit Hash-Tags für Magento-Session-Daten
Für ein Magento-Setup, das Redis als Session- oder Cache-Backend im Cluster-Modus betreibt, empfiehlt sich ein konsequentes Key-Design, bei dem alle logisch zusammengehörigen Schlüssel einer Session oder eines Warenkorbs denselben Hash-Tag tragen, etwa die Session-ID selbst als Tag. So bleiben Session-Daten, zugehörige Locks und eventuelle Zähler garantiert auf demselben Knoten kolokiert, ohne dass die Anwendung selbst wissen muss, welcher Knoten physisch zuständig ist.
Wichtig ist dabei, den Hash-Tag bewusst und konsistent über alle beteiligten Schlüssel hinweg zu verwenden, idealerweise zentral in einer gemeinsamen Key-Building-Funktion der Anwendung, statt Tags punktuell und uneinheitlich an einzelnen Stellen im Code zu ergänzen, da inkonsistente Tags denselben CROSSSLOT-Fehler erneut auslösen.
# Schlüssel mit gemeinsamem Hash-Tag anlegen
redis-cli -c SET "session:{a1b2c3}:data" "..."
redis-cli -c SET "session:{a1b2c3}:cart_count" 3
redis-cli -c EXPIRE "session:{a1b2c3}:data" 3600
# Jetzt funktioniert MGET über beide Schlüssel im Cluster-Modus
redis-cli -c MGET "session:{a1b2c3}:data" "session:{a1b2c3}:cart_count"
# Slot-Zuordnung beider Schlüssel ist identisch
redis-cli CLUSTER KEYSLOT "session:{a1b2c3}:data"
redis-cli CLUSTER KEYSLOT "session:{a1b2c3}:cart_count"
6. Trade-off: Kolokation reduziert die Sharding-Gleichverteilung
Der offensichtliche Nutzen von Hash-Tags kommt mit einem strukturellen Nachteil: Je mehr Schlüssel gezielt auf denselben Hash-Tag und damit denselben Slot gezwungen werden, desto weniger gleichmäßig verteilt sich die tatsächliche Last über die verfügbaren Cluster-Knoten. Ein Hash-Tag, der versehentlich für sehr viele Schlüssel gemeinsam genutzt wird, etwa ein globaler Tag statt eines pro Session eindeutigen Tags, kann einen einzelnen Slot und damit einen einzelnen Knoten deutlich stärker belasten als alle anderen.
Diese sogenannten Hot Slots zeigen sich in der Praxis durch eine spürbar ungleiche CPU- oder Speicherauslastung einzelner Knoten trotz augenscheinlich gleichmäßig konfiguriertem Cluster, und lassen sich über CLUSTER COUNTKEYSINSLOT pro Slot sowie über Knoten-Metriken frühzeitig erkennen, bevor sie zu einem echten Performance-Problem werden.
7. Lua-Skripte im Cluster-Modus: auch EVAL benötigt Slot-Kolokation
Dieselbe Hash-Tag-Regel gilt uneingeschränkt für Lua-Skripte, die über EVAL oder EVALSHA ausgeführt werden: Alle Schlüssel, die ein Skript als KEYS-Argumente übergeben bekommt, müssen im Cluster-Modus auf denselben Slot hashen, sonst verweigert der Server die Ausführung mit demselben CROSSSLOT-Fehler, unabhängig davon, wie die interne Logik des Skripts selbst aussieht.
Für Anwendungsfälle, die eine atomare, serverseitige Operation über mehrere logisch zusammengehörige Schlüssel benötigen, etwa das gemeinsame Aktualisieren eines Warenkorb-Objekts und eines Rabattzählers per Lua-Skript, ist konsequentes Hash-Tag-Design deshalb keine Option, sondern eine zwingende Voraussetzung, damit das Skript im Cluster-Modus überhaupt lauffähig bleibt.
8. Alternativen: Client-seitiges Fan-out statt Hash-Tags
Nicht jeder Anwendungsfall eignet sich für Hash-Tags, insbesondere wenn Schlüssel bewusst breit über den Cluster verteilt bleiben sollen, um die Last gleichmäßig zu halten. In solchen Fällen bietet sich stattdessen Client-seitiges Fan-out an: Statt eines einzelnen MGET über alle Schlüssel sendet der Client mehrere einzelne GET-Befehle parallel an die jeweils zuständigen Knoten und fasst die Ergebnisse selbst wieder zusammen.
Moderne cluster-fähige Client-Bibliotheken übernehmen dieses Fan-out oft automatisch und transparent für den Entwickler, sodass ein logischer Multi-Key-Aufruf im Anwendungscode intern in mehrere parallele Einzelbefehle aufgeteilt wird. Der Preis dafür ist der Verlust der Atomarität über alle Schlüssel hinweg, was für reine Lesezugriffe meist unproblematisch ist, bei Schreiboperationen jedoch sorgfältig gegen die Anforderungen der jeweiligen Anwendung abgewogen werden muss.
9. Best Practices und Monitoring von Hot Slots im laufenden Betrieb
Als Faustregel gilt, Hash-Tags gezielt und sparsam für logisch fest zusammengehörige Schlüsselgruppen einzusetzen, deren Anzahl pro Tag begrenzt und vorhersehbar bleibt, etwa alle Schlüssel einer einzelnen Session oder eines einzelnen Warenkorbs, statt Tags für ganze Kategorien oder gar den gesamten Datensatz zu verwenden. Ein guter Test vor dem produktiven Rollout ist die Frage, ob die Anzahl der Schlüssel pro Tag mit der Anzahl der Nutzer oder Sessions linear wächst, statt fix zu bleiben.
Im laufenden Betrieb lohnt sich regelmäßiges Monitoring der Schlüsselverteilung pro Slot über CLUSTER COUNTKEYSINSLOT sowie der CPU- und Speicherauslastung pro Knoten, um Hot Slots frühzeitig zu erkennen, bevor sie zu spürbaren Latenzproblemen für einzelne Nutzer oder Sessions führen, die zufällig auf den überlasteten Slot gehasht werden.
| Ansatz | Atomarität über mehrere Schlüssel | Lastverteilung | Praxisrelevanz |
|---|---|---|---|
| Kein Hash-Tag | Nicht möglich bei verschiedenen Slots | Optimal gleichmäßig | Standardfall ohne Multi-Key-Bedarf |
| Hash-Tag pro Session | Voll erhalten für alle Session-Schlüssel | Gut, da viele unterschiedliche Tags | Empfohlenes Muster für Magento-Sessions |
| Globaler Hash-Tag | Voll erhalten, aber riskant | Stark ungleich, Hot-Slot-Risiko | Nur für sehr kleine, feste Schlüsselmengen |
| Client-seitiges Fan-out | Keine Atomarität über alle Schlüssel | Optimal gleichmäßig | Sinnvoll für reine Lesezugriffe |
| EVAL mit gemeinsamen Tags | Voll erhalten innerhalb des Skripts | Abhängig vom Tag-Design | Notwendig für atomare Lua-Operationen |
Mironsoft
Cache-Layer-Setup und Magento-Redis-Integration
Magento-Cache, der nicht richtig greift oder falsch konfiguriert ist?
Wir richten Redis als Cache- und Session-Backend für Magento sauber ein, tunen Speicherverbrauch und Eviction-Strategien und sorgen dafür, dass Full Page Cache und Session-Storage zuverlässig zusammenspielen.
Redis-Setup
Cache-, Session- und FPC-Backend produktionsreif für Magento konfigurieren.
Memory-Tuning
Speicherverbrauch und Eviction-Policies auf die tatsächliche Shop-Last abstimmen.
High-Availability-Setup
Redis Sentinel oder Cluster für ausfallsichere Magento-Umgebungen einrichten.
10. Zusammenfassung
Cross-Slot-Handling im Redis Cluster: Das Wichtigste auf einen Blick
Grundprinzip
Redis Cluster verteilt Schlüssel über eine CRC16-Prüfsumme deterministisch auf 16384 feste Hash-Slots, und ein Knoten bearbeitet nur die ihm zugeordneten Slots.
CROSSSLOT-Ursache
Multi-Key-Befehle, Transaktionen und Lua-Skripte scheitern, sobald ihre Schlüssel auf unterschiedliche Slots und damit potenziell unterschiedliche Knoten verteilt sind.
Hash-Tag-Lösung
Ein in geschweiften Klammern eingeschlossener Abschnitt des Schlüsselnamens erzwingt, dass Redis nur diesen Abschnitt für die Slot-Berechnung heranzieht, wodurch zusammengehörige Schlüssel gezielt kolokiert werden.
Trade-off
Zu breit gefasste Hash-Tags erzeugen Hot Slots mit ungleicher Lastverteilung, weshalb Tags eng auf logisch zusammengehörige, in der Anzahl begrenzte Schlüsselgruppen wie einzelne Sessions beschränkt bleiben sollten.