0
点赞
收藏
分享

微信扫一扫

Redis源码解析:数据结构详解-ziplist


Redis源码解析:数据结构详解-ziplist_redis

压缩列表的数据结构

Redis源码解析:数据结构详解-ziplist_十进制_02

zset和hash容器对象在元素个数较少的时候,采用压缩列表(ziplist)来存储。压缩列表是一块连续的内存空间。结构如下

Redis源码解析:数据结构详解-ziplist_redis_03

属性

类型

长度

用途

zlbytes

uint32_t

4字节

整个压缩列表占用字节数

zltail

uint32_t

4字节

最后一个元素距离压缩列表起始位置的偏移量,用于快速定位最后一个元素

zllen

uint16_t

2字节

压缩列表的节点数量,值小于UINT16_MAX(65535)时,这个属性值就是压缩列表包含节点的数量,值等于UINT16_MAX,节点的数量需要遍历整个压缩列表才能计算得出

entry

不定

不定

元素内容,可以是字节数组,也可以是整数

zlend

uint8_t

1字节

压缩列表结束标志,值恒为0xFF(十进制255)

下图是压缩列表的示意图

Redis源码解析:数据结构详解-ziplist_字节数组_04


zlbytes的值为0x50(十进制80),表示压缩列表的总长度为80字节

zltail的值为0x3c(十进制60),entry3元素距离列表起始位置的偏移量为60,起始位置的指针加上60就能算出表尾节点entry3的地址

zllen的值为0x3(十进制3),表示压缩列表包含3个节点那么每个元素的组成又是怎样的呢?

每个元素的数据结构如下图所示

Redis源码解析:数据结构详解-ziplist_字节数组_05

previous_entry_length

previous_entry_length以字节为单位,记录了压缩列表中前一个节点的长度,这样主要为了方便倒着遍历。通过zltail属性直接定位压缩列表的最后一个节点,然后通过previous_entry_length定位前一个节点。

  1. 如果前一个节点的长度小与254字节,那么previous_entry_length属性的长度为1字节(1个字节可以表示的最大长度为28-1=255,但是255被设置为压缩列表的结束标志了,所以为254)
  2. 如果前一个节点的长度大于等于254字节,那么previous_entry_length属性的长度为5字节。属性的第一字节会被设置成0xFE(十进制为254),而之后的四个字节则用于保存前一字节的长度

当读取内容的时候,content存的是字符串呢?还是整数呢?我们就可以从encoding中判断出来

encoding

encoding存储了元素内容的类型编码信息,ziplist通过这个字段来决定后面的content的形式
Redis通过encoding字段的前缀来识别存储的格式

当encoding最高的2位为11是,说明是数字,否则是字符串

字节数组编码

编码

编码长度

content属性保存的值

00xxxxxx

1字节

长度小于等于63的字节数组(26-1)。前2个位标识类型,后6个字节标识长度

01xxxxxx xxxxxxxx

2字节

长度小于16383的字节数组(214-1)。前2个位标识类型,后14个字节标识长度

10xxxxxx aaaaaaaa bbbbbbbb cccccccc dddddddd

5字节

长度小于232-1的字节数组。前2个位标识类型,第一个字节剩下的6个位不使用, 剩下的32个位标识长度

整数编码

编码

编码长度

content属性保存的值

11000000

1字节

int16_t类型的数

11010000

1字节

int32_t类型的数

11100000

1字节

int64_t类型的数

11110000

1字节

int24类型的数

11111110

1字节

int8类型的数

1111xxxx

1字节

0-12之间的数字,没有content

可以看到编码为 1111xxxx时,没有content

因为编码本身的xxxx四个位已经保存了一个介于0-12之间的值,所以它无需content属性。xxxx的范围只能是(0001-1101),也就是1~13,因为0000,1110,1111都被占用了。读取value后会减1,即能0-12之间的值

content

保存节点的值,节点值可以是字节数组或者整数,值的类型和长度由encoding决定

级连更新

ziplist总结

优点:使用了一块连续的内存,省区了头尾指针占用内存的大小
缺点:对于插入或者增加新的元素会触发连锁更新反应

ZSET

当满足如下2个条件时,zset会用ziplist来存储,否则使用的是dict和skiplist

zset-max-ziplist-entries 128

zset-max-ziplist-value 64

先放member再放socre,按照score从小到大的顺序排列

Redis源码解析:数据结构详解-ziplist_redis_06

HASH

当满足如下2个条件时,hash会用ziplist来存储

// 键值对的长度都小于hash-max-ziplist-value字节
hash-max-ziplist-entries 512

// 键值对的个数小于hash-max-ziplist-entries(一个键值对算一个)
hash-max-ziplist-value 64

底层实现只能从ziplist转为dict

当用ziplist来存储时,数据结构如下

Redis源码解析:数据结构详解-ziplist_数据结构_07


当用dict来存储时,数据结构如下

Redis源码解析:数据结构详解-ziplist_redis_08

参考博客

[1]https://jishuin.proginn.com/p/763bfbd3293c


举报

相关推荐

0 条评论