Redis之对象
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
- 当对象被一个新程序使用时,它的引用计数值会被增一
- 当对象不再被一个程序使用时,它的引用计数值会被减一
- 当对象的引用计数值变为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之对象的更多相关文章
- redis object 对象系统
redis object对象系统 概述 redis 当中, sds字符串, adlist双向链表, dict字典, ziplist压缩链表, intset整数集合等均为底层数据结构 redis 并没有 ...
- redis存储对象
redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis存储对象序列化和反序列化 首先来了解一下为什么要实现序列化 为什么要实现序列 ...
- redis存储对象与对象序列化详解
redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis存储对象序列化和反序列化 首先来了解一下为什么要实现序列化 为什么要实现序列化接 ...
- redis的对象
简介:redis并没有直接使用前面所提到的基本数据结构,而是基于基本的数据结构构造了一个对象系统.这个系统包含了字符串对象,列表对象,哈希对象,集合对象,有序集合对象五种类型的对象.每种对象都用到了至 ...
- Redis | 使用redis存储对象反序列化异常SerializationFailedException
案例 使用Redis进行对象存储,在处理业务逻辑的时候,丛Redis获取对象发现反序列化失败,抛出如下异常: Caused by: org.springframework.data.redis.ser ...
- 深入了解Redis(3)-对象
Redis主要的数据结构有简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合,等等.但Redis并没有直接使用这些数据结构来实现键值对数据库, 而是基于这些数据结构创建了一个对象系统, 这个 ...
- Redis 存储对象信息是用 Hash 还是 String
Redis 内部使用一个 RedisObject 对象来表示所有的 key 和 value,RedisObject 中的 type,则是代表一个 value 对象具体是何种数据类型,它包含字符串(St ...
- 高性能的Redis之对象底层实现原理详解
对象 在前面的数个章节里, 我们陆续介绍了 Redis 用到的所有主要数据结构, 比如简单动态字符串(SDS).双端链表.字典.压缩列表.整数集合, 等等. Redis 并没有直接使用这些数据结构来实 ...
- redis存储对象,实体类新加字段空指针问题处理
redis是一个key-value存储系统.和Memcached类似,它支持存储的value类型相对更多,包括string(字符串).list(链表).set(集合).zset(sorted set ...
- redis存取对象
redis主要存储类型最常用的五种数据类型: String Hash List Set Sorted set redis不能直接存取对象,如何解决呢? 两种方式 1.利用序列化和反序列化的方式 两层对 ...
随机推荐
- 小师妹学JVM之:JIT中的LogCompilation
目录 简介 LogCompilation简介 LogCompilation的使用 解析LogCompilation文件 总结 简介 我们知道在JVM中为了加快编译速度,引入了JIT即时编译的功能.那么 ...
- AsyncOperation和SceneManager.LoadSceneAsync协同加载场景
这篇属于杂记,用于记录不甚理解的AsyncOperation AsyncOperation: //加载进度条 public Silder silder; 加载场景 public void LoginG ...
- c++运算符重及其调用
本文参考自:https://blog.csdn.net/lisemi/article/details/93618161 运算符重载就是赋予运算符新功能,其本质是一个函数. 运算符重载时要遵循以下规则: ...
- Charles的介绍,配置与使用
简介 Charles中文名叫青花瓷 它是一款基于HTTP协议的代理服务器 通过成为客户端或者浏览器的代理 然后截取请求和请求结果达到分析抓包的目的. 特点 跨平台 win linux mac 半免费 ...
- centos 6.5 nat方式上网络设置
1 前提虚拟机采用nat的方式和主机进行通信,这个时候再电脑上会模拟一个vmnet8网卡,如果是host-only对应的是vmnet1,配置一样 vmnet8的虚拟网卡,虚拟机通过vmnet8和主机之 ...
- Oracle 导入数据库dmp文件
场景:windows2008 R2系统 ,往新安装的oracle11g数据库导入同事给的dmp文件到指定的新建的用户. 1.创建表空间 在导入dmp文件之前,先打开查看dmp文件的表空间名称(tabl ...
- Python对文本读写的操作方法【源码】
Dear ALL 今天给大家分享的是 TXT文本读写方式,也是文件操作最常用的一种方式,主要内容有: 文件写方法 文件读方法 with open() as f 方法 话不多说,码上见: ''' 标题: ...
- JVM的堆内存泄漏排查-性能测试
JVM异常说明 https://testerhome.com/articles/24259 一文中已介绍了,JVM每个运行时区域--程序计数器 .Java虚拟机栈.本地方法栈.Java堆.方法区.直接 ...
- 区间dp 能量项链 洛谷p1063
题目大意:如果前一颗能量珠的头标记为m,尾标记为r,后一颗能量珠的头标记为r,尾标记为n,则聚合后释放的能量为 (Mars单位),新产生的珠子的头标记为m,尾标记为n. 需要时,Mars人就用吸盘夹住 ...
- FreeSql 使用 ToTreeList/AsTreeCte 查询无限级分类表
关于无限级分类 第一种方案: 使用递归算法,也是使用频率最多的,大部分开源程序也是这么处理,不过一般都只用到四级分类. 这种算法的数据库结构设计最为简单.category表中一个字段id,一个字段fi ...