采访者:Redis的基本数据类型有哪些?我:Redis的基本数据类型有:字符串(string)、哈希(hash)、列表(list)、集合(set)、有序集合(zset)。面试官:sortedsets的内部实现是怎样的?我还沉浸在最后一题的得意中,脸色顿时一僵,手心开始渗出冷汗。“这个……我了解不深。”我吞吞吐吐的说道。采访者:回去等消息吧。这句话干干净净,然后就没有了。失败是成功之母,我没有气馁,决定马上弥补。有序集合的内部实现有序集合的内部实现有两种,分别是:压缩列表(ziplist)和跳跃列表(skiplist)。接下来,我们对每一个进行详细的了解。当有序集合中的元素个数小于zset-max-ziplist-entries(默认为128),且每个元素成员的长度小于zset-max-ziplist-value(默认为64字节)时,使用打包列表作为有序集的内部实现。每个集合元素由两个相邻的压缩列表节点组成,其中第一个节点保存元素的成员,第二个节点保存元素的分支。压缩列表中的元素按照分数从小到大依次排列,有效减少了内存空间的使用。例如,我们使用zadd命令创建一个以压缩列表形式实现的有序集:127.0.0.1:6379>zaddone-more-zset1one2two3three(integer)3127.0.0.1:6379>zrangeone-more-zset0-11)"one"2)"two"3)"three"127.0.0.1:6379>objectencodingone-more-zset"ziplist"使用跳转列表作为内部实现,当元素个数在一个orderedset当大于等于zset-max-ziplist-entries(默认为128),或者每个元素成员的长度大于等于zset-max-ziplist-value(默认为64字节)时,使用跳表作为内部实现的有序集。此时,有序集实际上包含了两种结构,一种是跳表,一种是哈希表。在跳转列表中,所有元素按升序排列。跳表节点中的对象指针指向元素成员的字符串对象,score存储元素的分数。通过跳表,Redis可以快速对有序集合进行分值范围、排序等操作。在哈希表中,为排序集创建从元素成员到元素分数的映射。键值对中的key指向元素成员的字符串对象,键值对中的值保存着元素的分数。通过哈希表,Redis可以快速找到指定元素的分数。尽管排序集同时使用跳转表和哈希表,但这两种数据结构都使用指针来共享元素中的成员和分数,而不会浪费额外的内存。例如,我们使用zadd命令创建一个有序集作为跳表实现:127.0.0.1:6379>zaddone-more-zset1long-long-long-long-long-long-long-long-long-long-long-long-long(整数)1127.0.0.1:6379>zrangeone-more-zset0-11)“long-long-long-long-long-long-long-long-long-long-long-long-long-long-long"127.0.0.1:6379>objectencodingone-more-zset"skiplist"内部实现的转换当一个有序集内部用压缩列表实现时,添加更多的Long元素成员,或者当有这个有序集合中的元素太多,那么这个有序集合就会转为一个跳表作为内部实现。但是,在内部使用跳跃列表实现的有序集合不会在内部转换为打包列表。例如,让我们首先创建一个带有压缩列表的有序集合作为内部实现:127.0.0.1:6379>zaddone-more-zset1one2two3three(integer)3127.0.0.1:6379>zrangeone-more-zset0-11)"one"2)"two"3)"three"127.0.0.1:6379>objectencodingone-more-zset"ziplist"然后,给它添加一个更长的成员元素,就是Converttojumptable作为内部实现:127.0.0.1:6379>zaddone-more-zset4long-long-long-long-long-long-long-long-long-long-long-long-long-long(整数)1127.0.0.1:6379>zrangeone-more-zset0-11)"one"2)"two"3)"three"4)"long-long-long-long-long-long-long-long-long-long-long-long-long-long"127.0.0.1:6379>objectencodingone-more-zset"skiplist"然后,从有序集合中移除较长成员的元素,有序集合仍然使用跳表作为内部实现:127.0.0.1:6379>zremone-more-zsetlong-long-long-long-long-long-long-long-long-long-long-long-long-long(整数)1127.0.0.1:6379>zrangeone-more-zset0-11)"一"2)"二"3)"三"127.0.0.1:6379>objectencodingone-more-zset"skiplist"总结一下,在Redis中,有序集合的内部实现有压缩列表(ziplist)和跳跃列表(skiplist)两种。当集合中所有元素的成员长度较短且元素个数较少时,使用压缩列表作为内部实现,否则使用跳表和哈希表作为内部实现当不满足条件时,压缩列表可以转换为skiptable,但是skiptable不能转换为压缩列表。这点我早就看出来了,你我一定是有缘,留下你的喜欢和关注,你日后必成大器。
