写点什么

【Redis 集群原理专题】分析一下相关的 Redis 服务分片技术和 Hash Tag

作者:浩宇天尚
  • 2022 年 1 月 14 日
  • 本文字数:1737 字

    阅读完需:约 6 分钟

【Redis集群原理专题】分析一下相关的Redis服务分片技术和Hash Tag

背景介绍

Redis 集群没有使用一致性 hash,而是引入了哈希槽的概念,预分好 16384 个桶,根据 CRC16(key) mod 16384 的值,决定将一个 key 放到哪个桶中,每个 Redis 物理结点负责一部分桶的管理,当发生 Redis 节点的增减时,调整桶的分布即可。

Hash tag 的使用背景

场景 1

为了实现将 key 分到相同机器,就需要相同的 hash 值,即相同的 key,但 key 相同是不现实的,因为 key 都有不同的用途。

Hash tag 实际案例

例如:user:user1:ids 保存用户 id,user:user1:detail 保存用户的具体信息,两个 key 不可能同名。两个 key 其实有相同的地方,即 user。能不能拿这一部分去计算 hash 呢?这就是 Hash Tag。允许用 key 的部分字符串来计算 hash。

场景 2

  1. 哈希标签是确保两个键都在同一个哈希槽里的一种方式,将来也许会使用到哈希标签,例如为了在集群稳定的情况下(没有在做碎片重组操作)允许某些多键操作。

Hash tag 的使用介绍

为了实现哈希标签,哈希槽是用另一种不同的方式计算的。基本来说,如果一个键包含一个 “{…}” 这样的模式,只有 { 和 } 之间的字符串会被用来做哈希以获取哈希槽。但是由于可能出现多个 { 或 },计算的算法如下:


如果键包含一个 { 字符。那么在 { 的右边就会有一个 }。在 { 和 } 之间会有一个或多个字符,第一个 } 一定是出现在第一个 { 之后。
复制代码


然后不是直接计算键的哈希,只有在第一个 { 和它右边第一个 } 之间的内容会被用来计算哈希值。当一个 key 包含 {} 的时候,就不对整个 key 做 hash,而仅对 {} 包括的字符串做 hash。

hash 值计算方式

假设 hash 算法为 sha1。对 user:{user1}:ids 和 user:{user1}:detail,其 hash 值都等同于 sha1(user1)。

例子
  • 两个键 {user1000}.following 和 {user1000}.followers 会被哈希到同一个哈希槽里,因为只有 user1000 这个子串会被用来计算哈希值。

  • 对于 foo{}{bar} 这个键,整个键都会被用来计算哈希值,因为第一个出现的 { 和它右边第一个出现的 } 之间没有任何字符。

  • 对于 foozap 这个键,用来计算哈希值的是 {bar 这个子串,因为它是第一个 { 及其右边第一个 } 之间的内容。

  • 对于 foo{bar}{zap} 这个键,用来计算哈希值的是 bar 这个子串,因为算法会在第一次有效或无效(比如中间没有任何字节)地匹配到 { 和 } 的时候停止。


按照这个算法,如果一个键是以 {} 开头的话,那么就当作整个键会被用来计算哈希值。当使用二进制数据做为键名称的时候,这是非常有用的。

Hash tag 的注意事项

我们在使用 hashtag 特性时,一定要注意,不能把 key 的离散性变得非常差。


没有利用 hashtag 特性之前,key 是这样的:mall:sale:freq:ctrl:860000000000001,很明显这种 key 由于与用户相关,所以离散性非常好。


使用 hashtag 以后,key 是这样的:mall:sale:freq:ctrl:{860000000000001},这种 key 还是与用户相关,所以离散性依然非常好。

糟糕的案例

千万不要这样来使用 hashtag 特性,例如:将 key 设置为:mall:{sale:freq:ctrl}:860000000000001。


这样的话,无论有多少个用户多少个 key,其{}中的内容完全一样都是 sale:freq:ctrl,也就是说,所有的 key 都会落在同一个 slot 上,导致整个 Redis 集群出现严重的倾斜问题。

Twemproxy 的分片技术分析

twitter 的 twemproxy 是一个 Redis 的代理服务程序,能够实现 key 的分片。分片能使 key 均匀地分布到集群的机器上去,能保证数据的一致性,有着众多的优点。


但从 Redis 单实例切换到 twemproxy 集群时,还是有些需要注意的地方,不支持的方法:


KEYS,MIGRATE,SCAN 等


支持但需特殊处理的方法:


MSET,SINTERSTORE,SUNIONSTORE,ZINTERSTORE,ZUNIONSTORE 等


对于不支持的方法,在使用时需要寻找替代方案。本文主要解决一下需特殊处理的方法。MSET


单实例上的 MSET 是一个原子性(atomic)操作,所有给定 key 都会在同一时间内被设置,某些给定 key 被更新而另一些给定 key 没有改变的情况,不可能发生。


而集群上虽然也支持同时设置多个 key,但不再是原子性操作。会存在某些给定 key 被更新而另外一些给定 key 没有改变的情况。其原因是需要设置的多个 key 可能分配到不同的机器上。


SINTERSTORE,SUNIONSTORE,ZINTERSTORE,ZUNIONSTORE


这四个命令属于同一类型。它们的共同之处是都需要对一组 key 进行运算或操作,但要求这些 key 都被分配到相同机器上。


这就是分片技术的矛盾之处:


即要求 key 尽可能地分散到不同机器,又要求某些相关联的 key 分配到相同机器。

发布于: 刚刚阅读数: 2
用户头像

浩宇天尚

关注

🏆InfoQ写作平台-签约作者🏆 2020.03.25 加入

【个人简介】酷爱计算机科学、醉心编程技术、喜爱健身运动、热衷悬疑推理的“极客达人” 【技术格言】任何足够先进的技术都与魔法无异 【技术范畴】Java领域、Spring生态、MySQL专项、微服务/分布式体系和算法设计等

评论

发布
暂无评论
【Redis集群原理专题】分析一下相关的Redis服务分片技术和Hash Tag