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命令
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章