《Redis设计与实现》重点笔记②——对象和其他基本概念

redis对象

基本概念

  • redis的对象就是在各种底层结构体的基础上, 根据具体应用场景做出不同实现时应遵循的接口

  • redis存储的键值对至少包含两个对象: 键对象(只能是字符串对象) 和 值对象

    • // 对象的结构
      typedef struct redisObject {
          unsigned type:4;  // 类型
          unsigned encoding:4; // 编码
          void *ptr; // 指向底层实现数据结构的指针
          // ...
      } robj;
      
    • type的值是枚举类型, 有以下六类

      • REDIS_STRING
      • REDIS_LIST
      • REDIS_HASH
      • REDIS_SET
      • REDIS_ZSET
    • encoding的值也是枚举类型, 有以下八类

      • 编码常量编码所对应的底层数据结构
        REDIS_ENCODING_INTlong 类型的整数
        REDIS_ENCODING_EMBSTRembstr 编码的简单动态字符串
        REDIS_ENCODING_RAW简单动态字符串
        REDIS_ENCODING_HT字典
        REDIS_ENCODING_LINKEDLIST双端链表
        REDIS_ENCODING_ZIPLIST压缩列表
        REDIS_ENCODING_INTSET整数集合
        REDIS_ENCODING_SKIPLIST跳跃表和字典
    • 所以type对应的不同encoding实现

      • 类型编码对象
        REDIS_STRINGREDIS_ENCODING_INT使用整数值实现的字符串对象。
        REDIS_STRINGREDIS_ENCODING_EMBSTR使用 embstr 编码的简单动态字符串实现的字符串对象。
        REDIS_STRINGREDIS_ENCODING_RAW使用简单动态字符串实现的字符串对象。
        REDIS_LISTREDIS_ENCODING_ZIPLIST使用压缩列表实现的列表对象。
        REDIS_LISTREDIS_ENCODING_LINKEDLIST使用双端链表实现的列表对象。
        REDIS_HASHREDIS_ENCODING_ZIPLIST使用压缩列表实现的哈希对象。
        REDIS_HASHREDIS_ENCODING_HT使用字典实现的哈希对象。
        REDIS_SETREDIS_ENCODING_INTSET使用整数集合实现的集合对象。
        REDIS_SETREDIS_ENCODING_HT使用字典实现的集合对象。
        REDIS_ZSETREDIS_ENCODING_ZIPLIST使用压缩列表实现的有序集合对象。
        REDIS_ZSETREDIS_ENCODING_SKIPLIST使用跳跃表和字典实现的有序集合对象。

字符串对象

  • 字符串对象负责实现对字符串和数字的存储
    • 类型分别为 embstr(字符串 < 39字节)(只读), raw(字符串 > 39字节), int(整数)
    • 浮点数在存储时会被转化为字符串类型, 在计算时再转化回来

具体实现

  • 当存储整数时, 例如: SET test 100, 使redisobj对象的指针ptr指向long类型整数
  • 当使用embstr时, 会给redisobj对象sds字符串开辟一整块空间(短字符串限定优化)
  • 当使用raw时, 会给redisobj对象sds字符串分别开辟空间, 并使ptr指向sds

升级

  1. 向整数追加字符串时, 类型会从int转化为raw
  2. 修改只读短字符串时, 类型会从embstr转化为raw

列表对象

  • 可以使用ziplist或者linkedlist实现
    • ziplist
      • 列表对象保存的所有字符串元素的长度都小于 64 字节;
      • 列表对象保存的元素数量小于 512 个;
    • linkedlist
      • 其余情况

哈希对象

  • 可以使用ziplist或hashtable实现
    • ziplist
      • 列表对象保存的所有字符串元素的长度都小于 64 字节;
      • 列表对象保存的元素数量小于 512 个;
      • 将键值对按先后顺序放入ziplist(list中的每两个entry构成一个键值对)
    • hashtable
      • 其他情况

集合对象

  • 可以使用intset或hashtable实现
    • intset
      • 集合对象保存的所有元素都是整数值;
      • 集合对象保存的元素数量不超过 512 个;
    • hashtable
      • 其他情况

有序集合对象

  • 可以使用ziplist或skiplist(实质是zset)

    • ziplist

      • 有序集合保存的元素数量小于 128 个;
      • 有序集合保存的所有元素成员的长度都小于 64 字节;
      • 将成员-分值对按分值大小放入ziplist(list中的每两个entry构成一个成员-分值对)
    • zset

      • typedef struct zset {
            zskiplist *zsl; // 主要使用在批量操作连续元素时
            dict *dict; // 主要使用在单独查询时
        } zset;
        
      • zsl按分值大小顺序保存所有的有序集合元素

      • dict散列有序集合元素, 并以键值对的形式保存元素-分值对

      • 同时使用zskiplist和dict实现zset是为了提高性能

      • 指针形式保证了不会有重复的空间开辟, 而且可以根据不同的场景查不同的表

其它基本概念

类型检查与命令多态

  • redis的命令分为两种
    • 可以对任何对象使用
    • 只能对特定类型的对象使用
    • 在执行命令前检查redisobj的type属性进行校验
  • redis的同一抽象命令在面对具体底层实现时会被相应转化(多态)

内存回收

typedef struct redisObject {
    // ...
    int refcount; // 引用计数
    // ...
    unsigned lru:22; // last recent used 最近一次被使用的时间
    // ...
} robj;
  • 正常回收机制
    • 在创建一个新对象时, 引用计数的值会被初始化为 1
    • 当对象被一个新程序使用时, 它的引用计数值会被增一;
    • 当对象不再被一个程序使用时, 它的引用计数值会被减一;
    • 当对象的引用计数值变为 0 时, 对象所占用的内存会被释放。
  • 开启maxmemory
    • (当前时间 - lru) > maxmemory时, 会回收被使用的内存

对象共享

  • redis在开启数据库时会创建0 ~ 9999的整数类型字符串对象
  • 当需要存储这些值时, 直接将指针指向预创建的对象, 同时引用计数++
  • 不仅仅是单纯存储整数时共享, 在存储其他复杂类型时也会共享这些整数
  • 为什么不共享其他类型?
    • 共享时需要检查是否完全相等, 其他类型的检查成本太高了
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值