小結
-
字符串內部編碼:int embstr raw,用途:緩存。
-
哈希內部編碼:壓縮ziplist hashtable
-
列表內部編碼:壓縮ziplist linkedlist,用途:消息隊列。
-
集合內部編碼:intset hashtable,用途:標簽,計算用戶共同感興趣的標簽。sinter user:1:tags user:2:tags
-
有序集合內部編碼:壓縮ziplist 跳躍表zskiplist,用途:熱評的排行榜。zrevrangebyrank user:ranking:2016_0315 0 9
-
Bitmaps用途:通過極小空間進行位運算實現對狀態的判斷,例如可以做一個答題瓜分獎勵的活動,每個用戶答題答對可以設置
setbit user 1 1,然后后用bitcount統計有多少個1,看用戶答對了多少題。
跳躍表
跳躍表支持平均OlogN、最壞ON復雜度的節點查找。
在大部分情況下,跳躍表的效率可以和平衡樹相媲美,Redis使用跳躍表作為有序集合的底層實現之一。
實現
由redis.h/zskiplistNode和redis.h/zskiplist兩個結構定義,zskiplistNode表示跳躍表節點,而zskiplist保存跳躍表
節點的相關信息,比如節點數量,以及表頭節點和表尾結點的指針。
zskiplist結構:頭結點header,尾結點tail,層數level,長度length。
zskiplistNode結構:層level(層中有前進指針和跨度),后退指針backwrad,分值score,成員對象obj。
SDS簡單動態字符串
struct sdshdr {
// 記錄buf數組中已使用字節的數量
// 等於SDS所保存字符串的長度
int len;
// 記錄buf數組中未使用字節的數量
int free;
// 字節數組,用於保存字符串
char buf[];
}
-
free表示這個SDS沒有分配 未使用空間。
-
len表示SDS保存了無字節長的字符串。
-
buf是一個char數組。
SDS與C字符串區別
-
O(1)復雜度獲取字符串長度。
-
防止緩沖區溢出。
-
減少修改字符串時帶來的內存重分配次數。
字符串
命令
set key value [ex seconds] [px milliseconds] [nx|xx]
內部編碼
字符串類型的內部編碼有3種:
-
int:8個字節長整型。
-
embstr:小於等於39個字節的字符串。
-
raw:大於39個字節的字符串。
Redis會根據當前值的類型和長度決定使用哪種內部編碼實現。
整數:
set key 8653
ok
object encoding key
"int"
短字符:
set key "hello"
ok
object encoding key
"embstr"
長字符:
set key "40 bytes"
ok
object encoding key
"raw"
使用場景
-
緩存
-
計數
-
Session集中管理
-
限速
哈希
命令
hset key field value
hset uset:1 name tom
hget key field
hget uset:1 name
"tom"
內部編碼
- ziplist(壓縮列表):哈希類型元素個數小於hash-max-ziplist-entries默認512個、同時所有值都小於hash-max-
ziplist-value配置時,Redis會使用ziplist實現,節省內存方面比hashtable優秀。
- hashtable:哈希類型無法滿足ziplist條件時,會用這個,hashtable的讀寫時間復雜度都是O(1)。
hset hashkey f3 "bigger than 64 bytes"
object encoding hashkey
"hashtable"
hmset hashkey f1 v1 f2 v2 f3 v3 ...... f513 v513
object encoding hashkey
"hashtable"
列表
從右邊插入元素:rpush key value
lrange listkey 0 -1
從左邊插入元素:lpush key value
linsert key before | after pivot value
查找:lrange key start end
刪除:lpop key
內部編碼
-
ziplist:元素個數小於list-max-ziplist-entries,同時每個值都小於list-max-ziplist-value,Redis選用壓縮列表減少內存。
-
linkedlist:無法滿足ziplist就會用鏈表來實現。
使用場景
-
消息隊列
-
文章列表
集合
用來保存多個的字符串元素,不允許重復元素,無序。
sadd key a b c 添加key
3
srem key a b 刪除key
2
scard key 計算key
1
smembers key 獲取所有元素
sinter key 求交集
suinon key 求並集
sdiff key 求差集
內部編碼
-
intset(整數集合)
-
hashtable
使用場景
標簽(tag)
給用戶添加標簽
sadd user:1:tags tag1 tag2 tag3
sadd uset:1:tags tag1 tag2 tag3
給標簽添加用戶
sadd tag1:users user:1 user:3
sadd tag2:users user:1 user:2
計算用戶共同感興趣的標簽
sinter user:1:tag2 user:2:tag
有序集合
不能重復,可以排序的set,給每個元素設置了一個score作為排序的依據。
列表、集合和有序集合三者異同點
命令
zadd key score member 添加成員
zadd user:ranking 251 tom
有序集合提供排序字段,產生代價,zadd復雜度為Ologn,sadd為O1。
zcard user:ranking 計算成員數
zscore key member 返回某個成員分數
zrank key member 計算成員的排名
zrem key member 刪除成員
zrange ...
集合間的操作
(1)交集
(2)並集
內部編碼
-
壓縮列表
-
跳躍表
使用場景
添加用戶贊數:
zadd user:ranking:2016_03_15 mike 3
獲得贊后:
zincrby user:ranking:2016_03_15 mike 1
取消贊:
zrem
獲取贊數最多的十個用戶:
zrevrangebyrank user:ranking:2016_0315 0 9
展示用戶信息以及用戶分數:
此功能將用戶名作為鍵后綴,將用戶信息保存在哈希類型中,至於用戶的分數和排名可以使用zscore和zrank
hgetall user:info:tom
zscore user:ranking:2016_03_15 mike
zrank user:ranking:2016_03_15 mike
Bitmaps
Bitmap通常被用來在極小空間消耗下通過位的運算(AND/OR/XOR/NOT)實現對狀態的判斷,常見的使用場景例如:“答對12道題的同學有機會瓜分獎池”,這種如果使用bitmap來實現,就非常容易判斷出用戶是否全部答對。
答題系統設計如下:
- 每個用戶每輪答題,設置一個key,比如user1在第一輪答題的key是 round:1:user1。
- 每答對一道題,設置相關的bit為1,比如user1答對了第5題,那么就設置第5個bit為1就可以了,如:SETBIT round:1:user1 5 1 ;如果用戶1在第一輪答對了第9題,那么就把第9個bit設置為1,SETBIT round:1:user1 9 1;值得注意的是,Bitmaps默認bit都是0,答錯可以不設置。
- 計算用戶總共答對了幾道題,就可以使用 BITCOUNT 命令統計1的bit個數。
可見,Redis的bitmap接口可以用非常高的存儲效率和計算加速效果。
待更新:
HyperLogLog
GEO
Reference
《Redis設計與實現》
《Redis開發與運維》