1、对象的类型与编码

  Redis使用对象来表示数据库中的键和值,每次我们在Redis的数据库中新创建一个键值对,我们至少会创建两个对象,一个键对象,另一个值对象。

  每个对象都由一个redisObject结构表示,如下:

  

1.1、对象的类型和编码

type属性记录了对象的类型:

类型常量  对象的名称
REDIS_STRING 字符串对象
REIDS_LIST 列表对象
REDIS_HASH 哈希对象
REDIS_SET 集合对象
REDIS_ZSET 有序集合对象

encoding记录了对象使用的编码,也就是说这个对象使用了什么数据结构作为对象的底层实现

  

   每个类型的对象都至少使用了两种不同的编码:

  

   使用OBJECT ENCODING key(key就是你要查找的键)命令可以查看一个数据库键的值对象的编码 。

2、字符串对象

  • 字符串对象的编码可以是int、raw、embstr
编码 条件 
raw 1、字符串值长度 > 32字节
embstr  1、字符串值长度 <= 32字节
  • raw和embstr的比较 :

    • embstr编码创建字符串对象所需的内存分配次数从raw编码的两次降低为一次
    • 释放embstr编码的字符串只需调用一个内存释放,raw两次
    • embstr编码的字符串所有数据保存在一块连续的内存中,更好来的利用缓存带来的优势、
  • 可以用long、double类型表示的浮点数在Redis中也是作为字符串值保存。程序会先将浮点数转换为字符串值,然后再保存转换所得的字符串值。在有需要的时候,程序会将保存的字符串值转回浮点数,执行操作。

2.1、编码的转换

  • int ==> raw : 对int对象执行一些命令(比如APPEND),使得对象保存的不再是整数值,变成一个字符串值,那么字符串对象的编码从int变成raw
  • embstr ==> raw : redis没有为embstr编码的字符串对象编写任何修改程序,当我们对embstr编码的字符串对象执行任何修改命令时,程序会先将embstr转换为raw,再执行修改命令。

3、列表对象

  • 列表对象编码可以是ziplist、linkedlist
编码 条件 修改命令
ziplist 1、列表对象保存的所有字符串元素的长度都小于64字节 list-max-ziplist-value
2、列表对象保存的元素数量小于512个 list-max-ziplist-entries
linkedlist 上面不满足任一条件  

4、哈希对象

  • 哈希对象的编码可以是ziplist、hashtable
编码 条件 修改命令
ziplist 1、哈希对象保存的所有键值对的键和值的字符串长度都小于64字节 hash-max-ziplist-value
2、哈希对象保存的键值对数量小于512个 hash-max-ziplist-entries
hashtable 上面不满足任一条件  

5、集合对象

  • 集合对象的编码可以是intset、hashtable
编码 条件 修改命令
intset 1、集合对象保存的所有元素都是整数值  
2、集合对象保存的元素数量不超过512个 set-max-intset-entries
hashtable 上面不满足任一条件  

6、有序集合对象

  • 有序集合的编码可以是ziplist或者skiplist
