Redis的对象及命令

上一章讲解了Redis中的数据结构,这一章对Redis中的对象做简要介绍。本篇文章是对Redis对象做一个全局性的概览,每个对象的代码实现部分以后会一一解析。

Redis对象

Redis中有五大对象,分别是:字符串对象,列表对象,哈希对象,集合对象,有序集合对象。每一个对象都需要存储键值对,而key必须是字符串对象,value可能是五种类型对象之一。所以了解对象底层的存储编码方式有助于加深对Redis底层的了解,同时也是Redis设计思想中的重中之重,属于了解Redis的第一步。
Redis中的每个对象都是redisObject结构体表示的。

// 对象类型
#define REDIS_STRING 0
#define REDIS_LIST 1
#define REDIS_SET 2
#define REDIS_ZSET 3
#define REDIS_HASH 4

// 对象编码
#define REDIS_ENCODING_RAW 0     
#define REDIS_ENCODING_INT 1     
#define REDIS_ENCODING_HT 2      
#define REDIS_ENCODING_ZIPMAP 3  //后面的版本已经摒弃,这里不再考虑
#define REDIS_ENCODING_LINKEDLIST 4 
#define REDIS_ENCODING_ZIPLIST 5 
#define REDIS_ENCODING_INTSET 6  
#define REDIS_ENCODING_SKIPLIST 7  
#define REDIS_ENCODING_EMBSTR 8  

//redis对象结构体
typedef struct redisObject {
    // 类型
    unsigned type:4;
    // 编码
    unsigned encoding:4;
    // 对象最后一次被访问的时间
    unsigned lru:REDIS_LRU_BITS; /* lru time (relative to server.lruclock) */
    // 引用计数
    int refcount;
    // 指向实际值的指针
    void *ptr;
} robj;

字符串对象

字符串对象底层实现可能编码有三种,分别是raw SDS、整数、和embstr编码的SDS。当字符串对象保存的是一个整数值,则可以直接用整型编码来表示,即ptr指向一个long;当字符串对象保存的是一个字符串且字符串值的长度大于39字节,则用raw编码方式保存这个字符串的值,即ptr指向一个SDS类型;当字符串对象保存的是一个字符串且字符串值的长度小于39字节,则用embstr编码方式保存字符串。
int编码和raw编码都很简单,这里主要详细说一下embstr编码。embstr编码主要适合于短字符串的编码实现,通过调用一次内存分配函数分配一个连续的内存空间,用来存放redisobject和sdshdr对象。相比于raw编码方式,其有三个优点:

  1. 内存分配时候从raw编码的两次(分别申请redisobject和sdshdr)变成一次。
  2. 内存释放时候从raw编码的两次(分别释放redisobject和sdshdr)变成一次。
  3. embstr编码中字符串对象是在连续的内存中,有利于缓存。
    还有一点需要注意,字符串对象的三种编码方式之间可以转换。关系如下图。int编码当时当用append命令加上字符串的时候就变成raw编码方式了,embstr编码方式也是只读方式,当尝试对其做任何修改,也会将其转换成raw编码方式。
    在这里插入图片描述
    字符串对象常用的命令如下:
命令 作用
SET 插入字符串对象的值
GET 根据键返回字符串值
APPEND 根据键将字符串插入原值后面
INCRBY 将整数值加法(只有整型编码才可以执行)
DECRBY 将整数值减法(只有整形编码才可以执行)
STRLEN 返回字符串的长度
SETRANGE 将索引上的值设定为给定的字符(只有raw编码可以执行)
GETRANGE 返回字符串索引上的值(只有raw编码可以执行)

列表对象

列表对象的底层编码是linkedlist和ziplist。当列表对象保存的元素数小于512且字符串元素小于64字节的时候用ziplist编码,不满足的时候用linkedlist编码。两种编码可以转换。下图是两种编码类型的图示。
LINKEDLIST编码
ZIPLIST编码
列表常用的命令如下:

命令 作用
LPUSH 列表中头部插入值
RPUSH 列表尾部插入值
LPOP 列表头部弹出值
RPOP 列表尾部弹出值
LLEN 返回列表的长度
LINDEX 返回列表索引的值
LINSERT 在列表指定索引的位置中插入值
LSET 在列表指定索引位置更新节点的值
LREM 在列表中删除给定值的节点
LTRIM 在列表上删除指定索引之外的节点

哈希对象

哈希对象的底层编码有两种ziplist和hashtable。当哈希对象保存的键值对数小于512且键和值字符串长度小于64字节的时候用ziplist编码,不满足的时候用hashtable编码。两种编码可以转换。
在这里插入图片描述
在这里插入图片描述

命令 作用
HSET 将新节点添加到字典中
HGET 根据给定键返回相对应的值
HEXITS 根据给定键判断是否字典中存在
HDEL 根据给定键删除字典中的键值对
HLEN 字典中键值对的数量
HGETALL 返回字典中所有的键值对

集合对象

集合对象的编码方式也有两种:intset和hashtable。当集合中所有对象都是整数并且元素数量不超过512个就为intset编码,否则用hashtable编码。
intsetj集合编码
字典编码

命令 作用
SADD 添加新元素
SCARD 返回集合中的元素数量
SISMEMBER 集合中查找是否存在元素
SMEMBERS 返回整个集合元素
SRANDMEMBER 集合中随机返回一个元素
SPOP 集合中随机删除一个元素
SREM 集合中删除所有的元素

有序集合对象

有序集合对象的底层编码是ziplist或skiplist。当有序集合中元素数量小于128且所有元素长度小于64字节时候用ziplist编码,否则用skiplist编码。当使用ziplist编码时,压缩列表中对象按照分值从小到大排列,每个对象先存放对象内容,再存放对象分值。当使用skiplist编码时,其实是同时使用了字典和跳表。字典中存储了对象的元素和分值匹配关系,跳表根据分值从小到大有序存储。
这样设计的主要原因是同时利用跳表和字典的优势,比如ZSCORE命令可以返回指定元素的分值,如果只有跳表则查询的复杂度为O(logn),但是加上字典后查找的复杂度变成O(1)。但是如ZRANGE这类根据范围进行查找的命令就可以有效利用,
在这里插入图片描述
在这里插入图片描述

命令 作用
ZADD 插入新元素
ZCARD 返回有序集合中的元素数量
ZCOUNT 有序集合给定分值范围内的元素数量
ZRANGE 从表头到表尾遍历,返回索引范围内的元素数量
ZREVRANGE 从表尾到表头遍历,返回索引范围内的元素数量
ZSCORE 有序集合中返回给定成员的分值
ZREM 有序集合中删除所有包含给定成员的元素

常用作用于所有对象的命令

命令 作用
TYPE 查看键值对中值对象的类型
OBJECT ENCODING 查看键值对中值对象的编码类型
KEY + 模式 查找数据库中满足模式的KEY

参考

  1. 《Redis设计与实现》
  2. Redis命令
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章