当前位置: 首页 > news >正文

Redis 学习笔记(篇五):对象(RedisObject)

Redis-对象

在以前的文章中,我们介绍了 Redis 用到的主要数据结构,比如简单动态字符串、双端链表、字典、压缩列表、整数集合。
然而 Redis 并没有直接使用这些数据结构来实现键值对的数据库,而是在这些数据结构之上又包装了一层 RedisObject(对象),RedisObject 有五种对象:字符串对象、列表对象、哈希对象、集合对象和有序集合对象。

还是跟以前一样,看几个问题:

  • 使用 RedisObject 对象而不是直接使用双端队列、双端链表等数据结构,有什么好处呢?
  • RedisObject 的具体结构是什么?
  • 五种对象(string、hash、list、set、sort set)对应的 RedisObject 对象有何不同,底层使用的数据结构是什么?

使用 RedisObject 的好处

使用 RedisObject 的优点主要有两个,分别是:

  1. 通过不同类型的对象,Redis 可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。
  2. 我们可以针对不同的使用场景,为对象设置不同的实现,从而优化内存或查询速度。

RedisObject 的具体结构是什么?

RedisObject 的源码如下:

typedef struct redisObject {

    // 类型
    unsigned type:4;

    // 编码
    unsigned encoding:4;

    // 对象最后一次被访问的时间
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */

    // 引用计数
    int refcount;

    // 指向实际值的指针
    void *ptr;

} robj;

下面分别解释一下各个字段的含义:

  1. type
    type 记录了对象的类型,所有的类型如下(出自《Redis设计与实现第二版》第八章:对象):
    《Redis设计与实现第二版》61页
    对于 Redis 数据库保存的键值对来说,键一定是一个字符串对象,而值则可以使五种对象的其中一种。

  2. ptr 指针:指向对象的底层实现数据结构;

  3. encoding
    encoding 表示 ptr 指向的具体数据结构,即这个对象使用了什么数据结构作为底层实现。
    encoding 的取值范围如下(出自《Redis设计与实现第二版》第八章:对象):
    《Redis设计与实现第二版》62页
    每种类型的对象都至少使用了两种不同的编码,对象和编码的对应关系如下(出自《Redis设计与实现第二版》第八章:对象):
    《Redis设计与实现第二版》63页

  4. refcount
    refcount 表示引用计数,由于 C 语言并不具备内存回收功能,所以 Redis 在自己的对象系统中添加了这个属性,当一个对象的引用计数为0时,则表示该对象已经不被任何对象引用,则可以进行垃圾回收了。
    扩展一下:Java中由于引用计数法解决不了循环引用的问题,所以 Java 中使用了可达性分析算法。那么 Redis 有没有考虑循环引用的问题呢?

  5. lru:表示对象最后一次被命令程序访问的时间。

五种对象对应的 RedisObject

字符串对象(string)

字符串对象的 encoding 有三种,分别是:int、raw、embstr。

  1. 如果一个字符串对象保存的是整数值,并且这个整数值可以用 long 类型标识,那么字符串对象会讲整数值保存在 ptr 属性中,并将 encoding 设置为 int。
    假设有如下命令:set number 10086。那么 number 键对象的示意图如下(出自《Redis设计与实现第二版》第八章:对象):
    《Redis设计与实现第二版》64页

  2. 如果字符串对象保存的是一个字符串值,并且这个字符串的长度大于 32 字节,那么字符串对象将使用一个简单动态字符串(SDS)来保存这个字符串值,并将对象的编码设置为 raw。
    使用 raw 存储字符串的示意图如下(出自《Redis设计与实现第二版》第八章:对象):
    《Redis设计与实现第二版》65页

  3. 如果字符串对象保存的是一个字符串值,并且这个字符串的长度小于等于 32 字节,那么字符串对象将使用 embstr 编码的方式来保存这个字符串。
    使用 embstr 存储字符串的示意图如下(出自《Redis设计与实现第二版》第八章:对象):
    《Redis设计与实现第二版》65页

既然有了 raw 的编码方式,为什么还会有 embstr 的编码方式呢?
因为 embstr 的编码方式有一些优点,如下:

  • embstr 编码将创建字符串对象所需的内存分配次数从 raw 编码的两次降低为一次。
  • 释放 embstr 编码的字符串对象只需要调用一次内存释放函数,而释放 raw 编码的字符串对象需要调用两次内存释放函数。
  • 因为 embstr 编码的字符串对象的所有数据都保存在一块连续的内存里面,所以这种编码的字符串对象比起 raw ,编码的字符串对象能够更好地利用缓存带来的优势。

哈希对象(hash)

哈希对象的编码有两种,分别是:ziplist、hashtable。
当哈希对象保存的键值对数量小于 512,并且所有键值对的长度都小于 64 字节时,使用压缩列表存储;否则使用 hashtable 存储。