编码 条件
修改命令
ziplist  1、有序集合保存的元素数量小于128个 zset-max-ziplist-entries
2、有序集合保存的所有元素成员的长度都小于64字节 zset-max-ziplist-value
skiplist 上面不满足任一条件  
  • ziplist编码的压缩列表对象使用压缩列表作为底层实现,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),而第二个元素则保存元素的分值(score)。压缩列表内的集合元素按分值从小到大进行排序,分值较小的元素被放置在靠近表头的方向,而分值较大的元素则被放置在靠近表尾的方向。
  • skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表:

  

    • zset结构中的zsl跳跃表按分值从小到大保存了所有集合元素,每个跳跃表节点都保存了一个集合元素。通过这个跳跃表,程序可以对有序集合进行范围型操作,比如ZRANK、ZRANGE等命令就是基于跳跃表API来实现的
    • zset结构中的dict字典为有序集合创建了一个从成员到分值的映射,字典中的每个键值对都保存了一个集合元素:字典的键保存了元素的成员,而字典的值则保存了元素的分值。通过这个字典,程序可以用O(1)复杂度查找给定成员的分值,ZSCORE命令就是根据这一特性实现的
  • 为什么有序集合需要同时使用跳跃表和字典来实现?
    • 在理论上,有序集合可以单独使用字典或者跳跃表的其中一种数据结构来实现,但无论单独使用字典还是跳跃表,在性能上对比起同时使用字典和跳跃表都会有所降低。举个例子,如果我们只使用字典来实现有序集合,那么虽然以O(1)复杂度查找成员的分值这一特性会被保留,但是,因为字典以无序的方式来保存集合元素,所以每次在执行范围型操作——比如ZRANK、ZRANGE等命令时,程序都需要对字典保存的所有元素进行排序,完成这种排序需要至少O(NlogN)时间复杂度,以及额外的O(N)内存空间(因为要创建一个数组来保存排序后的元素)。另一方面,如果我们只使用跳跃表来实现有序集合,那么跳跃表执行范围型操作的所有优点都会被保留,但因为没有了字典,所以根据成员查找分值这一操作的复杂度将从O(1)上升为O(logN)。因为以上原因,为了让有序集合的查找和范围型操作都尽可能快地执行,Redis选择了同时使用字典和跳跃表两种数据结构来实现有序集合。

7、内存回收

  Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。

  每个对象的引用计数信息由redisObject结构的refcount属性记录:

  

   对象的引用计数信息会随着对象的使用状态而不断变化:

  1. 在创建一个新对象时,引用计数的值会被初始化为1
  2. 当对象被一个新程序使用时,它的引用计数值会被增一
  3. 当对象不再被一个程序使用时,它的引用计数值会被减一
  4. 当对象的引用计数值变为0时,对象所占用的内存会被释放

8、对象共享

   对象的引用计数属性还带有对象共享的作用,范围是0~9999,共享对象不单单只有字符串键可以使用,那些在数据结构中嵌套了字符串对象的对象(linkedlist编码的列表对象、hashtable编码的哈希对象、hashtable编码的集合对象,以及zset编码的有序集合对象)都可以使用这些共享对象

  让多个键共享同一个值对象需要执行以下两个步骤:

  1、将数据库键的值指针指向一个现有对象

  2、将被共享的值对象的引用计数增加一

  为什么Redis不共享包含字符串的对象?

  当服务器考虑将一个共享对象设置为键的值对象时,程序需要先检查给定的共享对象和键想创建的目标对象是否完全相同,只有在共享对象和目标对象完全相同的情况下,程序才会将共享对象用作键的值对象,而一个共享对象保存的值越复杂,验证共享对象和目标对象是否相同所需的复杂度就会越高,消耗的CPU时间也会越多:□ 如果共享对象是保存整数值的字符串对象,那么验证操作的复杂度为O(1);□ 如果共享对象是保存字符串值的字符串对象,那么验证操作的复杂度为O(N);□ 如果共享对象是包含了多个值(或者对象的)对象,比如列表对象或者哈希对象,那么验证操作的复杂度将会是O(N 2)。因此,尽管共享更复杂的对象可以节约更多的内存,但受到CPU时间的限制,Redis只对包含整数值的字符串对象进行共享

9、 对象的空转时长

  除了前面介绍过的type、encoding、ptr和refcount四个属性之外,redisObject结构包含的最后一个属性为lru属性,该属性记录了对象最后一次被命令程序访问的时间。

   OBJECT IDLETIME命令可以打印出给定键的空转时长,这一空转时长就是通过将当前时间减去键的值对象的lru时间计算得出的。

  如果服务器打开了maxmemory选项,并且服务器用于回收内存的算法为volatile-lru或者allkeys-lru,那么当服务器占用的内存数超过了maxmemory选项所设置的上限值时,空转时长较高的那部分键会优先被服务器释放,从而回收内存。

