作者
why技术责编
张文
头图
CSDN下载自东方IC
来源
why技术(ID:hello_hi_why)
从排行榜切入
懂行的老哥一看这个小标题,就知道我要以排行榜作为切入点,去讲Redis的zset了。确实是这样的。
经典面试题:请实现一个排行榜。
大部分情况下就是在考验你知不知道Redis的zset结构以及其对应的操作。
当然了,排行榜我们也可以基于其他的解决方案。比如mysql。
我曾经就基于mysql做过排行榜,一条sql就能搞定。但是仅限于数据量比较少,性能要求不高的场景。说好的只是一个切入点,本文不做过多解析。
如果你不知道具体怎么实现,或者根本就不知道这题在问啥,那一定记得看完本文后要去看看相关的文章,最好自己实操一下。
相信我,得背,这题要考。
zset的内部编码
众所周知,Redis对外提供了五种基本数据类型。但是每一种基本类型的内部编码却是另外一番风景:
其中list数据结构,在Redis3.2版本中还提供了quicklist的内部编码。不是本文重点,我提一嘴就行,有兴趣的朋友自己去了解一下。
本文主要探讨的是上图中的zset数据结构。
zset的内部编码有两种:ziplist和skiplist。
其实你也别觉得这个东西有多神奇。因为对于这种对外一套,对内又是一套的“双标党”,其实你已经很熟悉了。
它就是JDK的一个集合类,来朋友们,大胆的喊出它的名字:HashMap。
HashMap除了基础的数组结构之外,还有另外两个数据结构:一个链表,一个红黑树。
当链表长度大于8且数组长度大于64的时候,HashMap中的链表会转红黑树。
对于zset也是一样的,一定会有条件触发其内部编码ziplist和skiplist之间的变化。
这个条件就藏在redis.conf文件中,其中有两个配置:
上图中配置的含义是,当有序集合的元素个数小于zset-max-ziplist-entries配置的值,且每个元素的值的长度都小于zset-max-ziplist-value配置的值时,zset的内部编码是ziplist。
反之则用skiplist。
理论铺垫上了,接下我给大家演示一波。
首先,我们给memberscore这个有序集合的key设置两个值,然后看看其内部编码:
此时有序集合的元素个数是2,可以看到,内部编码采用的是ziplist的结构。
为了大家方便理解这个储存,我给大家画个图:
然后我们需要触发内部编码从ziplist到skiplist的变化。
先验证zset-max-ziplist-value配置,往memberscore元素中塞入一个长度大于64字节(zset-max-ziplist-value默认配置)的值:
这个时候key为memberscore的有序集合中有3个元素了,其中有一个元素的值特别长,超过了64字节。
此时的内部编码采用的是skiplist。
接下来,我们往zset中多塞点值,验证一下元素个数大于zset-max-ziplist-entries的情况。
我们搞个新的key,取值为whytestkey。
首先,往whytestkey中塞两个元素,这是其内部编码还是ziplist:
那么问题来了,从配置来看zset-max-ziplist-entries。
这个是等于呢还是大于呢?
没关系,我也不知道,试一下就行了。
现在已经有两个元素了,再追加个元素,看看:
通过实验我们发现,当whytestkey中的元素个数是的时候,其内部编码还是ziplist。
那么触发其从ziplist转变为skiplist的条件是元素个数大于,我们再加入一个试一试:
果然,内部编码从ziplist转变为了skiplist。理论验证完毕,zset确实是有两幅面孔。
本文主要探讨skiplist。它也就是标题说的:基于运气的数据结构。
什么是skiplist?
这个结构是一个叫做WilliamPugh的哥们在年发布的一篇叫做《SkipLists:AProbabilisticAlternativetoBalancedTrees》的论文中提出的。
论文