竹笋

首页 » 问答 » 灌水 » 一个基于运气的数据结构,你猜是啥
TUhjnbcbe - 2024/10/11 18:02:00

作者

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》的论文中提出的。

论文

1
查看完整版本: 一个基于运气的数据结构,你猜是啥