Redis教程

Redis读书笔记(二)对象

本文主要是介绍Redis读书笔记(二)对象,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!

对象介绍

  • 字符串对象
      • 编码实现
      • 编码转化
      • 常用命令
  • 列表对象
      • 编码实现
      • 编码转换
      • 常用命令
  • 哈希对象
      • 编码实现
      • 编码转换
      • 常用命令
  • 有序集合对象
      • 编码实现
      • 编码转换
      • 常用命令

前面介绍的都是基本数据结构,Redis并没有直接使用这些基本数据结构,而是基于这些数据结构创建了一个对象系统,这个系统包含 字符串对象列表对象哈希对象集合对象有序集合对象这五种类型。
Redis通过引用计数实现了内存回收,同时还实现了对象共享机制。
Redis中的键和值都是对象。 Redis中的每个对象都由一个redisObject结构表示,该结构中和 保存数据有关的3个属性分别是 type属性、 encoding属性和 ptr属性:

typedef struct redisObject {

    // 类型,':'表示占用的bit数
    unsigned type:4;

    // 编码
    unsigned encoding:4;

    // 对象最后一次被访问的时间
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */

    // 引用计数
    int refcount;

    // 指向实际值的指针
    void *ptr;

} robj;

字符串对象

编码实现

  • int:一个字符串对象保存的是整数,并且这个整数可以用long类型表示,那么就将这个整数保存在ptr中(将void*转换成long),并将字符串对象编码为int。
  • raw:保存的是一个字符串值,并且这个字符串值的长度大于39字节,那么将用一个SDS来保存这个字符串,并将对象编码设置为raw。
  • embstr:保存的是一个字符串值,但长度小于等于39字节,那么字符串对象将使用embstr编码方式。

raw和embstr的区别?
rmbstr编码是专门用于保存短字符串的一种优化编码方式,它只进行一次内存分配和回收,它的StringObject和SDS紧挨。而raw编码单独分配StringObject和SDS,需要两次内存分配和回收

编码转化

int和embstr的条件不满足时,会自动转化为raw编码。此外,对embstr执行任何修改命令时,程序会将对象编码转换成raw,因为embstr没有任何操作函数,它是只读的

常用命令

命令作用
SET设置值
GET获取值
APPEND将给定字符串追加到本字符串末尾
INCRBYFLOAT将字符串转化为long double然后加上给定的数字
INCRBY对整数值进行加法计算,只能用于int编码
DECRBY对整数值进行减法计算,只能用于int编码
STRLEN返回字符串的长度
SETRANGE将字符串特定索引上的值设置为给定的字符
GETRANGE返回字符串指定索引上的字符

列表对象

编码实现

  • 列表对象可以是ziplist或者linkedlist
  • Ziplist 是为了尽可能地节约内存而设计的特殊编码双端链表。它的所有元素在内存中紧挨在一起,却又不能通过下标访问
  • LinkedList是以链表的形式,每个节点是一个字符串对象字符串对象是Redis五种类型的对象中唯一一种会被其他四种对象嵌套的对象

编码转换

当列表对象可以同时满足以下两个条件时,列表对象使用ziplist编码:

  • 列表对象保存的所有字符串元素的长度都小于64字节;
  • 列表对象保存的元素数量小于512个;

不能同时满足这两个条件的,就需要使用linkelist编码。上面的两个值都是可以通过配置文件修改的。

常用命令

命令作用
LPUSH插入表头
RPUSH插入表尾
LPOP从表头返回并删除
RPOP从表尾返回并删除
LINDEX返回指定节点保存的元素
LLEN返回表的长度
LINSERT将值插入到指定位置
LREM删除包含了给定元素的节点
LTRIM删除表中所有不在指定索引范围内的节点
LSET将指定索引的值更新为指定的值

哈希对象

