Redis对象结构

Redis数据结构之Redis对象

Redis基本数据类型
Redis提供了5个基本数据类型 : 字符串对象 (string)、列表对象 (list)、哈希对象 (hash)、集合对象 (set)
、有序集合对象 (zset)。这五种基本数据对象都至少使用了之前介绍的一种Redis编码方式。

在这里插入图片描述

Redis对象
Redis中每个对象都由一个 redisObject 结构表示:

typedef struct redisObject {
  //数据类型
  unsigned type:4;
  //数据编码
  unsigned encoding:4;
  //指向底层数组数据结构的指针
  void *ptr;
  //对象引用计数
  unsigned refcount:4;
  //对象空转时长
  unsigned lru:22;
} robj;

举例 : 
    当我们在Redis中执行一个 Set msg “hello world” 时会创建一个键对,Redis底层会创建两个redisObject对象。
其中键值对的键是一个包含了 “msg” 的对象,键值对的值则是一个包含了字符串值 “hello world”的对象。下图是键msg的底层对象描述
    
    typedef struct redisObject {
      //数据类型
      unsigned type = string;
      //数据编码
      unsigned encoding = sds;
      //指向底层数组数据结构的指针
      void *ptr -> hello world;
      //对象引用计数
      unsigned refcount = 1;
      //对象空转时长
      unsigned lru = 20;
    } robj;

Redis对象之type属性
	redis对象的type属性记录了对象的类型,对于Redis数据库保存的键值对来说,键总是一个字符串对象,而值可以是
Redis提供的五种基本数据类型中一种。因此当我们称Redis中某个key为list对象时,其实指的是这个Key中的所对应的值
为list对象。与type属性相对应的是Redis提供的 type 命令。 type命令返回的结果为数据键对应的值对象的类型而不是键
对象的类型。  Redis命令为 : type [key]
Redis对象之encoding 、*ptr 属性

Redis对象的ptr指针指向对象的底层实现数据结构, 而这些数据结构由对象的encoding属性决定. encoding属性记录了对象所使用的编码,也即这个对象使用了什么数据结构作为对象的底层实现

encoding属性可选编码值 :

		编码常量						编码所对应的底层数据结构
   REDIS_ENCODING_INT				    long类型的整数
   REDIS_ENCODING_EMBSTR			    embstr编码的简单动态字符串
   REDIS_ENCODING_RAW					简单动态字符串
   REDIS_ENCODING_HT					字典
   REDIS_ENCODING_LINKEDLIST			双端链表
   REDIS_ENCODING_ZIPLIST				压缩列表
   REDIS_ENCODING_INTSET				整数集合
   REDIS_ENCODING_SKIPLIST         		跳跃表和字典
            
 	与encoding属性相对应的是Redis提供的 encoding 命令。encoding命令返回的结果是值对象所使用编码
    Redis 命令 :    object encoding [key]

每种类型的对象都至少使用了两种不同的编码
字符串对象编码:
    编码							对象
REDIS_ENCODING_INT	(int)		使用整数值实现的字符串对象
REDIS_ENCODING_EMBSTR (emstr)	使用embstr编码的简单动态字符串实现的字符串对象
REDIS_ENCODING_RAW	(raw)		使用简单动态字符串实现的字符串对象
    
1.	如果字符串对象保存的是整数值,并且这个整数可以用long类型表示。那么字符串会使用int编码类型(将*ptr转为long)
2.	如果字符串对象保存的是字符串,并且字符串值长度小于等于32字节。那么字符串会使用embstr编码保存字符串。
3.	如果字符串对象保存的是字符串,并且字符串值长度大宇32字节。那么字符串会使用raw编码保存字符串。

	embstr编码是专门用来保存短字符串的一种优化编码方式,这种编码和raw编码一样,都使用redisObject结构和sdshdr结构来
表示字符串对象。但是raw编码会调用两次内存分配函数分别创建 redisObject结构和sdshdr结构,而embstr编码则通过调用一
次内存分配函数来分配一块连续的空间,空间中依次包含redisObject和sdshdr两个结构。在释放内存时embstr编码只需要调用
一次内存释放函数而raw需要调用两次内存释放。embstr与raw相比能够更好的利用缓存带来优势。需要注意的是Redis没有为
embstr编码提供相应的修改操作,也就是说embstr是只读的。当对embstr编码字符串修改时会先将对象的编码从embstr转为
raw,然后再执行次修改命令。long、double类型表示的浮点数在Redis中也是作为字符串来表示的,如果要保存浮点数到字符
串对象里,redis会将浮点数转为字符串值保存起来。在有需要的时候Redis又会将字符串转为浮点数值执行某些操作,再将操
作所得的浮点数值转回字符串值。
列表对象编码 :
列表对象编码 : ziplist、linkedlist
	当列表对象保存的字符串满足下面两个条件时底层使用ziplist编码不满足这两个条件中任意一个时则会使用linkedlist编码
    	1.元素的长度都小于64字节
    	2.元素数量小于512个
    以上两个条件的上限值是可以修改的,可以通过修改redis配置文件中的
    	list-max-ziplist-value、list-max-ziplist-entries选项进行修改
