Redis stores values organized by keys and provides operations on different data structures. It can serve a cache, counters, sessions, collections, or event streams. An instance’s role depends on the data contract and how it is configured and operated; Redis does not turn all its content into a disposable copy.

The key determines which object is identified. The structure determines which operations can act on its value. In Redis Cluster, another decision connects that key to a slot and its primary. Separating identity, operation, and location avoids solving a load problem by accidentally changing the data’s meaning.

Key names and identity

A convention such as user:42:profile or cart:42:items expresses an entity, identifier, and purpose. It makes an entry’s meaning and owner easier to recognize. The separator is an application convention: it does not create folders or relationships on its own.

Prefixes do not create query indexes either. Knowing user:42:profile allows that key to be requested; finding all users by city needs another structure, an explicit index, or an appropriate store. Iterating through keys by pattern is different from an indexed query and can require work proportional to the dataset examined.

Identity must be stable and shared among participants. If each request adds a random suffix to a counter, it no longer updates the same counter. If several keys are created for an entity, the design must explain how they are queried, updated, and removed together.

Choosing a structure and its operations

A key’s value can represent more than text. The data type documentation describes structures with different operations and costs. Examples help choose according to access patterns:

StructurePossible useIllustrative operations
StringA value, counter, or serialized representation.GET, SET, INCR.
HashFields of an object identified by a key.HGET, HSET.
ListA sequence with insertion and removal at its ends.LPUSH, LPOP.
SetUnique members without a guaranteed query order.SADD, SISMEMBER.
Sorted setMembers with a score for ordering or range queries.ZADD, ZRANGE.
StreamLog entries with consumption mechanisms.XADD, XREADGROUP.

Command names illustrate accesses, rather than a complete recipe. A stream or list does not establish a queue’s delivery and recovery contract on its own: acknowledgements, retries, pending work, and persistence still matter.

The specific command’s cost and the size of its inputs and results are reviewed. A point lookup and retrieving an entire collection do different work. Transferred bytes, serialization, and operations on large values can dominate latency even when an operation has favorable complexity relative to the number of elements.

A key holding a huge collection also concentrates memory and work. Expected sizes and accesses should be defined before choosing a structure; adding nodes does not automatically split that object.

Redis Cluster: key, slot, and primary

Redis Cluster distributes 16,384 fixed slots, numbered from 0 to 16,383. The Cluster specification defines CRC16(key) % 16384, except for the hash tag rule. A map assigns each slot to its primary.

This is not a consistent hashing ring. Adding nodes can reassign slots and move their keys without changing the number of slots or the calculation for a stable key. The distinction between logical partition and physical owner is part of sharding design. It does not imply that migration happens without cost or coordination.

To use a hash tag, Redis finds the first { and the first } to its right. If the interior is nonempty, that content is hashed; if there is no valid pair or it is empty, the entire key is used. It does not look for another pair after a first empty pair.

cart:{user:42}:items and cart:{user:42}:meta use user:42 as the hash input. In this example, both map to slot 15880. The illustrative map assigns that slot to primary C; another map can select a different owner without changing the hash.

Arrows show logical routing decisions for those two keys; the hash, slot, and map do not represent separate network services. Primary C is an assignment in the example, rather than an identity embedded in the key or a replica.

---
config:
  look: handDrawn
---
flowchart TD
    keys["cart:{user:42}:items<br/>cart:{user:42}:meta"] --> hash["Hash tag: user:42<br/>CRC16 % 16384"]
    hash --> slot["Slot 15880<br/>logical partition"]
    slot --> routing["Slot map<br/>current topology"]
    routing --> primary["Primary C<br/>illustrative owner"]

Colocation and multi-key operations

Many multi-key operations compatible with Cluster require all keys to be in the same slot. Being on the same node is insufficient: that node can own numerous slots. A hash tag expresses colocation when the operation needs it; it does not turn an entire group of users into a unit that must share placement.

An operation on one cart’s items and metadata can justify a common tag. Using a fixed tag for all carts concentrates their keys into one slot and reduces the ability to distribute them. The unit is chosen according to the operation requiring coordination and the work its owner can sustain.

An atomic update within one command does not make an arbitrary sequence of calls atomic. Scripts and transactional mechanisms have their own restrictions, including the allowed key scope in Cluster. The local atomicity used by a Rate Limiter must be distinguished from a global decision across primaries or an external effect.

Clients must understand topology and routing responses. MOVED and ASK can indicate another destination or a transition; during migration, certain multi-key operations can receive TRYAGAIN. Sharing a slot does not remove every failure condition, and mutation retries need to preserve their meaning.

Hot keys and hot shards

A hot key receives a great deal of work on one object. A hot shard can accumulate load from many keys or one dominant key. Redistributing slots can relieve an overloaded owner, but moving a slot does not divide one key’s work among several primaries.

Adding random suffixes is not a universal solution. Creating counter:42:a and counter:42:b, without hash tags, splits the identity and can distribute the keys, but requires defining updates, reads, and aggregation. In contrast, counter:{user:42}:a and counter:{user:42}:b retain the same tag and remain in the same slot. Suffixes change the model; they do not make that distribution transparent.

Mitigations depend on access patterns. Repeated reads can allow a local cache, request coalescing, and a freshness policy. A replica can serve reads compatible with its lag, but it does not remove the load of a write that the primary must decide. Splitting a collection or counter only fits when the contract allows aggregating parts and resolving concurrency.

Requests, bytes, latency, and work are observed per key and owner. Similar key counts do not establish balanced memory or traffic. The aim is to identify which resource is concentrated and which part of the access can be distributed without breaking the operation.

TTL, eviction, and memory limits

A TTL defines when a key expires according to the expiration mechanism. Eviction removes keys to comply with a memory policy. These are different decisions: an entry with an unexpired TTL can be evicted if the policy includes it, and an entry without a TTL can remain or become a candidate depending on configuration.

Eviction policies are selected for the instance’s use. A policy that removes reconstructible entries does not automatically suit authoritative inventory. Redis uses approximations for policies such as LRU; it should not be described as an exact and infallible classification of the entire workload.

maxmemory guides server policy but is different from the process’s total memory consumption: overhead and replication or persistence buffers can require additional headroom. Key and value size, growth, limits, and behavior when capacity is exhausted must be verified together.

Expiring or removing an entry does not establish that a business operation finished. Ticketing holds require checking authority, ownership, and validity when confirming a sale. A TTL does not replace that decision. Mutations can change expiration according to the command; renewing or preserving it must be explicit.

Persistence, failures, and the data contract

Redis works with data in memory and offers RDB and AOF persistence options. A snapshot preserves a point in time; a log and its synchronization policy change the loss window and operating costs. Choosing an option does not guarantee surviving every failure without losing data.

Replication and high availability are additional decisions. Asynchronous replication can leave a replica behind and lose acknowledged writes when promoting it. Backups, restoration, and recovery still need a contract. Using Redis Cluster does not imply exactly-once behavior or absence of loss.

A timeout can leave it uncertain whether a mutation was applied. Repeating an increment or a payment decision can produce an additional effect if the operation was not designed to tolerate it. Knowing the key and its owner does not replace operation identity and coordination.

If Redis holds a cache, a failure can shift demand to the origin store: fallback needs limits to avoid saturating it. If it holds authoritative state, loss or unavailability must be resolved according to its durability and recovery rules, rather than treating every value as reconstructible.

A useful design explains what each key identifies, which commands act on it, where it is placed, and what can be lost or delayed. Slots, structures, TTLs, and replicas help implement that contract; they do not define it on their own.