编码实现

  • 哈希对象可用的编码是ziplist或者hashtable。
  • ziplist方式的哈希对象使用ziplist作为底层数据结构,键和值节点紧挨在一起,插入到压缩列表末尾。
  • hashtable编码的哈希对象使用字典作为底层实现,哈希对象中的每个键值对都使用一个字典键值对来保存:字典的每个键都是一个字符串对象,对象中保存了键值对的键;字典的每个值都是一个字符串对象,对象中保存了键值对的值。

编码转换

当哈希对象可以同时满足以下两个条件时,哈希对象使用ziplist编码:

  • 哈希对象保存的所有键值对的键和值的字符串长度都小于64字节;
  • 哈希对象保存的键值对数量小于512个;

不能满足这两个条件的哈希对象需要使用hashtable编码。上面两个上限值可以通过配置文件修改。

命令作用
HSET插入新的键值对
HGET查找给定键,并返回它的值
HEXISTS查找给定元素是否存在
HDEL删除指定键所在的键值对
HLEN返回键值对的数目
HGETALL返回所有的键和值

集合对象
集合对象的编码可以是intset或者hashtable。
intset编码使用整数集合作为底层实现,整数集合类似于一个数组,详细见上面介绍。
hashtable编码使用字典作为底层实现。
当下面两个条件都被满足时,使用intset编码,否则,使用hashtable编码
集合对象保存的所有元素都是整数值
集合对象保存的元素数量不超过512
第二个条件的上限可以通过配置文件修改。当两个条件中任一个不满足时,就会自动执行编码转换操作

常用命令

命令作用
SADD添加新元素
SCARD返回元素数量
SISMEMBER判断给定的元素是否在集合中
SMEMBERS返回所有元素
SRANDMEMBER随机返回集合中的一个元素
SPOP从列表中随机删除一个值
SREM删除所有给定的元素

有序集合对象

编码实现

  • 有序集合的编码可以是ziplist或者skiplist。
  • ziplist底层使用压缩列表,每个集合元素使用两个紧挨在一起的压缩列表节点来保存,第一个节点保存元素的成员(member),第二个节点保存元素的分值(Score)。压缩列表内按照分值升序排列

skiplist编码的有序集合对象使用zset结构作为底层实现,一个zset结构同时包含一个字典和一个跳跃表

/*
 * 有序集合
 */
typedef struct zset {

    // 字典,键为成员,值为分值
    // 用于支持 O(1) 复杂度的按成员取分值操作
    dict *dict;

    // 跳跃表,按分值排序成员
    // 用于支持平均复杂度为 O(log N) 的按分值定位成员操作
    // 以及范围操作
    zskiplist *zsl;

} zset;

正如源码注释所说,之所以同时采用两种数据结构来实现,是为了互相弥补对方的不足。zskiplist是为了弥补哈希表不能进行范围查询的缺点,而哈希表将单个元素的查询操作从zskiplist的O(logN)优化到了哈希表的O(1)
虽然同时使用了两种结构,但是所有的元素节点都是共用的,即真正的节点只有一份,但是它被两种方式使用了。因此,同时使用两种数据结构,并没有浪费空间,且同时提高了范围查询和单值查询的效率。

有序集合的每个元素成员都是一个字符串对象,而每个元素的分支都是一个double类型的浮点数。

编码转换

当有序集合对象同时满足以下两个条件时,对象使用ziplist编码:

  • 有序集合保存的元素数量小于128个;
  • 有序集合保存的所有元素成员的长度都小于64字节。

不能满足任何一个,则使用skiplist编码。以上两个条件的上限值是可以在配置文件里修改的。当两个条件的任何一个不被满足时,程序会自动执行编码转换操作。

常用命令

命令作用
ZADD插入元素
ZCARD返回集合元素的数量
ZCOUNT统计分值在给定范围内的节点的数量
ZRANGE返回给定索引范围内的所有元素
ZREVRANGE倒序返回给定范围内的元素
ZRANK返回元素的集合中的排名
ZREVRANK返回元素在集合中的倒序排名
ZREM删除所有包含了给定成员的跳跃表节点
ZSCORE返回给定元素的分值
这篇关于Redis读书笔记(二)对象的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!