面试必问 Redis 数据结构底层原理Hash、Set、ZSet,java工程师面试视频

这块倒是跟HashMap一样是2倍扩容

缩容

当hash表中元素被删除到元素个数小于数组长度的10%,就会去缩容。

Set 集合


是什么

类似于Java中的HashSet,内部实现是一个特殊的字典,字典中所有的value都是null,常被用于去重功能。

底层采用了intset整数集合和hashtable字典两种方式来实现的,当满足如下两个条件的时候,采用整数集合实现,否则用哈希表。

  • 集合中的所有元素都为整数

  • 集合中的元素个数不大于 512

可以通过修改 set-max-intset-entries调整集合大小,默认512

set-max-inset-entries 512

其中hashtablekeyset中元素的值,而valuenullinset为可以理解为数组。

intset

sadd key6 1 2 3

3

debug object key6

Value at:0x7f21f2eaddd0 refcount:1 encoding:intset serializedlength:15 lru:13223640 lru_seconds_idle:7

hashtable

sadd key6 a b c

3

debug object key6

Value at:0x7f21f2eaddd0 refcount:1 encoding:hashtable serializedlength:13 lru:13223654 lru_seconds_idle:5

为什么

为什么要优先使用intset整数集合?

  • intset是非常紧凑的数据结构,占用的内存已经压缩的非常小了,可以提高内存的利用率。

  • 查询方式一般采用二分查找法,实际查询复杂度也就在log(n).

  • intset底层是连续的内存空间,对CPU高速缓存支持更友好,提高查询效率。

如何实现

typedef struct intset {

// 编码方式

uint32_t encoding;

// 集合包含的元素数量

uint32_t length;

// 保存元素的数组

int8_t contents[];

}

在这里插入图片描述

intset底层实现为有序无重复数组保存集合元素。 intset这个结构里的整数数组的类型可以是16位的,32位的,64位的。如果数组里所有的整数都是16位长度的,如果新加入一个32位的整数,那么整个16的数组将升级成一个32位的数组。升级可以提升intset的灵活性,又可以节约内存,但不可逆。

ZSet 有序集合


是什么

类似Java中的TreeMap,用set保证value一致性,给每个value一个score属性代表排序权重。

在这里插入图片描述

zset有序,自动去重的集合数据类型,其底层实现为 ziplist + skiplist跳跃表,当数据比较少的时候用ziplist编码结构存储,否则改为跳跃表。

默认按照score排序,score相同则按照元素字典序

同时满足以下两个条件采用ziplist存储:

  • 有序集合保存的元素数量小于默认值128个

  • 有序集合保存的所有元素的长度小于默认值64字节

可以通过修改redis.conf修改默认值

zset-max-ziplist-entries 128 #配置元素个数最多512个

zset-max-ziplist-value 64 #配置value最大为64字节

ziplist

zadd key7 1 a 2 b

2

debug object key7

Value at:0x7f21f2eade10 refcount:1 encoding:ziplist serializedlength:22 lru:13224623 lru_seconds_idle:6

skiplist

zadd key7 1 a 2 b67777777777777777777777777777777777777777777777777777777777777777777777777777777

1

debug object key7

Value at:0x7f21f2eade10 refcount:1 encoding:skiplist serializedlength:43 lru:13224690 lru_seconds_idle:2

怎么实现

ziplist,之前讲不过,zskiplist编码其实就是zset

typedef struct zset {

// 字典,键为成员,值为分值

// 用于支持 O(1) 复杂度的按成员取分值操作

dict *dict;

// 跳跃表,按分值排序成员

// 用于支持平均复杂度为 O(log N) 的按分值定位成员操作

// 以及范围操作

zskiplist *zsl;

}

typedef struct zskiplist {

// 表头节点和表尾节点

struct zskiplistNode *header, *tail;

// 表中节点的数量

unsigned long length;

// 表中层数最大的节点的层数

int level;

} zskiplist;

typedef struct zskiplistNode {

// 成员对象

robj *obj;

// 分值

double score;

// 后退指针

struct zskiplistNode *backward;

// 层

struct zskiplistLevel {

// 前进指针

struct zskiplistNode *forward;

// 跨度—前进指针所指向节点与当前节点的距离

unsigned int span;

} level[];

} zskiplistNode;

zskiplist编码分为两部分,dict+ zskiplistdict跳跃表都存储数据,实际上 dict 和跳跃表最终使用指针都指向了同一份数据,即数据是被两部分共享的,dict结构,主要key是其集合元素,而value就是对应分值,而zkiplist作为跳跃表,按照分值排序,方便定位成员。

盗个图:

在这里插入图片描述

来源:https://juejin.cn/post/6863258283483807752

skiplist的查找时间复杂度是 O(log N),可以和平衡二叉树相当,但实现起来又比它简单。

为什么

这里redis为什么用跳表而不像Java的TreeMap一样用红黑树呢?

对于这个问题,Redis的作者 @antirez 是怎么说的:

There are a few reasons:

1) They are not very memory intensive. It’s up to you basically. Changing parameters about the probability of a node to have a given number of levels will make then less memory intensive than btrees.

2) A sorted set is often target of many ZRANGE or ZREVRANGE operations, that is, traversing the skip list as a linked list. With this operation the cache locality of skip lists is at least as good as with other kind of balanced trees.

3) They are simpler to implement, debug, and so forth. For instance thanks to the skip list simplicity I received a patch (already in Redis master) with augmented skip lists implementing ZRANK in O(log(N)). It required little changes to the code.

简单概括下

  • 内存占用相比于树更少,跳跃表使用的指针比树更少,64位操作系统每个指针占用8字节

  • 跳跃表范围查询支持更友好

  • 算法实现难度上相比于树实现起来更简单

小编13年上海交大毕业,曾经在小公司待过,也去过华为、OPPO等大厂,18年进入阿里一直到现在。

深知大多数初中级Java工程师,想要提升技能,往往是自己摸索成长,但自己不成体系的自学效果低效又漫长,而且极易碰到天花板技术停滞不前!

因此收集整理了一份《2024年最新Java开发全套学习资料》送给大家,初衷也很简单,就是希望能够帮助到想自学提升又不知道该从何学起的朋友,同时减轻大家的负担。
img
img
img

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
img

最后

本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们:

目录:

二面蚂蚁金服(交叉面),已拿offer,Java岗定级阿里P6

Java面试核心知识点

一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!

二面蚂蚁金服(交叉面),已拿offer,Java岗定级阿里P6

Java面试核心知识点

uf9aXKK3-1711200481714)]

由于文件比较大,这里只是将部分目录截图出来,每个节点里面都包含大厂面经、学习笔记、源码讲义、实战项目、讲解视频

如果你觉得这些内容对你有帮助,可以添加下面V无偿领取!(备注Java)
[外链图片转存中…(img-9nejEY9v-1711200481715)]

最后

本人也收藏了一份Java面试核心知识点来应付面试,借着这次机会可以送给我的读者朋友们:

目录:

[外链图片转存中…(img-8dfRKH7m-1711200481715)]

Java面试核心知识点

一共有30个专题,足够读者朋友们应付面试啦,也节省朋友们去到处搜刮资料自己整理的时间!

[外链图片转存中…(img-gfzygCRK-1711200481716)]

Java面试核心知识点

本文已被CODING开源项目:【一线大厂Java面试题解析+核心总结学习笔记+最新讲解视频+实战项目源码】收录

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值