(Redis设计与实现-2) 对象

news/2024/5/17 13:01:10
Redis并没有直接使用内部的基本数据结构来实现键值对数据库,而是基于这些数据结构创建了一个对象系统,这个系统包含字符串对象、列表对象、哈希对象、集合对象和有序集合对象这五种类型的对象, 每种对象都用到了至少一种内部的基本数据结构。

一.对象的结构

typedef struct redisObject {
    unsigned type;// 类型
    unsigned encoding;// 编码
    void *ptr;// 指向底层实现数据结构的指针
    int refcount; // 引用计数
    unsigned lru; //该属性记录了对象最后一次被命令程序访问的时间
} robj;

(1).type属性

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

(2).encoding属性

编码常量编码所对应的底层数据结构
REDIS_ENCODING_INTlong 类型的整数
REDIS_ENCODING_EMBSTRembstr 编码的简单动态字符串
REDIS_ENCODING_RAW简单动态字符串
REDIS_ENCODING_HT字典
REDIS_ENCODING_LINKEDLIST链表
REDIS_ENCODING_ZIPLIST压缩列表
REDIS_ENCODING_INTSET整数集合
REDIS_ENCODING_SKIPLIST跳跃表

(3).refcount

内存回收:因为C语言并不具备自动的内存回收功能,所以Redis在自己的对象系统中构建了一个引用计数(reference counting)技术实现的内存回收机制,通过这一机制,程序可以通过跟踪对象的引用计数信息,在适当的时候自动释放对象并进行内存回收。
a.在创建一个新对象时, 引用计数的值会被初始化为 1 ;
b.当对象被一个新程序使用时, 它的引用计数值会被增一;
c.当对象不再被一个程序使用时, 它的引用计数值会被减一;
d.当对象的引用计数值变为 0 时, 对象所占用的内存会被释放。
对象共享:通过引用技术无需对相同对象重新分配内存,而是直接通过对象共享相同的内存块,共享对象机制对于节约内存非常有帮助, 数据库中保存的相同值对象越多, 对象共享机制就能节约越多的内存。
目前来说,Redis会在初始化服务器时,创建一万个字符串对象,这些对象包含了从0到9999的所有整数值,当服务器需要用到值为0到9999的字符串对象时,服务器就会使用这些共享对象,而不是新创建对象。
a.将数据库键的值指针指向一个现有的值对象;
b.将被共享的值对象的引用计数增一。
Redis只对包含整数值的字符串对象进行共享。

(3).lru

空转时长就是通过将当前时间减去键的值对象的 lru 时间计算得出;可以用于回收内存(当开启maxmemory选项时),空转时长较高的那部分键会优先被服务器释放
volatile-lru:从已设置过期时间的数据集中挑选最近最少使用的数据淘汰
volatile-ttl:从已设置过期时间的数据集中挑选将要过期的数据淘汰
volatile-random:从已设置过期时间的数据集中任意选择数据淘汰
allkeys-lru:从数据集中挑选最近最少使用的数据淘汰
allkeys-random:从数据集中任意选择数据淘汰
no-enviction(驱逐):禁止驱逐数据,只是发出警告


二.字符串对象(REDIS_STRING)

图片描述

图片描述

图片描述

a.如果一个字符串对象保存的是整数值,并且这个整数值可以用long类型来表示,那么字符串对象会将整数值保存在字
符串对象结构的 ptr属性里面(将 void* 转换成 long ),并将字符串对象的编码设置为 int

b.如果字符串对象保存的是一个字符串值,并且这个字符串值的长度大于39字节,那么字符串对象将使用一个简单动态
字符串(SDS)来保存这个字符串值,并将对象的编码设置为 raw 

c.如果字符串对象保存的是一个字符串值,并且这个字符串值的长度小于等于39字节,那么字符串对象将使用 embstr 
编码的方式来保存这个字符串值。(embstr可以连续分配内存)

(1).编码的转换

a.对于int编码的字符串对象来说,如果我们向对象执行了一些命令,使得这个对象保存的不再是整数值,而是一个字
符串值,那么字符串对象的编码将从int变为raw 

b.因为Redis没有为embstr编码的字符串对象编写任何相应的修改程序 (只有 int 编码的字符串对象和 raw 编码的字
符串对象有这些程序),所以 embstr 编码的字符串对象实际上是只读的:当我们对 embstr 编码的字符串对象执行任
何修改命令时,程序会先将对象的编码从 embstr 转换成 raw ,然后再执行修改命令; 因为这个原因,embstr 编码
的字符串对象在执行修改命令之后,总会变成一个 raw 编码的字符串对象。


三.列表对象(REDIS_LIST)

图片描述

图片描述

a.当一个列表对象只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么Redis 
就会使用压缩列表来做列表键的底层实现。

b.当一个列表对象包含较多的列表项,那么Redis就会使用链表结构作为底层实现, 每个双端链表节点(node)都保存
了一个字符串对象, 而每个字符串对象都保存了一个列表元素。

(1).编码转换

a.当列表对象可以同时满足以下两个条件时, 列表对象使用 ziplist 编码:
    列表对象保存的所有字符串元素的长度都小于 64 字节;
    列表对象保存的元素数量小于 512 个;

b.不能满足这两个条件的列表对象需要使用 linkedlist 编码。


四.哈希对象(REDIS_HASH)

图片描述

图片描述

