一:前言
redis中有幾種常用的基礎對象,如String、hash、list、set、zset等,下面我們就來介紹下他們的底層實現(xiàn)數(shù)據(jù)結構與常見應用場景和特點。
二:redisobject
源碼位置位于server.h文件中605行開始
typedef?struct?redisObject?{ ????unsigned?type:4; ????unsigned?encoding:4; ????unsigned?lru:LRU_BITS; ????int?refcount; ????void?*ptr; }?robj;
2.1 type
redis中實際的對象類型,分為5種0-4聲明。位于文件server.h中466行
#define?OBJ_STRING?0????/*?String?object.?*/ #define?OBJ_LIST?1??????/*?List?object.?*/ #define?OBJ_SET?2???????/*?Set?object.?*/ #define?OBJ_ZSET?3??????/*?Sorted?set?object.?*/ #define?OBJ_HASH?4??????/*?Hash?object.?*/
2.2 encoding
redis五種對象string、list、hash、set、zset會用到的八種編碼格式,每一種編碼都對應一個數(shù)據(jù)結構
#define?OBJ_ENCODING_RAW?0???? #define?OBJ_ENCODING_INT?1???? #define?OBJ_ENCODING_HT?2?????? #define?OBJ_ENCODING_ZIPLIST?5? #define?OBJ_ENCODING_INTSET?6?? #define?OBJ_ENCODING_SKIPLIST?7 #define?OBJ_ENCODING_EMBSTR?8? #define?OBJ_ENCODING_QUICKLIST?9
2.3 refcount
redis中內(nèi)存的回收采用了比較簡單的引用計數(shù)法進行,每個對象引用就refcount + 1,當這個引用計數(shù)減少為0時內(nèi)存就會被回收
三:string
3.1 常用場景
分布式鎖:分布式鎖的實現(xiàn)基礎就是采用string的命令setnx用戶信息:很多時候用戶信息都會序列化后存到redis中緩存,但是這里可以考慮下hash。如果僅僅使用用戶數(shù)據(jù)部分信息,畢竟序列化與反序列化也是一筆開銷
3.2 編碼格式
int:當字符串中全是數(shù)字時會采用int編碼,這是真正的二進制數(shù)據(jù)存儲embstr:內(nèi)存地址連續(xù),內(nèi)存一次申請。字符串長度小于44raw:底層采用sds實現(xiàn),相對于embstr差別在于sds的創(chuàng)建與redisobject的創(chuàng)建分兩次實現(xiàn)
3.3 常用命令
#?存儲 set?key?value #?互斥存儲 #?已存在的key再次存入數(shù)據(jù)不會更改緩存 setnx?key?value #?過期存儲,單位秒 #?設定key過期時間,到期自動刪除 setex?key?seconds?value #?過期存儲,單位毫秒 psetex?key?milliseconds?value #?批量存儲 mset?key?value?[key?value?...] #?取值 get?key #?批量取值 mget?key?[key?...] #?追加 append?key?value #?長度 strlen?key #?自增,只能是int編碼的字符串 incr?key #?自定義步長自增 incrby?key?increment #?自減,只能是int編碼的字符串 #?這個可以減到負數(shù),秒殺扣減庫存啥的想想能不能用這個命令 decr?key #?自定義步長自減 decrby?key?increment
四:list
4.1 常用場景
消息隊列:一般不怎么用,畢竟各種MQ、kafka都已經(jīng)很成熟了。而且redis實現(xiàn)消息隊列并不保證數(shù)據(jù)的安全排行榜計算:這種僅僅適用于定時計算更新,不能用于實時更新排行。比如美團每天計算區(qū)域入駐商家排行點贊列表:比如微信中的點贊(不知道咋做的,猜一下)
4.2 編碼格式
quicklist:快速列表,之前版本有使用linkedlist和ziplist。目前使用的quicklist為兩者結合體,詳情可以查看Redis(一) — 淺談Redis中的數(shù)據(jù)結構
4.3 相關參數(shù)配置
配置參數(shù)位置位于redis.con文件中1083行和1099行
list-max-ziplist-size:配置單個ziplist大小list-compress-depth:配置LZF壓縮算法開始節(jié)點
4.4 常用命令
#?創(chuàng)建list并壓入節(jié)點 #?壓入節(jié)點位于鏈表頭 lpush?key?value #?壓入節(jié)點位于鏈表尾 rpush?key?value #?彈出list頭節(jié)點 lpop?key #?彈出list尾節(jié)點 rpop?key #?刪除節(jié)點 #?count?>?0?從左開始搜索刪除count數(shù)量的value #?count??0?從左開始搜索 lindex?key?index #?范圍查詢 #?stop?=?-1?表示所有 lrange?key?start?stop #?阻塞彈出 #?隊列中沒有節(jié)點時會一直等待 #?多個key時表示挨著順序依次檢查,知道找到非空列表為止 #?timeout可以設置等待時間,0表示一直等待 blpop?key?[key...]?timeout brpop?key?[key...]?timeout
五:Hash
5.1 常用場景
商品對象、用戶對象。這個場景需要驗證性對待,如果商品對象、用戶對象信息每次都需要全量的話不妨存string,但是僅僅部分使用就可以考慮使用hash結構SKU等信息,這個場景下hash就比較合適了。一個hash結構中存儲某個商品所有sku
5.2 編碼格式
ziplist:使用ziplist存儲hash結構時一個數(shù)據(jù)會使用相鄰兩個ziplistEntry存儲field和valuehashtable:當數(shù)據(jù)存儲超過參數(shù)限制后就會將其底層結構由ziplist轉換為dict進行存儲
5.3 相關參數(shù)配置
hash-max-ziplist-entries:默認512,即ziplist節(jié)點為1024。當節(jié)點數(shù)量超過該值限制后底層數(shù)據(jù)結構轉為dicthash-max-ziplist-value:默認64,當hash中插入任意一個長度超過該限制的value后底層數(shù)據(jù)結構轉換為dict
(學習視頻分享:redis視頻教程)
5.4 常用命令
#?存儲 hset?key?field?value? #?不允許更改存儲 #?若field值存在則本次存儲不會覆蓋原有value值 hsetnx?key?field?value #?批量存儲 hmset?key?field?value?[field?value?...] #?查詢 hget?key?field #?批量查詢 hmget?key?field?[field?...] #?全量查詢 hgetall?key? #?全量查詢field值 hkeys?key #?全量查詢value值 hvals?key #?刪除field hdel?key?field?[field?...] #?計算鍵值對數(shù)量 hlen?key #?field存在判斷 hexists?key?field #?增量式迭代 #?cursor表示迭代開始的游標 #?count?表示迭代返回數(shù)據(jù)數(shù)量 #?pattern?表示正則匹配結果限制 hscan?key?cursor?[Count?count]?[Match?pattern]
六:Set
6.1 常用場景
推薦:通過sinter命令計算交集,比如美團給你推薦附近外賣時就可以根據(jù)你的外賣記錄與附近商家計算交集推送安全提示:微信群成員保存在一個set中,用戶好友也保存在set中。當用戶加入群聊時可以提醒非好友用戶注意安全
6.2 編碼格式
intset:整數(shù)集合,用于存儲set集合中所有value都是整數(shù)的數(shù)據(jù)hashtable:field用于存儲set集合值
6.3 相關參數(shù)配置
set-max-inset-entries:默認512,表示當元素數(shù)量超過限定以后轉換為hashtable編碼
6.4 常用命令
#?存儲 sadd?member?[member?...] #?彈出元素并返回 spop?key?count #?查詢所有元素 smembers?key?[count] #?計算元素數(shù)量 scard?key? #?刪除指定元素 srem?key?member?[member?...] #?判斷元素存在 sismember?key?member #?計算給定集合與后續(xù)集合差集 #?返回計算結果 sdiff?key?[key?...] #?計算給定集合與后續(xù)集合差集 #?存儲結果到destination并返回 sdiffstore?destination?key?[key?...] #?計算給定集合與后續(xù)集合交集 #?返回計算結果 sinter?key?[key?...] #?計算給定集合與后續(xù)集合差集 #?存儲結果到destination并返回 sinterstore?destination?key?[key?...] #?計算給定集合與后續(xù)集合差集 #?返回計算結果 sunion?key?[key?...] #?計算給定集合與后續(xù)集合差集 #?存儲結果到destination并返回 sunionstore?destination?key?[key?...]
七:Zset
7.1 常用場景
排行榜:美團要做一個銷量排行榜,就可以使用店家的訂單做score,這個查詢出來的結果就是有序的權重隊列:score作為優(yōu)先級,這樣取出來的數(shù)據(jù)權重都是最大優(yōu)先執(zhí)行的延時任務:score作為任務啟動執(zhí)行時間,取值時判斷該值執(zhí)行即可
7.2 編碼格式
ziplist:與hash有異曲同工之妙,都是使用相鄰兩個節(jié)點存儲score和memberskiplist:跳躍表結構,可以查看Redis(一) — 淺談Redis中的數(shù)據(jù)結構
7.3 相關參數(shù)配置
zset-max-ziplist-entries:默認值128,指定ziplist存儲元素最多128個。超過轉換為skiplistzset-max-ziplist-value:默認值64,存儲數(shù)據(jù)值最大64字節(jié),超過轉換為skiplist
7.4 常用命令
#?存儲 #?xx?表示當zset中存在本次插入的member時才存儲 #?nx?表示當zset中不存在本次插入的member時才存儲 zadd?key?[nx|xx]?score?member?[score?member?...] #?查詢排序指定[start,stop]范圍內(nèi)元素 #?withscores?查詢結果順帶返回元素分數(shù) zrange?key?start?stop?[withscores] #?查詢指定元素分數(shù) zscore?key?member #?元素數(shù)量統(tǒng)計 zcard?key #?返回score位于[min,max]區(qū)間的元素數(shù)量 zcount?key?min?max? #?對指定元素分數(shù)增加incrment值 zincrby?key?incrment?member #?返回指定分數(shù)區(qū)間范圍內(nèi)元素 #?withscores?返回時攜帶分數(shù)一起返回 #?limit?offset?count表示跳過offset數(shù)量結果再返回count數(shù)量結果 zrangebyscore?key?min?max?[withscores]?[limit?offset?count] #?倒序返回指定分數(shù)區(qū)間范圍內(nèi)元素 #?withscores?返回時攜帶分數(shù)一起返回 #?limit?offset?count表示跳過offset數(shù)量結果再返回count數(shù)量結果 zrevrangebyscore?key?max?min?[withrescores]?[limit?offset?count] #?刪除指定分數(shù)范圍[min,max]內(nèi)元素 zremrangebyscore?key?min?max #?移除指定元素 zrem?key?member
相關推薦:redis視頻教程