Redis的應用場景彙總

Redis應用場景

Redis做爲一個非關係型數據庫,除了在訪問速度上擁有顯著優點外,其自己支持的多種數據類型也很是有用,能覆蓋系統開發中的不少應用場景。下面列舉的場景有的是從網上其餘人的博客裏看到的,有的本身開發時嘗試過的一些解決方案後記錄下來的,但願能給之後的開發帶來啓發。面試

在說應用場景前先說一些是否以爲使用Redis的建議算法

使用建議

  • Redis 速度快是創建在內存數據庫基礎上的,可是一臺服務器的內存要比磁盤金貴許多,因此在項目初期不要想什麼都往 Redis 裏放,這樣當數據量上來後很快內存就會不夠用,反而得不償失。合理的利用有限的內存,將讀(寫)頻繁的熱數據放在 Redis 中才能更好感覺到它帶來的性能提高。
  • Redis 雖然提供了RDBAOF兩種持久化方式,可是廣泛仍是認爲 Redis 的持久化並非很靠譜。很是重要的數據不要依賴Redis來開發,或者最起碼不要只在Redis中持久化
  • MySQL通過不斷優化性能已經很是好,因此MySQL提供的數據結構和訪問效率能知足的需求的狀況下不要引入Redis,多引入一個組件就多一個可能的故障節點,尤爲在保持數據一致性的場景中數據(好比用戶餘額)應該只放在數據庫中,除非你知道怎麼解決考系統的分佈式事務。

緩存

做爲Key-Value形態的內存數據庫,Redis 最早會被想到的應用場景即是做爲數據緩存。而使用 Redis 緩存數據很是簡單,只須要經過string類型將序列化後的對象存起來便可,不過也有一些須要注意的地方:數據庫

  • 必須保證不一樣對象的 key 不會重複,而且使 key 儘可能短,通常使用類名(表名)加主鍵拼接而成。
  • 選擇一個優秀的序列化方式也很重要,目的是提升序列化的效率和減小內存佔用。
  • 緩存內容與數據庫的一致性,這裏通常有兩種作法:緩存

    1. 只在數據庫查詢後將對象放入緩存,若是對象發生了修改或刪除操做,直接清除對應緩存(或設爲過時)。
    2. 在數據庫新增和查詢後將對象放入緩存,修改後更新緩存,刪除後清除對應緩存(或設爲過時)。

消息隊列

Redis 中list的數據結構實現是雙向鏈表,因此能夠很是便捷的應用於消息隊列(生產者 / 消費者模型)。消息的生產者只須要經過lpush將消息放入 list,消費者即可以經過rpop取出該消息,而且能夠保證消息的有序性。若是須要實現帶有優先級的消息隊列也能夠選擇sorted set。而pub/sub功能也能夠用做發佈者 / 訂閱者模型的消息。不管使用何種方式,因爲 Redis 擁有持久化功能,也不須要擔憂因爲服務器故障致使消息丟失的狀況。服務器

時間軸(Timeline)

list做爲雙向鏈表,不光能夠做爲隊列使用。若是將它用做棧即可以成爲一個公用的時間軸。當用戶發完微博後,都經過lpush將它存放在一個 key 爲LATEST_WEIBOlist中,以後即可以經過lrange取出當前最新的微博。數據結構

循環鏈表

list 還能夠做爲循環鏈表使用 RPOPLPUSH source destination分佈式

命令 RPOPLPUSH 在一個原子時間內,執行如下兩個動做:性能

  • 將列表 source 中的最後一個元素(尾元素)彈出,並返回給客戶端。
  • source 彈出的元素插入到列表 destination ,做爲 destination 列表的的頭元素。

若是 sourcedestination 相同,則列表中的表尾元素被移動到表頭,並返回該元素,能夠把這種特殊狀況視做列表的旋轉(rotation)操做。優化

好比有個進程來完成派單任務,須要將用戶發送過來的申請依次派發給工做人員,那麼就能夠把工做人員的身份標示維護在循環列表中,從列表尾部讀取每次讀取身份標示後相應的標示都會被放到列表頭如此循環往復。設計

排行榜

使用sorted set和一個計算熱度的算法即可以輕鬆打造一個熱度排行榜,zrevrangebyscore能夠獲得以分數倒序排列的序列,zrank能夠獲得一個成員在該排行榜的位置(是分數正序排列時的位置,若是要獲取倒序排列時的位置須要用zcard-zrank)。

計數器

計數功能應該是最適合 Redis 的使用場景之一了,由於它高頻率讀寫的特徵能夠徹底發揮 Redis 做爲內存數據庫的高效。在 Redis 的數據結構中,stringhashsorted set都提供了incr方法用於原子性的自增操做,下面舉例說明一下它們各自的使用場景:

  • 若是應用須要顯示天天的註冊用戶數,即可以使用string做爲計數器,設定一個名爲REGISTERED_COUNT_TODAY的 key,並在初始化時給它設置一個到凌晨 0 點的過時時間,每當用戶註冊成功後便使用incr命令使該 key 增加 1,同時當天天凌晨 0 點後,這個計數器都會由於 key 過時使值清零。
  • 每條微博都有點贊數、評論數、轉發數和瀏覽數四條屬性,這時用hash進行計數會更好,將該計數器的 key 設爲weibo:weibo_idhash的 field 爲like_numbercomment_numberforward_numberview_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 全部關注的用戶 id
  • A:follower:存放 A 全部粉絲的用戶 id

    那麼經過sinter命令即可以根據A:followA:follower的交集獲得與 A 互相關注的用戶。當 A 進入另外一個用戶 B 的主頁後,A:followB:follow的交集即是 A 和 B 的共同專一,A:followB:follower的交集即是 A 關注的人也關注了 B。

分佈式鎖

在 Redis 2.6.12 版本開始,stringset命令增長了三個參數:

  • EX:設置鍵的過時時間(單位爲秒)
  • PX:設置鍵的過時時間(單位爲毫秒)
  • NX | XX:當設置爲NX時,僅當 key 存在時才進行操做,設置爲XX時,僅當 key 不存在纔會進行操做

    因爲這個操做是原子性的,能夠簡單地以此實現一個分佈式的鎖,例如:

set key "lock" EX 1 XX

若是這個操做返回false,說明 key 的添加不成功,也就是當前有人在佔用這把鎖。而若是返回true,則說明得了鎖,即可以繼續進行操做,而且在操做後經過del命令釋放掉鎖。而且即便程序由於某些緣由並無釋放鎖,因爲設置了過時時間,該鎖也會在 1 秒後自動釋放,不會影響到其餘程序的運行。

倒排索引

倒排索引是構造搜索功能的最多見方式,在 Redis 中也能夠經過set進行創建倒排索引,這裏以簡單的拼音 + 前綴搜索城市功能舉例:

假設一個城市北京,經過拼音詞庫將北京轉爲beijing,再經過前綴分詞將這兩個詞分爲若干個前綴索引,有:北京bbebeijinbeijing。將這些索引分別做爲set的 key(例如:index:北)並存儲北京的 id,倒排索引便創建好了。接下來只須要在搜索時經過關鍵詞取出對應的set並獲得其中的 id 便可。

我的能力侷限目前只知道這些數據類型的應用場景,若是各位有其餘場景的應用經驗歡迎交流補充,另外面試時被問到爲什麼使用Redis不要簡單的說由於快, 若是在系統中只使用了緩存這一個應用場景那麼最起碼能夠提供一些MySQL的QPS和Redis的QPS數據或者程序在Redis使用先後的平均響應時長來印證你的觀點。

相關文章
相關標籤/搜索