图片描述

a.当一个哈希对象只包含少量键值对,并且每个键值对的键和值要么就是小整数值,要么就是长度比较短的字符串,那
么 Redis 就会使用压缩列表来做哈希键的底层实现。

b.当一个哈希对象包含较多键值对,哈希对象使用字典作为底层实现

(1).编码转换

a.当哈希对象可以同时满足以下两个条件时, 哈希对象使用 ziplist 编码:
    哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节;
    哈希对象保存的键值对数量小于 512 个;
    
b.不能满足这两个条件的哈希对象需要使用 hashtable 编码。


五.集合对象(REDIS_SET)

图片描述

图片描述

a.当一个集合对象只包含整数值元素, 并且这个集合对象的元素数量不多时, Redis就会使用整数集合作为集合对象
的底层实现。

b.当一个集合对象包含非整数值元素,或者元素数量较多时,Redis就会使用字典作为底层实现

(1).编码的转换

a.当集合对象可以同时满足以下两个条件时, 对象使用 intset 编码:
    集合对象保存的所有元素都是整数值;
    集合对象保存的元素数量不超过 512 个;

b.不能满足这两个条件的集合对象需要使用 hashtable 编码。


六.有序集合对象(REDIS_ZSET)

图片描述

图片描述

图片描述

图片描述

a.当一个有序集合对象只包含少量列表项,并且每个列表项要么就是小整数值,要么就是长度比较短的字符串,那么
Redis就会使用压缩列表来做有序集合的底层实现,压缩列表内的集合元素按分值从小到大进行排序, 分值较小的元素
被放置在靠近表头的方向, 而分值较大的元素则被放置在靠近表尾的方向。

b.当一个集合对象包含较多元素,Redis就会使用跳跃表与字典作为底层实现。dict字典为有序集合创建了一个从成员
到分值的映射,通过这个字典, 程序可以用 O(1) 复杂度查找给定成员的分值。zsl跳跃表按分值从小到大保存了所有
集合元素,跳跃表节点的 object 属性保存了元素的成员, 而跳跃表节点的 score 属性则保存了元素的分值。 通过
这个跳跃表, 程序可以对有序集合进行范围型操作,

(1).编码的转换

a.当有序集合对象可以同时满足以下两个条件时, 对象使用 ziplist 编码:
    有序集合保存的元素数量小于 128 个;
    有序集合保存的所有元素成员的长度都小于 64 字节;
    
b.不能满足以上两个条件的有序集合对象将使用 skiplist 编码。

http://www.niftyadmin.cn/n/3071551.html

相关文章

centos8网络连接检测_centos8联网问题

问题1描述:在vm上安装CentOS8后,发现无法联网。解决:1.若一开始ifconfig没有显示网卡,则去设置在系统启动时激活网卡:[rootlocalhost ~]# cd /etc/sysconfig/network-scripts/[rootlocalhost network-scripts]# ls #会看到一个配置…

【Oracle】Oracle锁表处理

问题分析(1)锁的分析ORACLE里锁有以下几种模式:0:none1:null 空2:Row-S 行共享(RS):共享表锁,sub share3:Row-X 行独占(RX):用于行的修改,sub exc…

拆解 米家扫地机器人_1699元!小米米家扫地机器人拆解:真复杂

8月底,小米在北京召开发布会,正式发布了生态链品牌米家旗下的新品:米家扫地机器人,售价1699元。米家扫地机器人采用了十分简洁的外观设计,尤其是透明灰尘盖可以一目了然地看到内部情况。同时,机身外壳还配备…

【跃迁之路】【443天】程序员高效学习方法论探索系列(实验阶段200-2018.04.24)...

(跃迁之路)专栏 实验说明 从2017.10.6起,开启这个系列,目标只有一个:探索新的学习方法,实现跃迁式成长实验期2年(2017.10.06 - 2019.10.06)我将以自己为实验对象。我将开源我的学习方法,方法不断…

flink读取不到文件_大数据培训课程之Flink部署

1 standalone模式1.1 安装解压缩 flink-1.7.0-bin-hadoop27-scala_2.11.tgz修改 flink/conf/flink-conf.yaml 文件修改 /conf/slave文件.分发给 另外两台机子启动访问http://hadoop1:80811.2 提交任务1) 准备数据文件2) 把含数据文件的文件夹,分发到taskmanage 机器…

4月23日云栖精选夜读:阿里AI新物种!设计机器人两年赶上资深员工水平

2019独角兽企业重金招聘Python工程师标准>>> 4月21日,阿里巴巴第七届UCAN用户体验设计论坛上,一系列重磅消息接连抛出:内部孵化两年后,阿里设计机器人鲁班更名为“鹿班”,并首度开始向外输送服务能力&#…

jersey 过滤_在Jersey过滤器中访问请求和响应

在 Jersey ,可以添加 ContainerRequestFilter 或 ContainerResponseFilterpublic class RequestFilter implements ContainerRequestFilter {Overridepublic ContainerRequest filter(ContainerRequest containerRequest) {// logic}}public class ResponseFilter i…

spring boot 之如何在两个页面之间传递值(转)

原文地址:spring boot 之如何在两个页面之间传递值 问题:页面之间的跳转,通常带有值的传输,但是,在现在比较流行的SPRING MVC WEB 开发模型中,设计机制导致页面之间的直接接跳转和传值不被支持(…