美文网首页
Redis 设计与实现 2:Redis 对象 redisObje

Redis 设计与实现 2:Redis 对象 redisObje

作者: 小新是也 | 来源:发表于2020-12-24 22:04 被阅读0次

    本文的分析都是基于 Redis 6.0 版本源码
    redis 6.0 源码:https://github.com/redis/redis/tree/6.0

    在 Redis 中,有五大数据类型,都统一封装成了一个数据类型:redisObject。定义如下:

    typedef struct redisObject {
        unsigned type:4; // 类型
        unsigned encoding:4; // 编码
        unsigned lru:LRU_BITS; // 最近被访问的时间
        int refcount; // 引用次数
        void *ptr; // 指向具体底层数据的指针
    } robj;
    

    redisObject 结构示意图如下:

    redisObject 结构示意图

    一、类型

    typedef struct redisObject {
        unsigned type:4; // 类型
    } robj;
    

    类型就是常见的五大对象类型。

    新版本的常量命名是 OBJ 前缀,老版本是 REDIS 前缀(如 REDIS_STRING )

    类型常量 对象名称
    OBJ_STRING 字符串对象
    OBJ_LIST 列表对象
    OBJ_SET 集合对象
    OBJ_ZSET 有序集合对象
    OBJ_HASH 哈希对象

    TYPE 命令可以输出指定 key 的值的对象类型。

    redis > set str_key str_value
    OK
    redis > TYPE
    string
    
    对象名称 TYPE 命令输出
    字符串对象 string
    列表对象 list
    集合对象 set
    有序集合对象 zset
    哈希对象 hash

    二、编码

    typedef struct redisObject {
        unsigned encoding:4; // 编码
    } robj;
    

    五大类型中,每种类型可能存在着不同的编码。编码的存在主要是为了在节约内存和提高性能之间做平衡。

    • 当数据量小的时候,会采用紧凑(性能偏低)的数据结构
    • 当数据量达到一定阈值的时候,会从紧凑型的结构转成高效率的数据结构

    由于篇幅有限,编码又比较复杂。所以编码就放到后面的文章写吧,嘿嘿嘿

    三、最近被访问时间

    typedef struct redisObject {
        unsigned lru:LRU_BITS; // 最近被访问的时间
    } robj;
    

    当 Redis 的使用内存达到指定的阈值的时候,Redis 会对内存进行回收,回收有很多策略,其中就有 LRU 策略。

    LRU 简单点来说就是,最近有修改或者访问的,就排在前面。等到要淘汰的时候,就淘汰排在后面的元素。淘汰的元素相对来说就是很久没有进行访问/修改了。

    Redis 记录这个最近访问时间,就是为了 LRU 策略用的。
    命令 OBJECT IDLETIME 可以查看 key 距离上次访问的时间。

    由于篇幅有限,具体的淘汰策略就放到后面的文章吧,嘿嘿嘿。

    四、引用次数

    typedef struct redisObject {
        int refcount; // 引用次数
    } robj;
    

    refcount 的作用主要是对象的引用计数和内存回收。refcount会随着对象的使用状态而变化:

    • 在创建一个新对象时,引用计数的值会被初始化为1;
    • 当对象被一个新程序使用时,它的引用计数值会被增一;
    • 当对象不再被一个程序使用时,它的引用计数值会被减一;
    • 当对象的引用计数值变为0时,对象所占用的内存会被释放。

    命令 OBJECT REFCOUNT 可以查看指定 key 的引用计数值。

    共享对象

    那么对象什么时候才会被新程序使用呢?
    为了节省内存,Redis 会在初始化的时候,创建好 0 ~ 9999 的对象,后续 0 ~ 9999 的整数值都会用这些共享对象,不会重新创建对象。

    server.h

    #define OBJ_SHARED_INTEGERS 10000
    

    object.c

    // ...
    if (value >= 0 && value < OBJ_SHARED_INTEGERS...)
    // ...
    

    五、指针

    typedef struct redisObject {
        void *ptr; // 指向具体底层数据的指针
    } robj;
    

    指针通常来说就是指向底层数据的。
    不过有个例外,当值是 string 类型,并且编码是 int 时,保存的就是这个整数值,而不是指针。

    关于底层数据的结构,后面会说。

    相关文章

      网友评论

          本文标题:Redis 设计与实现 2:Redis 对象 redisObje

          本文链接:https://www.haomeiwen.com/subject/ewoenktx.html