《Redis 设计与实现》读书笔记-Redis 对象
一、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 字符串对象
要注意的是 long
、double
浮点数在 Redis 中也是作为字符串值来保存的。
(1)字符串对象编码
字符串对象的编码有 int
、 raw
或者 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 以前的版本中列表的的编码类型有 ziplist
或 linkedlist
。
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)哈希对象编码
哈希对象的编码是 ziplist
或 hashtable
。
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 对象相关推荐
- Redis 设计与实现 读书笔记(菜鸟版)
Redis 设计与实现 读书笔记(简略版) 写在前面 第一章(内部数据结构) SDS List Dictionary Rehash Rehash 与 COW 渐进式Rehash 字典收缩 Skipli ...
- Redis 设计与实现读书笔记-第三章
引言 第三部分,属于多机数据库的实现,相较而言是很受关注的一部分,也是面试的高频考点,总体包含三个部分:主从复制.Sentinel 以及 集群.这三部分(加上之前介绍到的根据 RDB 和 AOF 实现 ...
- Redis 设计与实现——读书笔记
项目中能用到的: redis 数据结构(网络数据存储数据结构,使用何种数据结构能有利于网络数据的查询,如存储拓扑结构,前端需要频繁查询拓扑结构的数据(交换机自身信息switches+交换机链接link ...
- Redis设计与实现-读书笔记
一:数据结构和对象 SDS:动态字符串 包含len free buf SDS可以用作AOF缓冲区.客户端状态的输入缓冲区 len:记录buf数组中已使用字节的数量,等于SDS字符串长度 free:记录 ...
- Redis设计与实现 -读书笔记
2. 简单动态字符串(SDS) 定义: struct sdshdr {int len; // buf中已使用字节数量(不包括末尾'\0')int free; // 未使用字节char buf[]; / ...
- 读《redis设计与实现》笔记--redis数据结构
redis五大数据结构:string,hash,list,set,zset(有序集合) redis底层数据结构:简单动态字符串(SDS),链表,字典,跳表,整数集合,压缩列表 底层数据结构详解: 1. ...
- 《Redis设计与实现》笔记|SDS动态字符串|链表字典跳跃表整数集合压缩列表结构|redis中的对象|数据库原理|RDB持久化|AOF持久化|事件与多路利用模型|发布订阅原理|事务原理|慢查询日志
<Redis设计与实现>笔记 前记: 参考配套网站:http://redisbook.com 带注释的源码地址:https://github.com/huangz1990/redis-3. ...
- 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.常用命令 参考 ...
- 【《Redis深度历险》读书笔记(1)】基础:万丈高楼平地起 ——Redis 5种基础数据结构
[时间]2021.11.16 [题目][<Redis深度历险>读书笔记(1)]基础:万丈高楼平地起 --Redis 基础数据结构 本栏目是<Redis深度历险:核心原理和应用实践&g ...
- 领域驱动设计DDD之读书笔记
查看文章 领域驱动设计DDD之读书笔记 转载原地址:http://hi.baidu.com/lijiangzj 2007-08-17 16:53 一.当前Java软件开发中几种认识误区 Hibe ...
最新文章
- Leetcode 860. 柠檬水找零 解题思路及C++实现
- Java 基础之 Random类和Math.random()方法
- SpringBoot集成Redission实现分布式缓存
- tf.Session().as_default的作用
- bzoj 3747: [POI2015]Kinoman
- 老李谈JVM内存模型
- java syncr_JAVA基础—Synchronized线程同步机制
- java udp简单聊天程序_Java基于UDP协议实现简单的聊天室程序
- leetcode - 617. 合并二叉树
- oracle存储怎么调试tord,接口_数据交换应用指导(20页)-原创力文档
- dll注入的一种方式
- linux make项目管理器,Linux中makefile项目管理
- oracle安装无响应,求教 pl/sql连接本机数据库是未响应问题
- [转载]ASPNET MVC表格呈现利器:MvcContrib.UI.Grid
- 作为程序员,常用的工具软件之搜索引擎
- 利用Dreamweaver模板批量制作网页
- 0/0型极限等于多少_两个重要极限的一点理解(下)
- 网易蜗牛读书产品分析报告
- 艾司博讯:拼多多商品讲解视频如何制作
- java 气泡图_java报表开发制作气泡图