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.利用序列化和反序列化的方式 两层对 ...
随机推荐
- 为什么Web开发人员在2020年不用最新的CSS功能
转载请注明出处:葡萄城官网,葡萄城为开发者提供专业的开发工具.解决方案和服务,赋能开发者. 原文出处:https://dzone.com/articles/why-masses-are-not-usi ...
- Day7-微信小程序实战-引入iconfont(充分利用iconfont图标库的资源)
一.引入iconfont 首先在iconfont.com中注册登陆: 点击上方[图标管理]并进入我的项目 注意:如果没有项目的话,就点击右边的来创建项目 在官网中找到想要的图标之后,以SVG的形式下载 ...
- MySQL-数据库和表的基本操作
数据库和表的基本操作 数据库基础知识 创建数据库 CREATE DATABASE 数据库名称 ; 查看数据库(显示数据库名列表) SHOW DATABASES ; 查看某数据库信息(显示创建的信息) ...
- ArrayList、Vector、LinkedList 区别及底层实现
一.ArrayList.Vector.LinkedList 三者区别 1.ArrayList 底层:是数组结构,查询快,增删慢,线程不安全,效率高.2.LinkedList底层:是链表数据结构,查询 ...
- 一起玩转微服务(13)——AOP
一.什么是AOP编程 AOP: Aspect Oriented Programming 面向切面编程. 面向切面编程(也叫面向方面):Aspect Oriented Programming(AOP), ...
- Eclipse配置maven环境1
一.什么是maven? Maven是一个项目管理工具,它包含了一个项目对象模型 (Project Object Model),一组标准集合,一个项目生命周期(Project Lifecycle),一个 ...
- 搞懂ELK并不是一件特别难的事(ELK)
本篇文章主要介绍elk的一些框架组成,原理和实践,采用的ELK本版为7.7.0版本 一.ELK介绍 1.1.ELK简介 ELK是Elasticsearch.Logstash.Kibana三大开源框架首 ...
- 代码块&&API(object、String、StringBuffer、StringBuilder)
day 07 代码块 局部代码块 定义在方法中,用户划分区域的 构造代码块 和成员方法并列,用{}包裹 每次创建对象的时候都会执行,优先于构造方法 静态代码块 构造代码块前面用static声明 在同类 ...
- py之logging模块
参考:https://www.cnblogs.com/yuanchenqi/articles/5732581.html 一 (简单应用) import logging logging.debug('d ...
- 【必读】前端需要懂的 APP 容器原理
App 容器,简言之,App 承载某类应用(H5/RN/Weex/小程序/Flutter ...)的运行环境,可主动干预并进行功能扩展,达到丰富能力.优化性能.提升体验的目的,如页面数据预取(pref ...