Redis之对象的更多相关文章

  1. redis object 对象系统

    redis object对象系统 概述 redis 当中, sds字符串, adlist双向链表, dict字典, ziplist压缩链表, intset整数集合等均为底层数据结构 redis 并没有 ...

  2. redis存储对象

      redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis存储对象序列化和反序列化 首先来了解一下为什么要实现序列化 为什么要实现序列 ...

  3. redis存储对象与对象序列化详解

    redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis存储对象序列化和反序列化 首先来了解一下为什么要实现序列化 为什么要实现序列化接 ...

  4. redis的对象

    简介:redis并没有直接使用前面所提到的基本数据结构,而是基于基本的数据结构构造了一个对象系统.这个系统包含了字符串对象,列表对象,哈希对象,集合对象,有序集合对象五种类型的对象.每种对象都用到了至 ...

  5. Redis | 使用redis存储对象反序列化异常SerializationFailedException

    案例 使用Redis进行对象存储,在处理业务逻辑的时候,丛Redis获取对象发现反序列化失败,抛出如下异常: Caused by: org.springframework.data.redis.ser ...

  6. 深入了解Redis(3)-对象

    Redis主要的数据结构有简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合,等等.但Redis并没有直接使用这些数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统, 这个 ...

  7. Redis 存储对象信息是用 Hash 还是 String

    Redis 内部使用一个 RedisObject 对象来表示所有的 key 和 value,RedisObject 中的 type,则是代表一个 value 对象具体是何种数据类型,它包含字符串(St ...

  8. 高性能的Redis之对象底层实现原理详解

    对象 在前面的数个章节里, 我们陆续介绍了 Redis 用到的所有主要数据结构, 比如简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合, 等等. Redis 并没有直接使用这些数据结构来实 ...

  9. redis存储对象,实体类新加字段空指针问题处理

    redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...

  10. redis存取对象

    redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis不能直接存取对象,如何解决呢? 两种方式 1.利用序列化和反序列化的方式 两层对 ...

随机推荐

  1. jmeter对数据库进行简单的压测

    1.点击测试计划,再点击“浏览”,把JDBC驱动添加进来: 注:JDBC驱动一般的位置在java的安装地址下,路径类似于:    \java\jre\lib\ext 文件为:mysql-connect ...

  2. Eplan显示项目属性的编号设置方法

    打开eplan,点击选项->设置->用户->显示->用户界面.在“显示标识性的编号”前打勾.

  3. user is not in the sudoers file

    使用用户账户使用sudo来运行一些特权命令时出现了如下错误(sudo是一个允许特定的用户组用另一个用户(典型的是root)的特权来运行一个命令): user is not in the sudoers ...

  4. 龙芯团队完成CoreCLR MIPS64移植,在github开源

    国产龙芯的软件生态之中.NET不会缺席,毕竟 C# 与 .NetCore/Mono 也是全球几大主流的编程语言和运行平台之一,最近一段时间听到太多的鼓吹政务领域不支持.NET, 大家都明白这是某些人为 ...

  5. 重识Java8函数式编程

    前言 最近真的是太忙忙忙忙忙了,很久没有更新文章了.最近工作中看到了几段关于函数式编程的代码,但是有点费解,于是就准备总结一下函数式编程.很多东西很简单,但是如果不总结,可能会被它的各种变体所困扰.接 ...

  6. 微信小程序for循环遍历

    wxml:           <block wx:for="{{data}}" wx:for-item="data">             & ...

  7. 史上最经典的git教程

    原创作品,允许转载,转载时请务必以超链接形式标明文章 原始出处 .作者信息和本声明.否则将追究法律责任.http://wsyht90.blog.51cto.com/9014030/1832284 文档 ...

  8. Java 从入门到进阶之路(二十六)

    在之前的文章我们介绍了一下 Java 中的  集合框架中的Collection 的子接口 List,本章我们来看一下 Java 集合框架中的Collection 的子接口 Queue. 在之前我们讲 ...

  9. tomcat配置项目虚拟路径

    tomcat版本:apache-tomcat-7.0.42 参考:http://blog.csdn.net/pangdingshan/article/details/7214786 一.虚拟根目录 1 ...

  10. Solaris 10上Oracle 10g安装步骤图解

    文章目录 1. 说明 2. 查看相关包 3. 添加用户和组 4. 设置oracle环境变量 5. 创建Oracle软件目录 6. 修改OS参数 7. 上传Oracle软件包并解压 8. 开始安装 9. ...