Redis技巧:分片技术和Hash Tag

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Redis技巧:分片技术和Hash Tag相关的知识,希望对你有一定的参考价值。

参考技术A

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

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

不支持的方法:

KEYS,MIGRATE,SCAN等

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

MSET,SINTERSTORE,SUNIONSTORE,ZINTERSTORE,ZUNIONSTORE等

全部请查看 Redis命令列表 .

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

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

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

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

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

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

解铃还需系铃人。解决方法还是从分片技术的原理上找。

分片,就是一个hash的过程:对key做md5,sha1等hash算法,根据hash值分配到不同的机器上。

为了实现将key分到相同机器,就需要相同的hash值,即相同的key(改变hash算法也行,但不简单)。

但key相同是不现实的,因为key都有不同的用途。例如user:user1:ids保存用户的tweets ID,user:user1:tweets保存tweet的具体内容,两个key不可能同名。

仔细观察user:user1:ids和user:user1:tweets,两个key其实有相同的地方,即user1。能不能拿这一部分去计算hash呢?

这就是 Hash Tag 。允许用key的部分字符串来计算hash。

当一个key包含 的时候,就不对整个key做hash,而仅对 包括的字符串做hash。

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

Hash Tag是用于hash的部分字符串开始和结束的标记,例如""、"$$"等。
配置时,只需更改hash_tag字段即可

博客链接: http://spetacular.github.io/2015/09/20/redis-hash-tag.html

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 这个子串会被用来计算哈希值。
  • 对于 foobar 这个键,整个键都会被用来计算哈希值,因为第一个出现的 和它右边第一个出现的 之间没有任何字符。
  • 对于 foozap 这个键,用来计算哈希值的是 bar 这个子串,因为它是第一个 及其右边第一个 之间的内容。
  • 对于 foobarzap 这个键,用来计算哈希值的是 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分配到相同机器。

以上是关于Redis技巧:分片技术和Hash Tag的主要内容,如果未能解决你的问题,请参考以下文章

Redis集群专题「集群技术三部曲」分析一下相关的Redis服务分片技术和Hash Tag(实战篇)

Redis中的Sharding分片机制

动手实践Redis主从复制Sentinel主从切换Cluster分片

聊聊 Redis 分片集群

分布式 | MyCat如何迁移到DBLE之分片算法对比解析:hash分片

redis分片技术