using hash tags correctly without wrecking sharding distribution
Anyone running an existing Redis application against a Redis Cluster for the first time almost inevitably runs into the error message CROSSSLOT keys in request don't hash to the same slot as soon as a multi-key command such as MGET, or a transaction, touches several keys at once that are spread across different hash slots. This article explains why this behavior is a deliberate design decision in Redis Cluster, how hash tags can be used deliberately to colocate related keys, and what price that solution costs in terms of restricted sharding distribution.
Table of Contents
- 1. Core problem: Redis Cluster and its 16384 hash slots
- 2. Why multi-key commands across different slots fail by default
- 3. The CROSSSLOT error in practice: an example and typical triggers
- 4. Hash tags for targeted slot colocation: the curly-brace syntax
- 5. Practical example: key design with hash tags for Magento session data
- 6. Trade-off: colocation reduces even sharding distribution
- 7. Lua scripts in cluster mode: EVAL also needs slot colocation
- 8. Alternatives: client-side fan-out instead of hash tags
- 9. Best practices and monitoring hot slots in production
- 10. Summary
- 11. FAQ
1. Core problem: Redis Cluster and its 16384 hash slots
Redis Cluster distributes the entire key space across exactly 16384 fixed hash slots, with every key deterministically assigned to exactly one slot via a CRC16 checksum of its name, modulo 16384. Every node in the cluster is responsible for a certain subset of these slots, and this mapping can be inspected at any time via CLUSTER SLOTS or CLUSTER SHARDS.
This architecture enables horizontal scaling by spreading slots, and therefore data, across as many nodes as needed, but it comes with an important restriction: a single command is handled by exactly the node responsible for the affected slot, without Redis Cluster itself coordinating a distributed transaction across multiple nodes the way, for instance, a classic relational database would with a two-phase commit.
2. Why multi-key commands across different slots fail by default
As soon as a command like MGET key1 key2 references several keys at once that map to different slots, and therefore potentially different nodes, the queried node can no longer execute the command locally and atomically. Redis Cluster therefore refuses such commands outright, rather than attempting complex, potentially inconsistent coordination across multiple nodes internally, and returns a clear error instead.
The same restriction applies to transaction blocks via MULTI and EXEC, as well as to Lua scripts via EVAL, whenever they access keys in different slots, since Redis requires the same single-node atomicity guarantee for both mechanisms. This deliberate design decision favors a clear, immediately visible error at development time over silent inconsistency.
3. The CROSSSLOT error in practice: an example and typical triggers
In practice, the error often shows up unexpectedly when moving from a single Redis instance or a Sentinel topology to a real cluster mode setup, since application code that previously grouped several keys into one MGET without issue suddenly fails, even though the application code itself has not changed. Batch operations that deliberately fetch several values in a single round trip to save network latency are particularly affected.
Classic patterns such as jointly locking and updating several related keys within a transaction, for instance a shopping cart object and an associated counter, also regularly trigger this error without deliberate preparation, as soon as both keys happen to hash to different slots.
# Typical error with two keys in different slots
redis-cli -c MGET cart:1001 cart:1001:total
# (error) CROSSSLOT Keys in request don't hash to the same slot
# Check the slot of a single key
redis-cli CLUSTER KEYSLOT cart:1001
redis-cli CLUSTER KEYSLOT cart:1001:total
4. Hash tags for targeted slot colocation: the curly-brace syntax
By default, Redis Cluster computes a key's hash slot from the full key name. If the key name contains a section wrapped in curly braces, called a hash tag, Redis instead computes the slot exclusively from the contents of those braces and fully ignores the rest of the key name for the slot calculation.
This lets an arbitrary number of keys be forced onto the same slot deliberately by prefixing them with the same hash tag section: cart:{1001} and cart:{1001}:total are guaranteed to land in the same slot, and therefore on the same node, thanks to the identical 1001 tag, which makes MGET, transactions, and Lua scripts across both keys work again.
5. Practical example: key design with hash tags for Magento session data
For a Magento setup running Redis as a session or cache backend in cluster mode, a consistent key design is recommended, where all logically related keys of a session or shopping cart carry the same hash tag, for example the session ID itself as the tag. This keeps session data, associated locks, and any counters guaranteed to be colocated on the same node, without the application itself needing to know which node is physically responsible.
It matters to use the hash tag deliberately and consistently across all involved keys, ideally centralized in a shared key-building function within the application, rather than adding tags ad hoc and inconsistently at scattered points in the code, since inconsistent tags trigger the same CROSSSLOT error again.
# Create keys with a shared hash tag
redis-cli -c SET "session:{a1b2c3}:data" "..."
redis-cli -c SET "session:{a1b2c3}:cart_count" 3
redis-cli -c EXPIRE "session:{a1b2c3}:data" 3600
# MGET across both keys now works in cluster mode
redis-cli -c MGET "session:{a1b2c3}:data" "session:{a1b2c3}:cart_count"
# Both keys map to the identical slot
redis-cli CLUSTER KEYSLOT "session:{a1b2c3}:data"
redis-cli CLUSTER KEYSLOT "session:{a1b2c3}:cart_count"
6. Trade-off: colocation reduces even sharding distribution
The obvious benefit of hash tags comes with a structural downside: the more keys are deliberately forced onto the same hash tag, and therefore the same slot, the less evenly the actual load spreads across the available cluster nodes. A hash tag accidentally shared by very many keys, for instance a global tag instead of one unique per session, can load a single slot, and therefore a single node, noticeably more than all the others.
These so-called hot slots show up in practice as noticeably uneven CPU or memory usage on individual nodes despite an apparently evenly configured cluster, and can be detected early through CLUSTER COUNTKEYSINSLOT per slot as well as node-level metrics, before they turn into a real performance problem.
7. Lua scripts in cluster mode: EVAL also needs slot colocation
The same hash tag rule applies without exception to Lua scripts executed via EVAL or EVALSHA: all keys passed to a script as KEYS arguments must hash to the same slot in cluster mode, or the server refuses execution with the same CROSSSLOT error, regardless of what the script's internal logic actually looks like.
For use cases that need an atomic, server-side operation across several logically related keys, for instance jointly updating a shopping cart object and a discount counter via a Lua script, consistent hash tag design is therefore not optional but a hard requirement for the script to remain runnable at all in cluster mode.
8. Alternatives: client-side fan-out instead of hash tags
Not every use case is a good fit for hash tags, particularly when keys should deliberately stay spread widely across the cluster to keep load even. In such cases, client-side fan-out is an alternative: instead of a single MGET across all keys, the client sends several individual GET commands in parallel to the respective responsible nodes and merges the results itself.
Modern cluster-aware client libraries often handle this fan-out automatically and transparently for the developer, so a logical multi-key call in application code gets internally split into several parallel individual commands. The price is losing atomicity across all keys, which is usually unproblematic for pure read access but must be weighed carefully against the requirements of the given application for write operations.
9. Best practices and monitoring hot slots in production
As a rule of thumb, use hash tags deliberately and sparingly for logically fixed, related groups of keys whose count per tag stays bounded and predictable, for example all keys belonging to a single session or a single shopping cart, rather than using tags for entire categories or the whole dataset. A good test before rolling out to production is whether the number of keys per tag grows linearly with the number of users or sessions, rather than staying fixed.
In production, it is worth regularly monitoring key distribution per slot via CLUSTER COUNTKEYSINSLOT as well as CPU and memory usage per node, to catch hot slots early before they cause noticeable latency problems for individual users or sessions that happen to hash to the overloaded slot.
| Approach | Atomicity across multiple keys | Load distribution | Practical relevance |
|---|---|---|---|
| No hash tag | Not possible across different slots | Optimally even | Default case without multi-key needs |
| Hash tag per session | Fully preserved for all session keys | Good, since many distinct tags exist | Recommended pattern for Magento sessions |
| Global hash tag | Fully preserved, but risky | Highly uneven, hot-slot risk | Only for very small, fixed key sets |
| Client-side fan-out | No atomicity across all keys | Optimally even | Sensible for pure read access |
| EVAL with shared tags | Fully preserved within the script | Depends on tag design | Required for atomic Lua operations |
Mironsoft
Cache layer setup and Magento Redis integration
Magento cache that isn't quite working or is misconfigured?
We set up Redis as a cache and session backend for Magento cleanly, tune memory usage and eviction strategies, and make sure full page cache and session storage work together reliably.
Redis Setup
Configure the cache, session, and FPC backend production-ready for Magento.
Memory Tuning
Match memory usage and eviction policies to the shop's actual load.
High Availability Setup
Set up Redis Sentinel or Cluster for resilient Magento environments.
10. Summary
Cross-Slot Handling in Redis Cluster: The Essentials at a Glance
Core principle
Redis Cluster deterministically distributes keys across 16384 fixed hash slots via a CRC16 checksum, and a node only handles the slots assigned to it.
CROSSSLOT cause
Multi-key commands, transactions, and Lua scripts fail as soon as their keys are spread across different slots, and therefore potentially different nodes.
Hash tag solution
A section of the key name wrapped in curly braces forces Redis to use only that section for the slot calculation, deliberately colocating related keys.
Trade-off
Hash tags scoped too broadly create hot slots with uneven load distribution, so tags should stay narrowly scoped to logically related, bounded key groups such as individual sessions.