生活本是不进则退,不管这一步走的多多少少,至少要迈出去
线上业务依赖redis做一些数据存储,由于年底的业务量突增,导致redis中的一个key的存储突增,带来的大家口中所说的redis大key问题。
Redis大key带来的问题
命令执行: redis是单线程模型,所以对于一条客户端发起的命令,如果服务器端执行的时间过长,那么必然会导致同一redis slot上其他命令的阻塞。如果是不同的业务共用了同一个redis集群(必然共用同一slot),一个业务的大key问题就会有可能导致其他业务的不可用。
数据存储: 因为大key的问题,导致slot分片数据存储分配不均匀,会导致集群就算有较大的剩余容量,仍然会出现响应慢的情况
为什么redis大key就会导致上边的问题?
以上我只明白了redis大key会给线上服务带来什么样的问题。
1、但什么样的操作导致redis在处理数据的时候那么慢?
2、为什么一个key对应的value数据过大,操作起来就很慢,而redis却能支持上千万的key存储而又不慢呢?
那么针对以上问题,我了解了一下redis底层的数据模型:
redis存储结构
上图可以看到,redis底层db中存放的键空间其实就是一个dict字典的存储,字典的键是一个string类型的key,value则是不同redisObject。
而一般容易发生大key问题的操作,主要是在对list,hash等数据结构进行批量操作的时候。
O(1)操作:对于hget,hmget这种操作,对key进行hash再对dict的长度取模即可获取到对应元素的位置,所以时间复杂度为O(1);
而取到对应的元素之后,如果元素也是dict的话,我们再进行hash取模,获取到对应到field,时间复杂度仍然是O(1);
所以对于单元素的插入,查询等操作的时间复杂度都是O(1);
O(n)操作:但是对于hgetall,hdel,zrange等等很多,需要查询到所有数据的操作,时间复杂度都是O(n),
总结:
那么回到最开始的问题,
问题1在上文中已经有了答案,问题2的答案也很明显,因为操作redis的key其实就是在操作键空间的dict,一般单key的操作时间复杂度都是O(1),所以会比较快;如果也是涉及到查询所有的key,时间复杂度同样是O(n)
网友评论