Redis面试--数据结构

Redis数据结构

为什么用Redis

缓存,在内存中,IO多路复用,单线程

Redis有什么用

分布式锁,延迟队列,位图,hyperloglog记录UV,布隆过滤器,限流,GeoHash地理位置计算附近的人。

项目中用到了什么

验证码

Key Value 型

String

底层

ArrayList类似,是字节数组,动态分配长度,字符串长度最大为512M,超过1M会每次增加1M

Simple Dynamic String,支持append操作

SDS

struct SDS {
int8 capacity; // 1byte
int8 len; // 1byte
int8 flags; // 1byte
byte[] content;  // 内联数组,长度为 capacity
}

存储类型:emb vs raw

长度小于44 —因为要分配64个空间,那么一个SDS占用19字节,只剩下45字节选择emb ,大于选择raw。

emb为连续存储空间,raw为不连续

set get del

expire setnx

incr 累加 max为u long

List

底层

LinkedList QuickList–是一个连续空间的链表ziplist

插入快,查询慢

rpush x x1 x2

llen 长度

lpop rpop 左出 右出 队列和栈

慢操作

lindex 获得index所在为止 因为需要遍历链表,所以操作慢

Hash字典

Hash

底层,数组+链表,与hashmap相似,只能保存字符串

rehash不一样,采用了渐进式rehash,保留新旧两个 hash 结构,在空闲时间逐渐rehash

当hash移除了最后一个元素,该数据结构被删除

缺点:结构存储消耗高于单个字符串

hset x key value

hgetall x

hlen x

hget x key

hmset k1 v1 k2 v2 批量增加

底层原理

struct RedisDb {
dict* dict; // all keys key=>value
dict* expires; // all expired keys key=>long(timestamp)

}
struct zset {
dict *dict; // all values value=>score
zskiplist *zsl;
}

内部有两个hashtable --和java的hashmap一样

edis 的字典默认的 hash 函数是siphash,重复性低

hash元素个数大于2倍时考虑扩容,大于5倍时强制扩容。

Set

sadd x key

smembers x 获得x中所有元素

sismember x key 查询是否存在, return 1 0

spop x 弹出一个

scard x 获取x长度

Zset 有序set 底层是链表,所以不能二分查找定位

zadd zrange zcard zrem删除

跳跃列表

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-K0T3GHUK-1593086673887)(Untitled.assets/image-20200607211941308.png)]

层级式,类似于B+树

探索 四个列表

压缩列表 ziplist

struct ziplist {
int32 zlbytes; // 整个压缩列表占用字节数
int32 zltail_offset; // 最后一个元素距离压缩列表起始位置的偏移量,用于快速定位到最后一个
节点
int16 zllength; // 元素个数
T[] entries; // 元素内容列表,挨个挨个紧凑存储
int8 zlend; // 标志压缩列表的结束,值恒为 0xFF
}

支持双向遍历 有 zltail_offset

扩容,可能重新分配一块内存,可能在原有的扩张

intset小整数zipset

set 集合在数量很小的时候不使用 ziplist 来存储

快速列表 quickset

Redis 的跳跃表共有 64 层,意味着最多可以容纳 2^64 次方个元素

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-NeEiCnQT-1593086673897)(Untitled.assets/image-20200607212653612.png)]

跳跃列表 skiplist

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-Va3bNhos-1593086673899)(Untitled.assets/image-20200607212930241.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-1ubwHiMH-1593086673902)(Untitled.assets/image-20200607213021733.png)]

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-rM7zIh9H-1593086673903)(Untitled.assets/image-20200607213032170.png)]

紧凑列表listpack

Redis 5.0 又引入了一个新的数据结构 listpack,它是对 ziplist 结构的改进

struct listpack {
int32 total_bytes; // 占用的总字节数
int16 size; // 元素个数
T[] entries; // 紧凑排列的元素列表
int8 end; // 同 zlend 一样,恒为 0xFF
}

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-2P4lhceB-1593086673905)(Untitled.assets/image-20200607213622391.png)]

不同的是长度字段放在了元素的尾部,而且存储的不是上一个元素的长度,是当前元素的长度。正是因为长度放在了尾部,所以可以省去了 zltail_offset 字段来标记最后一个元素的位置,这个位置可以通过total_bytes 字段和最后一个元素的长度字段计算出来

探索「 「 基数树」 」

Rax 是 Redis 内部比较特殊的一个数据结构,它是一个有序字典树 (基数树 Radix
Tree),按照 key 的字典序排列,支持快速地定位、插入和删除操作。Redis 五大基础数据结
构里面,能作为字典使用的有 hash 和 zset。hash 不具备排序功能,zset 则是按照 score 进
行排序的。rax 跟 zset 的不同在于它是按照 key 进行排序的

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-TEHphKW0-1593086673906)(Untitled.assets/image-20200607215448353.png)]

struct raxNode {
int<1> isKey; // 是否没有 key,没有 key 的是根节点
int<1> isNull; // 是否没有对应的 value,无意义的中间节点
int<1> isCompressed; // 是否压缩存储,这个压缩的概念比较特别
int<29> size; // 子节点的数量或者是压缩字符串的长度 (isCompressed)
byte[] data; // 路由键、子节点指针、value 都在这里
}

你可能感兴趣的:(Redis)