一.概述 在前面章節中,主要瞭解了 Redis用到的主要數據結構,包括:簡單動態字元串、鏈表(雙端鏈表)、字典、跳躍表、 整數集合、壓縮列表(後面再瞭解)。Redis沒有直接使用這些數據結構來實現鍵值對資料庫,而是基於這些數據結構創建一個對象系統,這個系統對象包括:字元串對象、列表對象、哈希對象(散 ...
一.概述
在前面章節中,主要瞭解了 Redis用到的主要數據結構,包括:簡單動態字元串、鏈表(雙端鏈表)、字典、跳躍表、 整數集合、壓縮列表(後面再瞭解)。Redis沒有直接使用這些數據結構來實現鍵值對資料庫,而是基於這些數據結構創建一個對象系統,這個系統對象包括:字元串對象、列表對象、哈希對象(散列)、集合對象、有序集合對象這五種類型,每種類型對象都用到了至少一種前面所介紹的數據結構。
通過這五種不同類型的對象,可以針對不同的使用場景, 在Redis 內部會為對象設置不同的數據結構實現,從而優化對象在不同場景下的使用效率。下麵先直觀看下關係圖(五種對象與type與encoding編碼與ptr底層數據結構),然後再來詳細介紹它們之間的關係。
二. 對象類型與編碼(五種類型的對象)
Redis中的每個對象都由一個RedisObject結構表示,該結構中和保存數據有關的三個屬性分別是type屬性、encoding屬性、ptr屬性。
typeof struct redisObject{ //類型 unsigned type:4; //編碼 unsigned encoding:4; //指向底層實現數據結構的指針 void *ptr; //... }robj;
2.1 type類型
對象的type屬性記錄了對象的類型,對於鍵來說它總是一個字元串對象,而值可以是五種類型,這五種類型如下表格:
type取值的類型常量 |
五種對象的名稱 |
Type命令輸出 |
Redis_string |
字元串對象 |
string |
Redis_list |
列表對象 |
list |
Redis_hash |
哈希對象 |
hash |
Redis_set |
集合對象 |
set |
Redis_zset |
有序集合對象 |
zset |
例1: 下麵使用type命令,該命令返回結果為資料庫鍵對應的值對象類型,而不是鍵對象的類型。
-- 值為字元串對象 127.0.0.1:6379> set msg "hello world" OK 127.0.0.1:6379> type msg string -- 值為列表對象 127.0.0.1:6379> rpush number 1 3 5 (integer) 3 127.0.0.1:6379> type number list -- 值為哈希對象 127.0.0.1:6379> hmset profile name tom age 25 career programmer OK 127.0.0.1:6379> type profile hash -- 值為集合對象 127.0.0.1:6379> sadd fruit apple banana cherry (integer) 3 127.0.0.1:6379> type fruit set -- 值為有序集合對象 127.0.0.1:6379> zadd price 8.50 apple 3.30 banana (integer) 2 127.0.0.1:6379> type price zset
2.2 編碼和底層實現(encoding, ptr)
對象的ptr指針指向對象的底層實現數據結構,而這些數據結構由對象的encoding屬性決定,encoding記錄了對象所使用的編碼。使用object encoding命令查看不同編碼的輸出。表格如下:
(1) 底層數據結構與encoding編碼的對應關係:
底層數據結構 |
encoding編碼常量取值 |
object encoding 輸出 |
整數 |
Redis_encoding_int |
int |
Embstr編碼的SDS字元串(長字元值) |
Redis_encoding_embstr |
embstr |
SDS字元串 |
Redis_encoding_raw |
raw |
字典 |
Redis_encoding_ht |
hashtable |
鏈表 |
Redis_encoding_linkedlist |
linkedlist |
壓縮列表 |
Redis_encoding_ziplist |
ziplist |
整數集合 |
Redis_encoding_intset |
intset |
跳躍表和字典 |
Redis_encoding_skiplist |
skiplist |
(2) 五種對象類型與encoding編碼的對應關係
五種對象類型常量 |
對應encoding編碼常量 |
對象說明 |
Redis_string |
Redis_encoding_int |
使用整數值實現的字元串對象 |
Redis_string |
Redis_encoding_embstr |
使用embstr編碼的簡單動態字元串實現的字元串對象 |
Redis_string |
Redis_encoding_raw |
使用簡單動態字元串實現的字元串對象 |
Redis_list |
Redis_encoding_ziplist |
使用壓縮列表實現的列表對象 |
Redis_list |
Redis_encoding_linkedlist |
使用雙端鏈表實現的列表對象 |
Redis_hash |
Redis_encoding_ziplist |
使用壓縮列表實現的哈希對象 |
Redis_hash |
Redis_encoding_ht |
使用字典實現的哈希對象 |
Redis_set |
Redis_encoding_intset |
使用整數集合實現的集合對象 |
Redis_set |
Redis_encoding_ht |
使用字典實現的集合對象 |
Redis_zset |
Redis_encoding_ziplist |
使用壓縮列表實現的有序集合對象 |
Redis_zset |
Redis_encoding_skiplist |
使用跳躍表和字典實現的有序集合對象 |
例2: 下麵使用object encoding命令,該命令查看一個資料庫鍵的值對象的編碼:
127.0.0.1:6379> set msg "hello wrold" OK 127.0.0.1:6379> object encoding msg "embstr" 127.0.0.1:6379> set story "long long long long long long long long long ..." OK 127.0.0.1:6379> object encoding story "raw" 127.0.0.1:6379> sadd num 1 3 4 (integer) 0 127.0.0.1:6379> object encoding num "intset" 127.0.0.1:6379> sadd num 1 3 4 "one" (integer) 1 127.0.0.1:6379> object encoding num "hashtable" 127.0.0.1:6379> zadd fruit-price 5.0 banana 6.5 cherry 8.0 apple (integer) 0 127.0.0.1:6379> object encoding fruit-price "ziplist" 127.0.0.1:6379> rpush integers "1" "2" "3" "4" "5" "6" "7" "8" "9" "10" (integer) 20 127.0.0.1:6379> object encoding integers "quicklist"
總結:通過encoding屬性來設定對象所使用的編碼,而不是為特定類型的對象關聯一種固定的編碼,極大提升了redis的靈活性和效率。例如:上面演示的zadd fruit-price 添加列表元素,redis使用壓縮列表作為列表對象的底層實現,因為壓縮列表比鏈表更節約記憶體,並且在元素數量較少時,在記憶體中以連續塊方式保存的壓縮列表比鏈表可以更快被載入到緩存中。但隨著列表對象元素越來越多時,這種壓縮優勢就會消失,此時對象就會將底層實現從壓縮列表轉向鏈表。 其它類型的對象也會通過使用多種不同的編碼來進行類似的優化。
使用對象key通過Type命令查看value值的對象類型,通過object encoding命令查看value值的底層數據結構。