一、robj 介绍
Redis 的其他基本数据结构,比如 sds、intset、ziplist、linkedlist、dict、zskiplist,其实 Redis 并没有直接使用这些数据结构来实现键值对的数据库,而是在这些数据结构之上又包装了一层 RedisObject(对象)。
使用 robj的好处:
1、通过不同类型的对象,Redis 可以在执行命令之前,根据对象的类型来判断一个对象是否可以执行给定的命令。
2、可以针对不同的使用场景,为对象设置不同的实现,从而优化内存或查询速度。
二、robj 结构
robj 字段描述:
type:数据类型
encoding:编码方式
lru:根据 lru 或者 lfu 等不同算法,来存储相关值
refcount:引用计数
ptr:指向实际值的指针
1、type
type 记录了对象所保存值的类型,目前redis中包含以下几种类型:
2、encoding
encoding 表示为编码方式,如果说每个类型只有一种方式,那么其实 type 和 encoding 两个字段只需要保留一个即可,但 Redis 为了在各种情况下尽可能减少内存,对每种类型的数据在不同情况下有不同的编码格式,所以这里需要用额外的字段标识出来。目前有以下几种编码:
这里有个 OBJ_ENCODING_EMBSTR,这里着重介绍下。
从上面代码就可以看出,它是 robj 和 sds 的一个结合,将 sds 直接放在 robj 里,这里限制最多可以存放 44 字节长度的字符串(3.2 版本之前是 39 字节长度)。因为 robj 占 16 字节,sdshdr8 占 3 字节,’\0’一个字节,限制字符串最长为 44 就可以保证在 64 个字节里存放下所有内容 (16+3+1+44==64)。
3、lru
众所周知,Redis 提供了过期数据自动淘汰的策略,如何知道数据是否已经过期?按照什么样的策略淘汰数据?这俩问题的答案都和 lru 这个字段有关。
Redis 给了 lru 这个字段 24 位,但千万别以为字段名叫 lru 就认为它只是 LRU 淘汰策略中才会使用的,其实 LFU 用的也是这个字段。
我估计是 Redis 作者先写了 LRU 策略,所以直接就叫 lru 了,后来再加上 LFU 策略的时候直接复用这个字段了。
lru 字段在不同淘汰策略时有不同的含义:
1、当使用 LRU 策略时,它就是一个 24 位的秒级 unix 时间戳,代表这个数据在第多少秒被更新过。
2、但使用 LFU 策略时,24 位会被分为两部分,16 位的分钟级时间戳和 8 位的特殊计数器。
4、refcount
引用计数,表示这个 robj 目前被多少个地方应用,refcount 的出现为对象复用提供了基础。了解过垃圾回收的同学都知道有种回收策略就是采用计数器的方式,当 refcount 为 0 时,说明该对象已经没用了,就可以被回收掉了,Redis 的作者也实现了这种引用回收的策略。
5、ptr
这个就很简单了,前面几个字段是为 robj 提供 meta 信息,那该字段就是数据具体所在地址。