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