Command Palette

Search for a command to run...

Hectal
PHASE 11Advanced ~9 min· topic 2 of 5

Topic 11.2

Hash Tags and Multi-Key Operations

In one line

If a key contains {...} with at least one character inside, only that part is hashed. Keys that share a tag land in the same slot, which makes MGET, transactions and Lua across them possible. Choose tags carefully: too coarse a tag creates hot and oversized shards.

0/5 · 0%

Think of it like this

A family booking hotel rooms under one surname. Every room booked under "Sharma" is placed on the same floor, so the family can move between rooms easily. But if a huge wedding party books under one surname, that floor overflows while others sit empty.

Key ideas

  1. 01

    Rules: Redis hashes the substring between the first { and the first } after it, if that substring is non-empty. {user:123}:cart and {user:123}:profile share a slot; user:{}:x has an empty tag, so the whole key is hashed; only the first tag counts.

  2. 02

    Without a shared slot, multi-key commands fail with CROSSSLOT Keys in request don't hash to the same slot. That includes MGET, MSET, SINTER, RENAME, SMOVE, BLMOVE across keys, MULTI touching several keys, and Lua or Functions with several KEYS.

  3. 03

    Pick the tag at the level where you need atomicity: a user, an order, a conversation. Never a tenant, a date, or a constant like {global}, since everything with that tag becomes one shard's problem.

  4. 04

    Some operations don't need tags: pipelines across slots (clients split them per node) and client-side joins (fetch separately, combine in the app). Use tags only where atomicity or a single round trip truly requires it.

  5. 05

    Check the distribution: sample keys, compute slots, and verify load and memory spread (redis-cli --cluster info shows keys per node; watch per-node ops).

Code & diagrams

hash-tags.redisredis
127.0.0.1:6379> CLUSTER KEYSLOT user:123:profile
(integer) 12291
127.0.0.1:6379> CLUSTER KEYSLOT user:123:cart
(integer) 9189
127.0.0.1:6379> MGET user:123:profile user:123:cart
(error) CROSSSLOT Keys in request don't hash to the same slot
127.0.0.1:6379> CLUSTER KEYSLOT {user:123}:profile
(integer) 5236
127.0.0.1:6379> CLUSTER KEYSLOT {user:123}:cart
(integer) 5236
127.0.0.1:6379> MGET {user:123}:profile {user:123}:cart
1) "{...}"
2) "{...}"
checkout.lualua

Both keys share the {user:123} tag, so this script is valid in Cluster.

-- KEYS[1] = {user:123}:cart  KEYS[2] = {user:123}:profile
local tier = redis.call('HGET', KEYS[2], 'tier')
local items = redis.call('HGETALL', KEYS[1])
if #items == 0 then return redis.error_reply('EMPTY_CART') end
redis.call('HSET', KEYS[2], 'lastCheckout', ARGV[1])
return {tier, items}

Interview problem

The problem

Atomic profile + cart update in a cluster

You need to read the user's profile and cart and update both in one atomic operation on Redis Cluster. Design the keys. Then: what happens if one user becomes extremely hot?

The interviewer follows up

01

Can you move one hot hash tag to its own node?

When it breaks

Lua scripts developed on standalone Redis with untagged keys

What you see

In Cluster they fail with CROSSSLOT, or with undeclared keys, fail unpredictably depending on which node runs them.

Fix & prevent

Run CI against a real cluster (for example a 3-node cluster in Docker) and enforce tags for multi-key operations.

Explain it without notes

01

Explain how hash tags work and the rule for choosing a tag.

Practice

01

Rewrite three of your multi-key operations to be cluster-safe, either with tags or by splitting them.

Trade-offs

  • ↔

    Tags enable atomic multi-key logic at the cost of distribution; use them narrowly.

Done when you can

  • I can design hash tags for atomic operations without creating hot shards.

  • I recognise every kind of CROSSSLOT failure.