redis第八章-对象

文档:redis第八章-对象.note
链接:http://note.youdao.com/noteshare?id=352c39bafcd58562888f0aa894250a07&sub=B89662A963D54020AE587952DEFE446B

对象

redis并没有直接使用之前讲的数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象,列表对象,哈希对象,集合对象和有序集合对象五种。

1.对象的类型和编码

redis的对象其实就是由一个键对象和一个值对象构成。

每个对象由一个redisObject结构表示,该结构和保存数据有关的三个属性分别是type(类型),encoding(编码)和 *ptr(指向底层实现数据结构的指针)属性。

  1. 1.1 type类型

         type是说明该对象是五种数据类型中的其中一个。

  1. 1.2编码和底层实现

2字符串对象

    字符串对象的编码可以是int,raw,embstr。

    如果字符串对象保存的是一个字符串,并且这个字符串值的长度大于32字节,那么这个字符串对象将使用一个简单动态字符串sds来保存这个字符串,并将对象的编码设置为raw。

    如果小于32字节,那么字符串对象的编码使用embstr方式保存,这句话在redis版本不同 字节大小不同.楼主在redis-5-.10上测试 大于44才会变成raw编码格式

   embstr和raw编码都是用于保存短字符串的编码方式,但raw编码会调用两次内存分配函数来分别创建redisObject结构和sdshdr结构,而embstr编码则通过调用一次内存分配函数来分配一块连续的空间,而此空间中依次包含redisObject和sdshdr两个结构。

long,doubble类型表示的浮点数在redis中也是作为字符串值来保存的。

  1. 2.1 编码的转换

        如int编码的字符串对象和embstr编码的字符串对象,在经过一系列的命令之后,使得保存的这个对象不再是int类型,就会变成raw.

          embstr编码的对象是只读的,所以修改embstr编码的对象,首先要转成raw编码.

3。列表对象

        列表对象的编码可以是ziplist或者linkedlist.

      ziplist编码的列表对象使用压缩列表作为底层实现,每个压缩列表节点保存了一个列表元素

         linkerlist编码的列表对象使用双端链表作为底层实现,每个双端链表节点都保存了一个字符 串对象,而每个字符串对象都保存了一个列表元素。

 

注意,linkedlist编码的列表对象在底层的双端链表结构中包含了多个字符串对象,这种嵌套字符串的行为在稍后介绍的哈希对象,集合对象和有序集合对象中都会出现,字符串对象是redis五种类型的对象中唯一 一种会被其他对象类型嵌套的对象。

 

3.1 列表对象的编码转换

列表对象的编码ziplist和linkedlist在一定条件下是可以转换的,当同时满足以下两个条件则使用ziplist

1)当列表对象保存的所有字符串元素的长度都小于64字节

2)列表对象的元素数量小于512个;不能满足这两个条件的列表对象需要使用linkedlist编码

注意:

以上两个条件的上限值是可以修改的,具体配置在list-max-ziplist-value选项和list-max-ziplist-entries选项的说明。

 

以上两个条件,只要有其中一个条件不满足就会由ziplist编码转换到linkedlist编码

 

重要更新:

注:Redis在3.2版本之前List的底层编码是ZipList和LinkedList实现的

在3.2版本之后,重新引入了QuickList的数据结构,列表的底层都是QuickList实现

当List对象中元素的长度比较小或者数量比较少的时候,采用ZipList来存储

当List对象中元素的长度比较大或者数量比较多的时候,采用LinkList来存储

这两种存储方式的优缺点

LinkedList便于在表的两端进行Push和Pop操作,在插入节点复杂度很低,但是它的内存开销很大,首先,它在每个节点上除了要保存数据之外,还要额外保存两个指针。

其次;双向链表的各个节点时单独的内存块,地址不连续,节点多了容易产生内存碎片

ZipList存储在一段连续的内存上,所以存储效率很高,但是它不利于修改操作,插入和删除操作需要频繁的申请释放内存。

特别是当ZipList长度很长的时候,一次Realloc可能导致大批量的数据拷贝

QuickList可以看作一个双向列表,但是列表的每个节点都是一个ziplist,

其实就是linkedlist和ziplist的结合。quicklist中的每个节点ziplist都能够存储多个数据元素。

 

quicklist的结构:

typedef struct quicklist {

quicklistNode *head; // 指向quicklist的头部

quicklistNode *tail; // 指向quicklist的尾部

unsigned long count; // 列表中所有数据项的个数总和

unsigned int len; // quicklist节点的个数,即ziplist的个数

int fill : 16; // ziplist大小限定,由list-max-ziplist-size给定

unsigned int compress : 16; // 节点压缩深度设置,由list-compress-depth给定

} quicklist;

 

count用来统计所有数据项的个数总和,len用来统计quicklist的节点个数, 因为每个节点ziplist都能存储多个数据项,所以有了这两个统计值。

 

typedef struct quicklistNode {

struct quicklistNode *prev; // 指向上一个ziplist节点

struct quicklistNode *next; // 指向下一个ziplist节点

unsigned char *zl; // 数据指针,如果没有被压缩,就指向ziplist结构,反之指向quicklistLZF结构

unsigned int sz; // 表示指向ziplist结构的总长度(内存占用长度)

unsigned int count : 16; // 表示ziplist中的数据项个数

unsigned int encoding : 2; // 编码方式,1--ziplist,2--quicklistLZF

unsigned int container : 2; // 预留字段,存放数据的方式,1--NONE,2--ziplist

unsigned int recompress : 1; // 解压标记,当查看一个被压缩的数据时,需要暂时解压,标记此参数为1,之后再重新进行压缩

unsigned int attempted_compress : 1; // 测试相关

unsigned int extra : 10; // 扩展字段,暂时没用

} quicklistNode;

4.哈希对象

哈希对象的编码可以是ziplist或者hashtable

5.集合对象(set)

集合对象的编码可以是intset或者hashtable。

intset编码的集合对象使用整数集合作为底层实现,集合对象包含的所有元素都被保存在整数集合里面。

127.0.0.1:6379> sadd num 1 3 5

(integer) 3

127.0.0.1:6379> object encoding num

"intset"

 

另一方面,hashtable编码的集合对象使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串包含了一个集合元素,而字典的值全为null。

5.1编码的转换

当集合对象可以同事满足以下两个条件时,对象使用intset编码;

1)集合对象保存的所有元素都是整数值。

2)集合对象保存的元素数量不超过512个。(上限可以修改)

不能满足这两个条件的集合对象使用hashtable编码;

127.0.0.1:6379> object encoding num

"intset"

127.0.0.1:6379> sadd num a

(integer) 1

127.0.0.1:6379> object encoding num

"hashtable"

6.有序集合对象

有序集合对象的编码使用的是ziplist或者skiplist

ziplist编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员,而第二个元素则保存元素的分值。压缩列表内的集合元素按分值从小到大排序,分值小的元素被放置在表头,分值大的在表尾方向。

 

skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表:

zset{

zskiplist *zsl;

dict *dict

}

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值