哈希对象的压缩列表对应的示意图如下(出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

哈希对象的 hashtable 对应的示意图如下(出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

列表对象(list)

列表对象的编码有两种,分别是:ziplist、linkedlist。

ziplist(压缩列表)主要是为节省内存而设计的内存结构,它的优点就是节省内存,但缺点就是比其他结构要消耗更多的时间,所以 Redis 在数据量小的时候使用压缩列表存储。

当列表的长度小于 512,并且所有元素的长度都小于 64 字节时,使用压缩列表存储;否则使用 linkedlist 存储。

列表对象的压缩列表对应的示意图如下出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

列表对象的链表对应的示意图如下出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

集合对象(set)

集合对象的编码有两种,分别是:intset、hashtable。

intset(整数集合)主要是为节省内存而设计的内存结构,它的优点就是节省内存,但缺点就是比其他结构要消耗更多的时间,所以 Redis 在数据量小的时候使用整数集合存储。

当集合的长度小于 512,并且所有元素都是整数时,使用整数集合存储;否则使用 hashtable 存储。

集合对象的 intset 对应的示意图如下出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

集合对象的 hashtable 对应的示意图如下出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

有序集合对象(sort set)

有序集合对象的编码有两种,分别是:ziplist、skiplist。

当有序集合的长度小于 128,并且所有元素的长度都小于 64 字节时,使用压缩列表存储;否则使用 skiplist 存储。

有序集合对象的 ziplist 对应的示意图如下出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

有序集合对象的 skiplist 对应的示意图如下出自《Redis设计与实现第二版》第八章:对象):

《Redis设计与实现第二版》

转载于:https://www.cnblogs.com/wind-snow/p/11172832.html

相关文章:

  • Codevs 3981 动态最大子段和
  • A 小石的签到题
  • 又是问题~~~
  • Sql: 請假跨月份問題,或跨年份問題 日期部分边界
  • OpenFlow通信流程解读
  • React 入门与实战-课时7 虚拟DOM的本质和目的
  • sort函数和next_permutation()函数的用法。
  • 舵机控制原理
  • BZOJ1123 BLO
  • Mac下的PHP的配置与运行
  • 数据映射工具 AssionMapper
  • Navicat 连接MySQL 8.0.11 出现2059错误
  • 牛客练习赛33 C tokitsukaze and Number Game (结论+字符串处理)
  • 【知识库】-数据库_数据库事务与隔离级别
  • cpan 配置
  • [case10]使用RSQL实现端到端的动态查询
  • bootstrap创建登录注册页面
  • C学习-枚举(九)
  • iOS动画编程-View动画[ 1 ] 基础View动画
  • JavaScript服务器推送技术之 WebSocket
  • JavaScript函数式编程(一)
  • Js基础——数据类型之Null和Undefined
  • leetcode386. Lexicographical Numbers
  • Meteor的表单提交:Form
  • overflow: hidden IE7无效
  • vue-cli3搭建项目
  • 多线程 start 和 run 方法到底有什么区别?
  • 简单数学运算程序(不定期更新)
  • 买一台 iPhone X,还是创建一家未来的独角兽?
  • 盘点那些不知名却常用的 Git 操作
  • 前端每日实战 2018 年 7 月份项目汇总(共 29 个项目)
  • 使用 Xcode 的 Target 区分开发和生产环境
  • 双管齐下,VMware的容器新战略
  • ​iOS实时查看App运行日志
  • ​LeetCode解法汇总2583. 二叉树中的第 K 大层和
  • (12)Hive调优——count distinct去重优化
  • (html5)在移动端input输入搜索项后 输入法下面为什么不想百度那样出现前往? 而我的出现的是换行...
  • (分布式缓存)Redis分片集群
  • (附源码)springboot“微印象”在线打印预约系统 毕业设计 061642
  • (十六)串口UART
  • (四)Tiki-taka算法(TTA)求解无人机三维路径规划研究(MATLAB)
  • (淘宝无限适配)手机端rem布局详解(转载非原创)
  • (一)RocketMQ初步认识
  • (幽默漫画)有个程序员老公,是怎样的体验?
  • ./include/caffe/util/cudnn.hpp: In function ‘const char* cudnnGetErrorString(cudnnStatus_t)’: ./incl
  • .NET CF命令行调试器MDbg入门(一)
  • .net core webapi 部署iis_一键部署VS插件:让.NET开发者更幸福
  • .Net8 Blazor 尝鲜
  • .project文件
  • .set 数据导入matlab,设置变量导入选项 - MATLAB setvaropts - MathWorks 中国
  • .w文件怎么转成html文件,使用pandoc进行Word与Markdown文件转化
  • /bin/rm: 参数列表过长"的解决办法
  • /etc/sudoer文件配置简析
  • @RequestMapping用法详解
  • @select 怎么写存储过程_你知道select语句和update语句分别是怎么执行的吗?