2019独角兽企业重金招聘Python工程师标准>>>
前言
由于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上。
newHashKey = hashKey + ( hash(field) % 10000); hset (newHashKey, field, value) ; hget(newHashKey, field)
set,zset,list做法类似。
一个集群存储了上亿的key
如果key个数过多会带来更多的内存占用空间:
- key本身占用。
- 集群中,服务端会建立slot2key的映射关系,这种指针占用在key多的情况下存在巨大的空间浪费,在key上亿时,内存消耗十分明显。
减少key个数可以减少对内存的消耗,可以参考hash结构存储,将多个key存储在一个hash结构中。
组合那些key本身强相关性的,比如key代表一个对象,m每个key是对象的一个属性,按照这种方式设置一个新的key-hash的结构,原先的key作为这个新hash field。
比如:
将user.zhangsan.id= 123,user.zhangsan.age = 18,user.zhangsan.country = china 改成 key = user.zhangsan field:id = 123 field:age = 18 field:country = china
如果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即可。