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.利用序列化和反序列化的方式 两层对 ...
随机推荐
- equals与hashCode的区别
equals与hashCode的区别 1.类中的equals方法是一定要重写/覆盖(Override)的,因为要让它按照设计的需求来根据特征值判断等价性. 这里的特征值,就是String类型的name ...
- MVC、MVP、MVVM模型
在学习vue.react的过程中,总能看到MVVM模型,那么MVVM究竟是什么,下面将我最近看到的资料以及自己的想法总结一下. 与MVVM相似的,还有MVC.MVP,先从MVC.MVP这两个入手,方面 ...
- Ehcache基础入门
1. 基本介绍 EhCache 是一个纯Java的进程内缓存框架,具有快速.精干等特点,是Hibernate中默认CacheProvider.Ehcache是一种广泛使用的开源Java分布式缓存.主要 ...
- 【解读】TCP协议
本文内容如下: 1)TCP协议概念 2)TCP头部结构和字段介绍 3)TCP流量控制 滑动窗口 4)TCP拥塞控制 慢 ...
- IOT设备SmartConfig实现
一般情况下,IOT设备(针对wifi设备)在智能化过程中需要连接到家庭路由.但在此之前,需要将wifi信息(通常是ssid和password,即名字和密码)发给设备,这一步骤被称为配网.移动设备如An ...
- WPF中的Data Binding调试指南
大家平时做WPF开发,相信用Visual studio的小伙伴比较多.XAML里面曾经在某些特殊版本的Visual Studio中是可以加断点进行调试的,不过目前多数版本都不支持在XAML加断点来调试 ...
- vim/vm命令后提示错误:Found a swap file by the name ".dockerfile.swp"
今天在使用docker时,使用vim命令操作dockerfile文件,提示如下错误: 错误原因,是由于上一次在操作该文件时,异常退出,然后系统生成了一个dockerfile.swp文件,该文件是个隐藏 ...
- ubuntu无法安装vim、tree等解决办法
rm /etc/apt/sources.list.d/* 删除该目录下所有文件
- 我用shell写了个mud游戏:武林群侠传
零.前言 学习shell的时候,无聊的我,写了个简单版的文字mud,暂且叫武林群侠传吧.可能90后都不知道文字mud是什么了--哈哈 壹.效果 先看下效果吧,GIF图如下 文字效果如下: [root@ ...
- Python内置函数和内置常量
Python内置函数 1.abs(x) 返回一个数的绝对值.实参可以是整数或浮点数.如果实参是一个复数,返回它的模. 2.all(iterable) 如果 iterable 的所有元素为真(或迭代器为 ...