春哥大魔王的博客

春哥大魔王的博客

前言

由于redis是单线程运行的,如果一次操作的value很大会对整个redis的响应时间造成负面影响,所以业务上通常会以以下方式进行分拆。

分拆

单个key存储大value

每次都是整存整取

这种操作一般都是每次整存整取,这种情况可以尝试将对象拆分成多个key-value,使用multiGet获取值,这样分拆意义在于分拆操作的压力,将操作压力平摊到多个redis实例,降低对于单个redis的io压力。

每次只存取部分数据

同样可以拆成几个key-value,也可以将这些存储在一个hash中,每个field代表具体属性,使用hget,hmget来获取部分value,使用hset,hmset来更新部分属性。

hash,set,zset,list中存储过多数据

同样可以将这部分元素拆分,以hash为例,正常的流程是:hget(hashKey, field);hset(hashKey, field, value)。现在可以固定一个桶数量,比如1w,每次存取的时候,先在本地计算field的hash值,对1w取模,确定field落在哪个key上。

set,zset,list做法类似。

一个集群存储了上亿的key

如果key个数过多会带来更多的内存占用空间:

  1. key本身占用。
  2. 集群中,服务端会建立slot2key的映射关系,这种指针占用在key多的情况下存在巨大的空间浪费,在key上亿时,内存消耗十分明显。

减少key个数可以减少对内存的消耗,可以参考hash结构存储,将多个key存储在一个hash结构中。

组合那些key本身强相关性的,比如key代表一个对象,m每个key是对象的一个属性,按照这种方式设置一个新的key-hash的结构,原先的key作为这个新hash field。

比如:

如果key本身没有相关性,可以预估总量,对一些场景预分固定的桶数量。

比如有2亿key,按照一个hash存储100个field来算,需要200w个桶,这样可以按照200w个固定桶数量做取模,hash(123456) % 200w,比如算出3个key的桶分别是1,2,3。调用存储api hset(key, field, value),读取时用hget(key,field)。建议分桶数量100合适。

Bitmap和Bloom拆分

使用Bloom的场景往往是数据量极大的情况,这种情况下,bitmap和bloom使用空间比较大。

如果bitmap比较大,可以拆分成多个小的bitmap,可以通过结合hash方式,将key路由到hash上对应的bitmap上,将不同的key分配给不同的bitmap,而不是所有小的bitmap当作一个整体,这样每次请求都只要取redis中的一个key即可。

03-11 23:22