redis的使用场景和基本数据类型
一:redis使用的場景
redis是一個(gè)高性能的NoSQL數(shù)據(jù)庫,特點(diǎn)是高性能,持久存儲,適應(yīng)高并發(fā)的應(yīng)用場景。
下面看看它的使用場景
1、取最新N個(gè)數(shù)據(jù)的操作
比如取網(wǎng)站的最新文章,通過下面方式,我們可以將最新的5000條評論的ID放在Redis的List集合中,并將超出的部分從數(shù)據(jù)庫中獲取
1)使用PUSH latest.comments <ID> 命令,向list集合中插入數(shù)
2)插入完成后再用LTRIM latest.comments 0 5000 命令使其永遠(yuǎn)保持最近5000個(gè)ID
3)然后我們就可以根據(jù)最新需要取最新的5000個(gè)評論
比如你還有不同的維度,比如某個(gè)分類的最新N條,那么你還可以在新建一個(gè)按此分類的List,也只存ID
2、排行榜應(yīng)用,去TOP N 操作
這個(gè)需求與上面不同之處在于,前面的操作時(shí)間為權(quán)重, 這個(gè)是以某條件為權(quán)重, 游戲里面比如按等級排序,這時(shí)候就可以用sorted set了,將要排序的值設(shè)置成 sorted set的score,將具體的數(shù)據(jù)設(shè)置成相應(yīng)的值,
每次只需要執(zhí)行一條ZADD命令
3、需要精確設(shè)置過期時(shí)間的應(yīng)用
比如你可以把上面說到的sorted set的score值設(shè)置成過期時(shí)間的時(shí)間戳,那么就可以簡單地通過過期時(shí)間排序,定時(shí)清除過期數(shù)據(jù)了,不僅是清除Redis中的過期數(shù)據(jù),你完全可以把 Redis里這個(gè)過期時(shí)間當(dāng)成是對數(shù)據(jù)庫中數(shù)據(jù)的索引,用Redis來找出哪些數(shù)據(jù)需要過期刪除,然后再精準(zhǔn)地從數(shù)據(jù)庫中刪除相應(yīng)的記錄。
4、 計(jì)數(shù)器應(yīng)用
Redis的命令都是原子性的,你可以輕松地利用INCR,DECR命令來構(gòu)建計(jì)數(shù)器系統(tǒng)。
5、 Uniq操作,獲取某段時(shí)間所有數(shù)據(jù)排重值
這個(gè)使用Redis的set數(shù)據(jù)結(jié)構(gòu)最合適了,只需要不斷地將數(shù)據(jù)往set中扔就行了,set意為集合,所以會自動排重。
6、 實(shí)時(shí)系統(tǒng),反垃圾系統(tǒng)
通過上面說到的set功能,你可以知道一個(gè)終端用戶是否進(jìn)行了某個(gè)操作,可以找到其操作的集合并進(jìn)行分析統(tǒng)計(jì)對比等。沒有做不到,只有想不到。
7、 Pub/Sub構(gòu)建實(shí)時(shí)消息系統(tǒng)
Redis的Pub/Sub系統(tǒng)可以構(gòu)建實(shí)時(shí)的消息系統(tǒng),比如很多用Pub/Sub構(gòu)建的實(shí)時(shí)聊天系統(tǒng)的例子。
8、 構(gòu)建隊(duì)列系統(tǒng)
使用list可以構(gòu)建隊(duì)列系統(tǒng),使用sorted set甚至可以構(gòu)建有優(yōu)先級的隊(duì)列系統(tǒng)。
二:數(shù)據(jù)類型
redis最為常用的數(shù)據(jù)類型有5種:string,hash,list,set和SortedSet。
redisObj
redis內(nèi)部使用一個(gè)redisObject的對象來表示所有的key和value。redisObj主要信息如下圖所示:
type:代表一個(gè)value對象具體是何種數(shù)據(jù)類型,
encoding:是不同數(shù)據(jù)類型在redis內(nèi)部的存儲方式,比如:type=string代表value存儲的是一個(gè)普通字符串,那么對應(yīng)的encoding可以是raw或者是int,如果是int則代表實(shí)際redis內(nèi)部是按數(shù)值類型存儲和表示這個(gè)字符串的,當(dāng)然前提是這個(gè)字符串本身可以用數(shù)值表示。
vm:這里需要特殊說明下vm字段,只有打開了redis的虛擬內(nèi)存功能,此字段才會真真的分配內(nèi)存,該功能默認(rèn)是關(guān)閉的。vm的功能我們在稍后討論,通過上圖可以發(fā)現(xiàn)redis使用redisObject來表示所有的key-value數(shù)據(jù)是比較浪費(fèi)內(nèi)存的,當(dāng)然這些內(nèi)存管理的成本的付出也是為了給redis不同數(shù)據(jù)類型提供一個(gè)統(tǒng)一的管理接口,實(shí)際作者也提供了許多方法幫助我們盡量節(jié)省內(nèi)存使用。這個(gè)也在稍后探討。下面我們先來逐一分析下這五種數(shù)據(jù)類型的使用和內(nèi)部實(shí)現(xiàn)方式
String
常用命令:set,get,decr,incr, mset, mget等。
應(yīng)用場景:String是最常用的一種數(shù)據(jù)類型,普通的key-value存儲都可以歸為此類。
實(shí)現(xiàn)方式:String在redis內(nèi)部存儲默認(rèn)就是一個(gè)字符串,被redisObject所引用,當(dāng)遇到incr,decr等操作時(shí),會轉(zhuǎn)成數(shù)值型進(jìn)行計(jì)算,此時(shí)redisObject的encoding字段為int。
Hash
常用命令: hmset, hmget, hdel, hlen等。
應(yīng)用場景
?我們簡單舉個(gè)實(shí)例來描述下Hash的應(yīng)用場景,比如我們要存儲一個(gè)用戶信息對象數(shù)據(jù),包含以下信息:
?用戶ID為查找的key,存儲的value用戶對象包含姓名,年齡,生日等信息,如果用普通的key/value結(jié)構(gòu)來存儲,主要有以下2種存儲方式:
第一種方式將用戶ID作為查找key,把其他信息封裝成一個(gè)對象以序列化的方式存儲,這種方式的缺點(diǎn)是,增加了序列化/反序列化的開銷,并且在需要修改其中一項(xiàng)信息時(shí),需要把整個(gè)對象取回,并且修改操作需要對并發(fā)進(jìn)行保護(hù),引入CAS等復(fù)雜問題。
?
第二種方法是這個(gè)用戶信息對象有多少成員就存成多少個(gè)key-value對兒,用用戶ID+對應(yīng)屬性的名稱作為唯一標(biāo)識來取得對應(yīng)屬性的值,雖然省去了序列化開銷和并發(fā)問題,但是用戶ID為重復(fù)存儲,如果存在大量這樣的數(shù)據(jù),內(nèi)存浪費(fèi)還是非常可觀的。
?那么Redis提供的Hash很好的解決了這個(gè)問題,Redis的Hash實(shí)際是內(nèi)部存儲的Value為一個(gè)HashMap,并提供了直接存取這個(gè)Map成員的接口,如下圖:
?
也就是說,Key仍然是用戶ID, value是一個(gè)Map,這個(gè)Map的key是成員的屬性名,value是屬性值,這樣對數(shù)據(jù)的修改和存取都可以直接通過其內(nèi)部Map的Key(Redis里稱內(nèi)部Map的key為field), 也就是通過 key(用戶ID) + field(屬性標(biāo)簽) 就可以操作對應(yīng)屬性數(shù)據(jù)了,既不需要重復(fù)存儲數(shù)據(jù),也不會帶來序列化和并發(fā)修改控制的問題。很好的解決了問題。
?這里同時(shí)需要注意,Redis提供了接口(hgetall)可以直接取到全部的屬性數(shù)據(jù),但是如果內(nèi)部Map的成員很多,那么涉及到遍歷整個(gè)內(nèi)部Map的操作,由于Redis單線程模型的緣故,這個(gè)遍歷操作可能會比較耗時(shí),而另其它客戶端的請求完全不響應(yīng),這點(diǎn)需要格外注意。
?實(shí)現(xiàn)方式:上面已經(jīng)說到Redis Hash對應(yīng)Value內(nèi)部實(shí)際就是一個(gè)HashMap,實(shí)際這里會有2種不同實(shí)現(xiàn),這個(gè)Hash的成員比較少時(shí)Redis為了節(jié)省內(nèi)存會采用類似一維數(shù)組的方式來緊湊存儲,而不會采用真正的HashMap結(jié)構(gòu),對應(yīng)的value redisObject的encoding為zipmap,當(dāng)成員數(shù)量增大時(shí)會自動轉(zhuǎn)成真正的HashMap,此時(shí)encoding為ht
List
常用命令: lpush,rpush,lpop,rpop,lrange等。
應(yīng)用場景: Redis list的應(yīng)用場景非常多,也是Redis最重要的數(shù)據(jù)結(jié)構(gòu)之一,比如twitter的關(guān)注列表,粉絲列表等都可以用Redis的list結(jié)構(gòu)來實(shí)現(xiàn),比較好理解,這里不再重復(fù)。
實(shí)現(xiàn)方式:Redis list的實(shí)現(xiàn)為一個(gè)雙向鏈表,即可以支持反向查找和遍歷,更方便操作,不過帶來了部分額外的內(nèi)存開銷,Redis內(nèi)部的很多實(shí)現(xiàn),包括發(fā)送緩沖隊(duì)列等也都是用的這個(gè)數(shù)據(jù)結(jié)構(gòu)。
Set
常用命令:sadd,spop,smembers,sunion 等。
應(yīng)用場景:Redis set對外提供的功能與list類似是一個(gè)列表的功能,特殊之處在于set是可以自動排重的,當(dāng)你需要存儲一個(gè)列表數(shù)據(jù),又不希望出現(xiàn)重復(fù)數(shù)據(jù)時(shí),set是一個(gè)很好的選擇,并且set提供了判斷某個(gè)成員是否在一個(gè)set集合內(nèi)的重要接口,這個(gè)也是list所不能提供的。
實(shí)現(xiàn)方式:set 的內(nèi)部實(shí)現(xiàn)是一個(gè) value永遠(yuǎn)為null的HashMap(ps:這點(diǎn)和java中set的實(shí)現(xiàn)基本相同),實(shí)際就是通過計(jì)算hash的方式來快速排重的,這也是set能提供判斷一個(gè)成員是否在集合內(nèi)的原因。
Sorted Set
常用命令:zadd,zrange,zrem,zcard等.
使用場景:Redis sorted set的使用場景與set類似,區(qū)別是set不是自動有序的,而sorted set可以通過用戶額外提供一個(gè)優(yōu)先級(score)的參數(shù)來為成員排序,并且是插入有序的,即自動排序。當(dāng)你需要一個(gè)有序的并且不重復(fù)的集合列表,那么可以選擇sorted set數(shù)據(jù)結(jié)構(gòu),比如twitter 的public timeline可以以發(fā)表時(shí)間作為score來存儲,這樣獲取時(shí)就是自動按時(shí)間排好序的。
實(shí)現(xiàn)方式:Redis sorted set的內(nèi)部使用HashMap和跳躍表(SkipList)來保證數(shù)據(jù)的存儲和有序,HashMap里放的是成員到score的映射,而跳躍表里存放的是所有的成員,排序依據(jù)是HashMap里存的score,使用跳躍表的結(jié)構(gòu)可以獲得比較高的查找效率,并且在實(shí)現(xiàn)上比較簡單。
參考:https://blog.csdn.net/u013256816/article/details/51133134
轉(zhuǎn)載于:https://www.cnblogs.com/jiujuan/p/9061088.html
總結(jié)
以上是生活随笔為你收集整理的redis的使用场景和基本数据类型的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: keepalived+LVS实现高可用的
- 下一篇: 【转】构建C1000K的服务器(1) –