哈希对象编码 :
哈希对象编码 : ziplist、hashtable
    当哈希对象保存的字符串满足下面两个条件时底层使用ziplist编码不满足这两个条件中任意一个时则会使用hashtable编码
    	1.键值对的键和值的长度都小于64字节
    	2.键值对数量小于512个
    以上两个条件的上限值是可以修改的,可以通过修改redis配置文件中的
    	hash-max-ziplist-value、hash-max-ziplist-entries选项进行修改
集合对象编码 :
集合对象编码 : intset、hashtable
     当集合对象保存的字符串满足下面两个条件时底层使用intset编码不满足这两个条件中任意一个时则会使用hashtable编码。当使用hashtable编码时,set集合中的值保存在字典的键上,而字典的值为null。
    	1.集合对象保存的所有元素都是整数值
    	2.集合对象保存的元素数量小于512个
    以上第二个条件的上限值是可以修改的,可以通过修改redis配置文件中的
    	set-max-ziplist-entries选项进行修改
有序集合对象编码 :
有序集合对象编码 : ziplist、skiplist
    当有序集合对象保存的字符串满足下面两个条件时底层使用ziplist编码不满足这两个条件中任意一个时则会使用skiplist编码。
    	1.有序集合对象保存的所有元素长度都小于 64字节
    	2.集合对象保存的元素数量小于128个
    以上第二个条件的上限值是可以修改的,可以通过修改redis配置文件中的
    	zset-max-ziplist-value、zset-max-ziplist-entries选项进行修改
    
    
    当有序集合使用ziplist编码时,压缩列表内的集合元素按分值从小到大进行排序,分值较小的被放在靠近表头的方向,而分值较大的元素则被放在靠近表尾的方向。
    
    当有序集合使用skiplist编码时,一个zset结构同时包含一个字典和一个skiplist
        typedef struct zset {
            zskiplist * zsl;
            dict *dict;
        }zset;
        
	zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素;跳跃表节点的object属性
保存了元素成员,而跳跃表节点的score属性则保存了元素的分值。通过这个跳跃表可以对有序集合进行范围行操作,比如zrank、
zrange. zset结构中的dict字典为有序集合创建了一个成员到分值的映射,字典的键保存了元素的成员,字典的值保存了元素的
分值。通过这个字典,程序可以用O(1)复杂度查找给定成员的分值,ZSCORE命令就是根据这一特性实现的。虽然zset结构同
时使用跳跃表和字典来保存有序集合元素,但这两中数据结构都会通过指针来共享相同元素的成员和分值,所以同时使用跳跃
表和字典保存集合元素不会产生任何重复成员或分值,也不会因此浪费内存。

在这里插入图片描述

Redis对象之refcount属性
	因为C语言并不具备自动内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数计数实现的内存回收机制,
通过这一机制程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对方并进行内存回收。除了内存回收外,对
象的refcount属性还带有对象共享的作用。假设有1万个key的值都是整数100,那么Redis只需要用一个字符串对象的内存
就可以保存一万个字符串对象的内存才能保存的数据。Redis会在初始化服务器时创建1万个字符串对象 (0~9999的所有整
数值),当服务器需要用到0到9999的字符串对象时Redis会直接共享这些对象而不是创建对象。另外,这些共享对象不单单
只有字符串可以使用,那些在数据结构中嵌套了字符串对象linkedlist/hashtable/zset都可以使用这些对象
      与refcount属性对应的Redis命令是  object refcount [key]

在这里插入图片描述

Redis对象之lru属性
	lru属性记录了对象最后一次被命令程序访问的时间。object idletime 命令可以打印出给定键的空转时
长,这已空转时长就是通过当前时间减去对象的lru时间计算得出的。object idletime命令不会修改对象的lru
属性。如果服务器打开了maxmemory选项,并且使用XXX-lru算法,那么当服务器占用的内存超过最大内存时,空转时长
较高的那部分键会优先被服务器释放掉,从而回收内存。
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值