Redis 中的散列标签
由于作者水平有限,失误在所难免,如有任何意见或建议,请不吝指正。
Redis Cluster 中有一个称为散列标签的概念,可用于强制将某些键存储在同一个散列槽中。Redis Cluster 不像 Redis 的独立版本那样支持多数据库。它只支持数据库 0;不允许使用 SELECT 命令。 Redis Cluster 实现了非分布式 Redis 版本中可用的所有单键命令。执行复杂的多键操作(如集合并集和交集)的命令要求操作中涉及的所有键散列到同一个槽。
哈希标签是一种确保在同一个哈希槽中分配多个键的方法。 这是为了在 Redis 集群中实现多键操作。
为了实现哈希标签,键的哈希槽在某些条件下以稍微不同的方式计算。简单来说,如果键包含 {...}
模式,则仅对 {
和 }
之间的子字符串进行哈希。 但是,由于 {
或 }
可能多次出现,因此算法由以下更加详细的规则指定:
- 如果键包含
{
字符。 - 且
{
右侧有一个}
字符。 - 且在第一次出现
{
和第一次出现}
之间有一个或多个字符。
那么,不是对整个键进行哈希,而是只哈希第一次出现的 {
和接下来的第一次出现的 }
之间的内容。下面是一些例子:
-
两个键
{user1000}.following
和{user1000}.followers
将哈希到相同的槽,因为只有子字符串user1000
参与计算。 -
对于键
foo{}{bar}
,整个键将被哈希,因为第一次出现{
和}
中间没有字符。 -
对于键
foo{{bar}}zap
,子字符串{bar
将被哈希,因为它是第一次出现{
和第一次出现}
之间的子串。 -
对于键
foo{bar}{zap}
,子字符串bar
将被哈希。 -
从该算法得出的结论是,如果键以
{}
开头,则保证它作为一个整体进行散列。 这在使用二进制数据作为键名时很有用。
以下是 HASH_SLOT
函数的C语言版本:
unsigned int HASH_SLOT(char *key, int keylen) {
int s, e; /* start-end indexes of { and } */
/* Search the first occurrence of '{'. */
for (s = 0; s < keylen; s++)
if (key[s] == '{') break;
/* No '{' ? Hash the whole key. This is the base case. */
if (s == keylen) return crc16(key,keylen) & 16383;
/* '{' found? Check if we have the corresponding '}'. */
for (e = s+1; e < keylen; e++)
if (key[e] == '}') break;
/* No '}' or nothing between {} ? Hash the whole key. */
if (e == keylen || e == s+1) return crc16(key,keylen) & 16383;
/* If we are here there is both a { and a } on its right. Hash
* what is in the middle between { and }. */
return crc16(key+s+1,e-s-1) & 16383;
}
参考资料: