一、Redis 对象

1.1 Redis 对象简介

Redis 使用对象来表示数据库中键和值,当我们在数据库中存储一个键值对时,至少会创建两个对象,一个对象用于存储键值对的键,另一个对象用于存储键值对的值。

Redis 中的每一个对象都由一个 redisObject 结构表示,该结构有三个属性和保存的数据有关,分别是 type 属性、encoding 属性和 ptr 属性。

typedef struct redisObject {// 类型unsigned type:4;// 编码unsigned encoding:4;// 指向底层数据实现数据结构的指针void *ptr;
} robj;

1.2 对象类型

redisObject 对象的 type 属性记录了对象的类型,Redis 中的键总是一个字符串对象,值对象可以是字符串对象、哈希对象、集合对象等。

我们可以通过使用 TYPE key 命令查看数据库键对应的值对象的类型。

1.3 编码与底层实现

encoding 属性记录了对象所使用的编码,也就是这个对象底层实现的数据结构。关于编码可以使用 OBJECT ENCODING key 命令查看。

二、五种数据类型对象与编码

2.1 字符串对象

要注意的是 longdouble 浮点数在 Redis 中也是作为字符串值来保存的。

(1)字符串对象编码

字符串对象的编码有 intraw 或者 embstr 三种。

  • int:保存的是整数值
  • raw:保存的是字符串,并且字符串的长度小于等于 39 个字节
  • embstr:保存的是字符串,并且字符串的长度大于等于 39 个字节

embstr 编码的好处:

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

(2)编码转换

int 编码的字符串对象和 embstr 编码的字符串对象在一定条件下, 会被转换为 raw 编码的字符串对象,如下。

  • int 编码的字符串对象通过某些操作,保存的不再是单纯的整数值
  • embstr 编码的字符串对象执行任何修改命令时, 程序会先将对象的编码从 embstr 转换成 raw , 然后再执行修改命令

下面是一个例子,供参考:

127.0.0.1:6379> SET num-str 100
OK
127.0.0.1:6379> OBJECT ENCODING num-str
"int"
# 追加元素内容
127.0.0.1:6379> APPEND num-str "hei~"
(integer) 7
127.0.0.1:6379> OBJECT ENCODING  num-str
"raw"

2.2 列表对象

(1)列表对象编码

Redis 3.2 以前的版本中列表的的编码类型有 ziplistlinkedlist

ziplist 编码的列表对象使用压缩列表作为底层实现, 每个压缩列表节点(entry)保存了一个列表元素。

linkedlist 编码的列表对象使用双端链表作为底层实现, 每个双端链表节点(node)都保存了一个字符串对象, 而每个字符串对象都保存了一个列表元素。

在 Redis 3.2 以上的版本中列表对象的编码替换为 quicklist,它的底层实现是一个双向链表,而且是一个ziplist 数据结构的双向链表。关于这种数据结构的详细信息就不介绍了,以后有机会接触到 Redis 的源码后再单独拿出来总结。

例子如下(基于 3.2.× 版本):

127.0.0.1:6379> RPUSH students "zs" "ls" "ww"
(integer) 3
127.0.0.1:6379> OBJECT ENCODING students
"quicklist"

2.3 哈希对象

(1)哈希对象编码

哈希对象的编码是 ziplisthashtable

ziplist 编码的哈希对象使用压缩列表作为底层实现,每当有新的键值对要加入到哈希对象时,程序会先将保存了键的压缩列表节点推入到压缩列表表尾,然后再将保存了值的压缩列表节点推入到压缩列表表尾。因此保存了同一键值对的两个节点总是紧挨在一起, 保存键的节点在前, 保存值的节点在后。

hashtable 编码的哈希对象使用字典作为底层实现,哈希对象中的每个键值对都使用一个字典键值对来保存。

(2)编码转换

当哈希对象可以同时满足以下两个条件时, 哈希对象使用 ziplist 编码。

  • 键和值的字符串长度都小于 64 字节
  • 键值对数量小于 512 个

不能满足上面两个条件的哈希对象使用 hashtable 编码。

PS:
上面两个条件的上限值是可以在配置文件中修改的,默认配置如下:

hash-max-ziplist-entries 512
hash-max-ziplist-value 64

下面是一个例子:

127.0.0.1:6379> OBJECT ENCODING student
"ziplist"
# 存储一个大于 64 字节的值
127.0.0.1:6379> HSET student desc "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz ... "
(integer) 1
127.0.0.1:6379> OBJECT ENCODING student
"hashtable"

2.4 集合对象

(1)集合对象编码

集合对象的编码可以是 intset 或者 hashtable

inset 编码的底层实现是整数集合,集合对象包含的所有元素都被保存在整数集合里。

hashtable 编码使用字典作为底层实现,字典的每个键都是一个字符串对象,每个字符串对象包含了一个集合元素,而字典的值则全部被设置为 NULL ,可以类比于 Java 中的 HashSet 的实现。

(2)编码转换

当集合对象可以满足以下两个条件中的任一个时, 对象使用 intset 编码:

  • 集合对象中的元素都是整数值
  • 集合对象中元素的数量不超过 512 个

PS:
上面第二个条件的上限值是可以在配置文件中修改的,默认配置如下:

set-max-intset-entries 512

下面是一个例子:

127.0.0.1:6379> SADD keys "1" "2"
(integer) 2
127.0.0.1:6379> OBJECT ENCODING keys
"intset"
# 添加非整数元素
127.0.0.1:6379> SADD keys "hei~"
(integer) 1
127.0.0.1:6379> OBJECT ENCODING keys
"hashtable"

2.5有序集合对象

(1)有序集合对象编码

有序集合的编码可以是 ziplist 或者 skiplist

压缩列表内的集合元素按分值从小到大进行排序,分值较小的元素被放置在靠近表头的方向, 分值较大的元素则被放置在靠近表尾的方向。

skiplist 编码的有序集合对象使用 zset 结构作为底层实现, 一个 zset 结构同时包含一个字典和一个跳跃表。

为什么 zset 结构要同时使用字典与跳跃表来实现有序集合?

  • 如果只使用字典实现有序集合,查找成员的复杂度为O(1),但是当执行范围操作时,就需要对字典中保存的元素进行排序。
  • 如果只使用跳跃表实现有序集合,执行范围操作时的所有优点都会被保留,但是执行查找元素时,时间复杂度上升为O(logN)
  • 因此 zset 集成了字典与跳跃表两者的优点来实现有序集合对象。

(2)有序集合对象编码转换

当有序集合对象满足以下条件时,对象会使用 ziplist 编码:

  • 有序集合保存的元素数量小雨 128 个
  • 有序集合保存的所有元素成员长度小于 64 字节

PS:
上面第二个条件的上限值是可以在配置文件中修改的,默认配置如下:

zset-max-ziplist-entries 128
zset-max-ziplist-value 64

三、Other

3.1内存回收

C 语言自身不具备内存回收功能,因此 Redis 使用引用计数(refering counting)实现内存回收机制。每个对象的引用计数信息由 redisO此处输入代码bject 结构中的 refcount 属性记录。

在对象创建时,引用计数值会被初始化为 1,当对象被程序引用时,引用计数值会加 1,当对象不在被一个对象使用时,它的引用计数值会减 1,当对象的引用计数值为 0 时,对象所占的内存就会被回收。

3.2对象共享

Redis 会在初始化服务器时,创建 [0 ,10000) 之间的字符串对象,当服务器需要用到 0 到 9999 之间的字符串对象时,服务器会共享这些对象,而不是创建新的对象,通过这种方式可以节约内存。

参考书籍

《Redis 设计与实现》黄健宏著

《Redis 设计与实现》读书笔记-Redis 对象相关推荐

  1. Redis 设计与实现 读书笔记(菜鸟版)

    Redis 设计与实现 读书笔记(简略版) 写在前面 第一章(内部数据结构) SDS List Dictionary Rehash Rehash 与 COW 渐进式Rehash 字典收缩 Skipli ...

  2. Redis 设计与实现读书笔记-第三章

    引言 第三部分,属于多机数据库的实现,相较而言是很受关注的一部分,也是面试的高频考点,总体包含三个部分:主从复制.Sentinel 以及 集群.这三部分(加上之前介绍到的根据 RDB 和 AOF 实现 ...

  3. Redis 设计与实现——读书笔记

    项目中能用到的: redis 数据结构(网络数据存储数据结构,使用何种数据结构能有利于网络数据的查询,如存储拓扑结构,前端需要频繁查询拓扑结构的数据(交换机自身信息switches+交换机链接link ...

  4. Redis设计与实现-读书笔记

    一:数据结构和对象 SDS:动态字符串 包含len free buf SDS可以用作AOF缓冲区.客户端状态的输入缓冲区 len:记录buf数组中已使用字节的数量,等于SDS字符串长度 free:记录 ...

  5. Redis设计与实现 -读书笔记

    2. 简单动态字符串(SDS) 定义: struct sdshdr {int len; // buf中已使用字节数量(不包括末尾'\0')int free; // 未使用字节char buf[]; / ...

  6. 读《redis设计与实现》笔记--redis数据结构

    redis五大数据结构:string,hash,list,set,zset(有序集合) redis底层数据结构:简单动态字符串(SDS),链表,字典,跳表,整数集合,压缩列表 底层数据结构详解: 1. ...

  7. 《Redis设计与实现》笔记|SDS动态字符串|链表字典跳跃表整数集合压缩列表结构|redis中的对象|数据库原理|RDB持久化|AOF持久化|事件与多路利用模型|发布订阅原理|事务原理|慢查询日志

    <Redis设计与实现>笔记 前记: 参考配套网站:http://redisbook.com 带注释的源码地址:https://github.com/huangz1990/redis-3. ...

  8. redis设计与实现学习笔记1

    文章目录 1.对象 1.1 类型 1.2 内存回收 1.3 对象共享 1.4 对象空转时长 2.单机数据库 2.1 RDB 2.2 AOF 2.3 事件 2.4客户端 2.5服务器 3.常用命令 参考 ...

  9. 【《Redis深度历险》读书笔记(1)】基础:万丈高楼平地起 ——Redis 5种基础数据结构

    [时间]2021.11.16 [题目][<Redis深度历险>读书笔记(1)]基础:万丈高楼平地起 --Redis 基础数据结构 本栏目是<Redis深度历险:核心原理和应用实践&g ...

  10. 领域驱动设计DDD之读书笔记

    查看文章   领域驱动设计DDD之读书笔记  转载原地址:http://hi.baidu.com/lijiangzj 2007-08-17 16:53 一.当前Java软件开发中几种认识误区 Hibe ...

最新文章

  1. Leetcode 860. 柠檬水找零 解题思路及C++实现
  2. Java 基础之 Random类和Math.random()方法
  3. SpringBoot集成Redission实现分布式缓存
  4. tf.Session().as_default的作用
  5. bzoj 3747: [POI2015]Kinoman
  6. 老李谈JVM内存模型
  7. java syncr_JAVA基础—Synchronized线程同步机制
  8. java udp简单聊天程序_Java基于UDP协议实现简单的聊天室程序
  9. leetcode - 617. 合并二叉树
  10. oracle存储怎么调试tord,接口_数据交换应用指导(20页)-原创力文档
  11. dll注入的一种方式
  12. linux make项目管理器,Linux中makefile项目管理
  13. oracle安装无响应,求教 pl/sql连接本机数据库是未响应问题
  14. [转载]ASPNET MVC表格呈现利器:MvcContrib.UI.Grid
  15. 作为程序员,常用的工具软件之搜索引擎
  16. 利用Dreamweaver模板批量制作网页
  17. 0/0型极限等于多少_两个重要极限的一点理解(下)
  18. 网易蜗牛读书产品分析报告
  19. 艾司博讯:拼多多商品讲解视频如何制作
  20. java 气泡图_java报表开发制作气泡图

热门文章

  1. 解决spring boot项目启动后访问接口出现日志乱码
  2. Java代码实现执行HTTP请求
  3. java向指定文件写入内容
  4. 阿里云安全组——添加安全组规则(开放端口)
  5. html媒体查询怎么把颜色换成图片,为网页中图片src添加媒体查询功能。
  6. 【项目实战】vue-springboot-pytorch前后端结合pytorch深度学习 html打开本地摄像头 监控人脸和记录时间
  7. Python基础day05 作业解析【10道 函数作业题】
  8. Android studio 克隆分支
  9. IOS学习之蓝牙4.0
  10. 基于B/S模式的推送