深入Redis原理与应用——Redis 中的对象类型

对象简介

(1)redis 并未直接使用基本数据结构而是基于基本的数据结构封装了对象系统,包括了字符串对象、列表对象、哈希对象、集合对象和有序集合对象。
(2)使用对象的好处是可以才不同的场景对对象设置不同的数据结构实现从而优化效率。
(3)redis 对象机制使用了基于引用计数的回收机制,当程序不再使用某个对象时该对象就会自动释放,同时也通过引用计数实现了共享机制,节约内存。
(4)redis 带有访问时间记录信息,当开启 maxmemory 时空转时长较大的将会优先被删除。

对象的结构

(1)对象使用 redisObject 存储,type 表示当前对象的类型,encoding 表示对象的编码即底层使用的数据结构,ptr 是一个指向具体内容的指针。
(2)type 有五种分别对应 redis 的五个数据类型。
(3)对象的 ptr 指向对象的底层实现数据结构,而数据结构由对象的 encoding 属性决定。
在这里插入图片描述
注:3.2 版本之后的列表均使用 quicklist(快速列表)实现。快速列表是以压缩列表为节点的链表,将链表按段切分,每一段使用压缩列表进行内存的连续存储,多个压缩列表通过 prev 和 next 指针组成的双向链表。它结合了压缩列表和链表的优势,进一步压缩内存的使用量和提高效率。

对象种类

字符串对象

(1)字符串对象的编码可以是 int、raw 或者 embstr。
(2)如果一个字符串对象保存了整数值且整数值可用 long 类型表示,则会使用 int 编码存储。
(3)如果存储了字符串值并且字符串的长度大于 32 字节,那么字符串会使用简单动态字符串实现,即编码为 raw。
(4)如果存储了字符串值并且其长度小于等于 32 字节,那么会使用 embstr 存储。embstr和 raw 编码都使用 redisObject 和 sdshdr 来表示字符串,而 raw 需要调用两次内存分配函数分别申请两个结构的内存空间,但 embstr 只通过一次调用内存分配函数完成分配一块连续的内存空间,空间中依次包括 redisObject 和 sdshdr。
(5)embstr 优势:内存分配和内存释放都只需要调用一次对应的分配和释放函数,且其保存在一块连续内存里结构紧凑更能很好利用缓存的优势。
(6)embstr 是只读的,我们执行任何修改的程序都会将其先转化为 raw 编码格式。
(7)浮点数内部是 embstr 或 raw 实现的,embstr 不会使 embstr 变为 raw。

列表对象(redis3.2 之前的旧版本)

(1)列表对象使用 ziplist 或 linkedlist 实现。
(2)列表对象所有元素的长度都小于 64 字节且列表元素数量小于 512 时采用 ziplist,否则采用 linkedlist 实现。

哈希对象

(1)哈希对象使用 ziplist 或 hashtable 实现。
(2)保存了同一个键值对的两个节点总是紧挨在一起的,保存键的节点在前保存值的节点在后。
(3)使用 ziplist 结构紧凑避免创建多个对象并彼此关联(使用 hashtable 的情况)。
(4)哈希对象保存的所有键值对的键和值的字符串长度都小于 64 字节且键值对的数量小于 512 时使用 ziplist,否则采用 hashtable 实现。

集合对象

(1)集合对象编码采用 intset 或 hashtable 实现。
(2)当集合对象满足集合元素全都是整数值且元素个数不超过 512 个时可以使用 intset,否则使用 hashtable 实现。

有序集合对象

(1)有序集合对象编码可以是 ziplist 或者 skiplist。
(2)使用 ziplist 保存时每个集合元素使用两个紧挨的压缩列表节点表示,第一个保存元素成员第二个保存元素的分值。压缩列表元素按从小到大排序。
(3)使用 skiplist 作为 zset 结构的话,zset 结构由两个属性,一是 zskiplist 类型的 zsl指针,二是 dict 类型的 dict 指针。跳跃表节点的 object 属性保存了元素的成员,跳跃表节点的 score 属性保存了元素的分值,通过这个跳跃表可以很方便对有序集合进行范围操作。而字典则创建一个从成员到分值的映射,字典的键保存了元素的成员,字典的值保存了分值。zset 的 zsl 和 dict 会通过指针共享元素的成员(字符串对象)和分值(double 类型的浮点数)。
(4)有序集合同时采用跳跃表和字典的原因:字典可以以 O(1)的时间复杂度查找成员的分值又可以进行高效的范围查找。
(5)有序集合保存的元素数量小于 128 且所有成员的长度都小于 64 字节时会使用 ziplist,否则采用 skiplist 编码。

类型检查与命令多态

(1)redis 命令分为可以在任何键上执行的命令(del、expire、type、object 等)和只能在特定数据类型上执行的命令。
(2)在使用特定类型的命令之前 redis 服务器会先检查类型是否符合,不符合则拒绝执行并返回错误。
(3)redisObject 的 type 属性中包含了该对应类型的相应处理函数,实现多态。

引用计数

(1)内存回收:c 语言不支持自动内存回收所以 redis 在对象系统中构建了一个引用计数技术实现内存回收。通过给每一个redisObject添加一个refcount属性表示被引用的个数。
(2)对象共享:一个对象可以被多个位置引用,节省内存空间,只需要操作 refcount。

对象的空转时长

(1)除了 type、encoding、ptr 和 refcount 属性外 redisObject 还使用 lru 属性记录对象最后一次被访问的时间。
(2)某个对象的空转时长即当前时间减去对象的 lru 属性值。
(3)当打开了 maxmemory 选项后并且服务器用于回收内存的算法为 volatile-lru 或者allkeys-lru,那么当服务器占用内存超过 maxmemory 上限后空转时间较长的键优先被释放。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值