Redis做爲一個非關係型數據庫,除了在訪問速度上擁有顯著優點外,其自己支持的多種數據類型也很是有用,能覆蓋系統開發中的不少應用場景。下面列舉的場景有的是從網上其餘人的博客裏看到的,有的本身開發時嘗試過的一些解決方案後記錄下來的,但願能給之後的開發帶來啓發。面試
在說應用場景前先說一些是否以爲使用Redis的建議算法
RDB
和AOF
兩種持久化方式,可是廣泛仍是認爲 Redis 的持久化並非很靠譜。很是重要的數據不要依賴Redis來開發,或者最起碼不要只在Redis中持久化做爲Key-Value
形態的內存數據庫,Redis 最早會被想到的應用場景即是做爲數據緩存。而使用 Redis 緩存數據很是簡單,只須要經過string
類型將序列化後的對象存起來便可,不過也有一些須要注意的地方:數據庫
緩存內容與數據庫的一致性,這裏通常有兩種作法:緩存
Redis 中list
的數據結構實現是雙向鏈表,因此能夠很是便捷的應用於消息隊列(生產者 / 消費者模型)。消息的生產者只須要經過lpush
將消息放入 list,消費者即可以經過rpop
取出該消息,而且能夠保證消息的有序性。若是須要實現帶有優先級的消息隊列也能夠選擇sorted set
。而pub/sub
功能也能夠用做發佈者 / 訂閱者模型的消息。不管使用何種方式,因爲 Redis 擁有持久化功能,也不須要擔憂因爲服務器故障致使消息丟失的狀況。服務器
list
做爲雙向鏈表,不光能夠做爲隊列使用。若是將它用做棧即可以成爲一個公用的時間軸。當用戶發完微博後,都經過lpush
將它存放在一個 key 爲LATEST_WEIBO
的list
中,以後即可以經過lrange
取出當前最新的微博。數據結構
list
還能夠做爲循環鏈表使用 RPOPLPUSH source destination
分佈式
命令 RPOPLPUSH
在一個原子時間內,執行如下兩個動做:性能
source
中的最後一個元素(尾元素)彈出,並返回給客戶端。source
彈出的元素插入到列表 destination
,做爲 destination
列表的的頭元素。若是 source
和 destination
相同,則列表中的表尾元素被移動到表頭,並返回該元素,能夠把這種特殊狀況視做列表的旋轉(rotation)操做。優化
好比有個進程來完成派單任務,須要將用戶發送過來的申請依次派發給工做人員,那麼就能夠把工做人員的身份標示維護在循環列表中,從列表尾部讀取每次讀取身份標示後相應的標示都會被放到列表頭如此循環往復。設計
使用sorted set
和一個計算熱度的算法即可以輕鬆打造一個熱度排行榜,zrevrangebyscore
能夠獲得以分數倒序排列的序列,zrank
能夠獲得一個成員在該排行榜的位置(是分數正序排列時的位置,若是要獲取倒序排列時的位置須要用zcard
-zrank
)。
計數功能應該是最適合 Redis 的使用場景之一了,由於它高頻率讀寫的特徵能夠徹底發揮 Redis 做爲內存數據庫的高效。在 Redis 的數據結構中,string
、hash
和sorted set
都提供了incr
方法用於原子性的自增操做,下面舉例說明一下它們各自的使用場景:
string
做爲計數器,設定一個名爲REGISTERED_COUNT_TODAY
的 key,並在初始化時給它設置一個到凌晨 0 點的過時時間,每當用戶註冊成功後便使用incr
命令使該 key 增加 1,同時當天天凌晨 0 點後,這個計數器都會由於 key 過時使值清零。hash
進行計數會更好,將該計數器的 key 設爲weibo:weibo_id
,hash
的 field 爲like_number
、comment_number
、forward_number
和view_number
,在對應操做後經過hincrby
使hash 中
的 field 自增。sorted set
吧,將集合的 key 設爲POST_RANK
。當用戶發帖後,使用zincrby
將該用戶 id 的 score 增加 1。sorted set
會從新進行排序,用戶所在排行榜的位置也就會獲得實時的更新。這個場景最開始是是一篇介紹微博 Redis 應用的 PPT 中看到的,其中提到微博的 Redis 主要是用在在計數和好友關係兩方面上,當時對好友關係方面的用法不太瞭解,後來看到《Redis 設計與實現》中介紹到做者最開始去使用 Redis 即是但願能經過set
解決傳統數據庫沒法快速計算集合中交集這個功能。後來聯想到微博當前的業務場景,確實可以以這種方式實現,因此姑且猜想一下:
對於一個用戶 A,將它的關注和粉絲的用戶 id 都存放在兩個 set 中:
A:follow
:存放 A 全部關注的用戶 idA:follower
:存放 A 全部粉絲的用戶 id那麼經過sinter
命令即可以根據A:follow
和A:follower
的交集獲得與 A 互相關注的用戶。當 A 進入另外一個用戶 B 的主頁後,A:follow
和B:follow
的交集即是 A 和 B 的共同專一,A:follow
和B:follower
的交集即是 A 關注的人也關注了 B。
在 Redis 2.6.12 版本開始,string
的set
命令增長了三個參數:
EX
:設置鍵的過時時間(單位爲秒)PX
:設置鍵的過時時間(單位爲毫秒)NX
| XX
:當設置爲NX
時,僅當 key 存在時才進行操做,設置爲XX
時,僅當 key 不存在纔會進行操做因爲這個操做是原子性的,能夠簡單地以此實現一個分佈式的鎖,例如:
set key "lock" EX 1 XX
若是這個操做返回false
,說明 key 的添加不成功,也就是當前有人在佔用這把鎖。而若是返回true
,則說明得了鎖,即可以繼續進行操做,而且在操做後經過del
命令釋放掉鎖。而且即便程序由於某些緣由並無釋放鎖,因爲設置了過時時間,該鎖也會在 1 秒後自動釋放,不會影響到其餘程序的運行。
倒排索引是構造搜索功能的最多見方式,在 Redis 中也能夠經過set
進行創建倒排索引,這裏以簡單的拼音 + 前綴搜索城市功能舉例:
假設一個城市北京
,經過拼音詞庫將北京
轉爲beijing
,再經過前綴分詞將這兩個詞分爲若干個前綴索引,有:北
、北京
、b
、be
…beijin
和beijing
。將這些索引分別做爲set
的 key(例如:index:北
)並存儲北京
的 id,倒排索引便創建好了。接下來只須要在搜索時經過關鍵詞取出對應的set
並獲得其中的 id 便可。
我的能力侷限目前只知道這些數據類型的應用場景,若是各位有其餘場景的應用經驗歡迎交流補充,另外面試時被問到爲什麼使用Redis不要簡單的說由於快, 若是在系統中只使用了緩存這一個應用場景那麼最起碼能夠提供一些MySQL的QPS和Redis的QPS數據或者程序在Redis使用先後的平均響應時長來印證你的觀點。