Skip to content
huazaiki's blog
Go back

终于理解 Redis Hash Tag 了

Edit page

最近在实操部署 Redis Cluster,我在了解其中原理的时候发现:多条 key 会被分散存储到不同的节点上,所以像 MGET key1 key2 这种跨 key 的命令就不能用了——因为 key1 和 key2 可能不在同一个节点。

然后教程接着讲,用 Hash Tag 可以解决这个问题。你只需要把 key 写成 {user:1}:name{user:1}:age,它们就会被放到同一个节点上,MGET 也能正常用了。

这里的原理并不复杂。Redis Cluster 将数据分布到 16384 个哈希槽,槽号由 CRC16(key) % 16384 计算得出——这是默认行为。而 Hash Tag 的规则只有一条:如果 key 中包含 {...},则只对花括号内的部分做 CRC16 计算。

Key参与 CRC16 计算的部分结果
user:1:nameuser:1:name随机分布
{user:1}:nameuser:1两个 key 落到同一个槽
{user:1}:ageuser:1同上

所以 {user:1}:name{user:1}:age 的计算输入都是 user:1,槽号自然相同,从存入那一刻起就在同一个节点上。这就是 Hash Tag 的全部机制,几句话就能说清。

看到这里的时候,我脑子里冒出一个奇怪的理解。

我以为,不管你有没有用 Hash Tag,key 都是被分散存储的。Hash Tag 的作用只是在读取的时候,能把散在各处的 key”归拢”回来看作一组——像是一种检索魔法。所以当时我特别困惑:既然都存到不同节点了,Redis 凭什么能通过一个 Tag 就把它俩一起取回来?

这个困惑折磨了我挺长时间。直到后来重新翻文档,才意识到一个根本性的误解。

Hash Tag 不是在取的时候才生效的,它在存的时候就决定了 key 的位置。 不是“分开存然后再合起来取”,而是”一开始就没分开”。

那篇教程并没有明确指出这两种情况是两个独立的分支——它先讲了”默认会分散存储,多 key 命令会出问题”,紧接着给了 Hash Tag 的解法,但没有在中间做一个清晰的切断。我脑子自动把两个场景拼接在一起,产生了一个完全错误的模型。

现在回想,如果教程当时多写一句——“使用 Hash Tag 存储数据可以让相关 key 落到同一个槽,从而避免遇到跨节点问题”——这个困惑从一开始就不会存在。


Edit page

Previous Post
上手配置一台新的服务器(一):SSH 与基础安全加固