redis之Zset 底层原理

Zset 有两种编码格式 , 一种是ziplist(双向链表的形式), skiplist(跳跃表的形式),Zset会根据相应的规则来选择编码格式,

一、ziplist (压缩列表)

1.条件 :

  1. 元素个数小于128个
  2. 元素的长度小于64

ziplist采用的是双向的链表的结构实现, 且是一个特殊的双向链表,为啥特殊呢,因为链表的设计采用了连续的内存空间

2.结构:

redis之Zset 底层原理_第1张图片

redis之Zset 底层原理_第2张图片

<zlbytes> <zltail> <zllen> <entry> <entry> ... <entry> <zlend>

zbytes :
整个记录了ziplist占用的字节数 (32位)
ztail :
最后一个数据实体的元素的的偏移量(32位) 这就使得我们能更加快速的找到最后一个元素,它能以O(1)的时间复杂度在表的两端提供push和pop操作
zlen :
数据实体的元素的个数 (16位),当数据量个数超出2^16-1 时,zlen会将16位全部置为1,
这时zlen 不再表示当前ziplist的数据元素个数, 此时要想知道元素个数就只能通过遍历的方式去得到。
zlentry:
ziplist中的数据实体元素
zlend :
ziplist的结束标志位 固定位数值255

不足:
因为内存地址是需要连续的,所以大量的数据的时候不适合,如果是大量的数据的话就会需要大量的连续的内存地址,这可能也是是为啥呀限制,数据超过128后要转出为跳跃表

3.zentry得结构组成

redis之Zset 底层原理_第3张图片

prerawlen :
前一个数据实体的长度,通过当前地址-prerwalen可以快速的找到前一个数据
len:
当前实体的数据长度
endcoding :
编码格式
data :
实际的数据

二、skiplist (跳跃表)

条件:

当不满足ziplist的条件的时候就会使用skiplist的方式,即不满足(元素个数小于128,数据长度小于64)

skiplist 结构其实由一个 score 跳跃链表 + 一个字典构成
字典中记录了每个score —>对应的value 的地址 ,只要通过跳跃表查到对应的score 就可以 在字典 中根据score 快速找到对应的value

结构:

redis之Zset 底层原理_第4张图片

与标准的跳跃表不同, 每次插入数据的时候会随机的产生一个层数,因为如果是严格的跳跃表的话,相邻两节点的层高之比固定为2:1, 这样的话就会存在在加入数据的时候,为了保证层高固定比例而必须去调整后面的节点,就会影响查找的效率
产生随机层数的源码:

#define ZSKIPLIST_MAXLEVEL 32 
#define ZSKIPLIST_P 0.25 

int zslRandomLevel(void) {
    int level = 1;
    while ((random()&0xFFFF) < (ZSKIPLIST_P * 0xFFFF))
        level += 1;
    return (level<ZSKIPLIST_MAXLEVEL) ? level : ZSKIPLIST_MAXLEVEL;
}

每一个节点平均的指针数:=1/(1-p)

你可能感兴趣的:(redis相关,redis,链表,面试)