redis介紹(7)高級用法

redis的過時策略以及內存淘汰機制

  分析:這個問題其實至關重要,到底redis有沒用到家,這個問題就能夠看出來。好比你redis只能存5G數據,但是你寫了10G,那會刪5G的數據。怎麼刪的,這個問題思考過麼?還有,你的數據已經設置了過時時間,可是時間到了,內存佔用率仍是比較高,有思考過緣由麼?redis

  回答:redis採用的是按期刪除+惰性刪除策略。數據庫

爲何不用定時刪除策略?

  定時刪除,用一個定時器來負責監視key,過時則自動刪除。雖然內存及時釋放,可是十分消耗CPU資源。在大併發請求下,CPU要將時間應用在處理請求,而不是刪除key,所以沒有采用這一策略.緩存

  按期刪除+惰性刪除是如何工做的呢?併發

  按期刪除,redis默認每一個100ms檢查,是否有過時的key,有過時key則刪除。須要說明的是,redis不是每一個100ms將全部的key檢查一次,而是隨機抽取進行檢查(若是每隔100ms,所有key進行檢查,redis豈不是卡死)。所以,若是隻採用按期刪除策略,會致使不少key到時間沒有刪除。dom

  因而,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key若是設置了過時時間那麼是否過時了?若是過時了此時就會刪除。異步

採用按期刪除+惰性刪除就沒其餘問題了麼?不是的,若是按期刪除沒刪除key。而後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會愈來愈高。那麼就應該採用內存淘汰機制。分佈式

  在redis.conf中有一行配置ui

  # maxmemory-policy volatile-lruspa

  該配置就是配內存淘汰策略的線程

    1)noeviction:當內存不足以容納新寫入數據時,新寫入操做會報錯。

    2)allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。推薦使用,目前項目在用這種。

    3)allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。

    4)volatile-lru:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,移除最近最少使用的key。這種狀況通常是把redis既當緩存,又作持久化存儲的時候才用。不推薦

    5)volatile-random:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,隨機移除某個key。依然不推薦

    6)volatile-ttl:當內存不足以容納新寫入數據時,在設置了過時時間的鍵空間中,有更早過時時間的key優先移除。不推薦

    ps:若是沒有設置 expire 的key, 不知足先決條件(prerequisites); 那麼 volatile-lru, volatile-random 和 volatile-ttl 策略的行爲, 和 noeviction(不刪除) 基本上一致。

redis和數據庫雙寫一致性問題

  分析:一致性問題是分佈式常見問題,還能夠再分爲最終一致性和強一致性。數據庫和緩存雙寫,就必然會存在不一致的問題。答這個問題,先明白一個前提。就是若是對數據有強一致性要求,不能放緩存。咱們所作的一切,只能保證最終一致性。另外,咱們所作的方案其實從根本上來講,只能說下降不一致發生的機率,沒法徹底避免。所以,有強一致性要求的數據,不能放緩存。

  回答:《分佈式之數據庫和緩存雙寫一致性方案解析》給出了詳細的分析,在這裏簡單的說一說。首先,採起正確更新策略,先更新數據庫,再刪緩存。其次,由於可能存在刪除緩存失敗的問題,提供一個補償措施便可,例如利用消息隊列。

如何應對緩存穿透和緩存雪崩問題

  分析:這兩個問題,說句實在話,通常中小型傳統軟件企業,很難碰到這個問題。若是有大併發的項目,流量有幾百萬左右。這兩個問題必定要深入考慮。
  回答:以下所示

  緩存穿透,即黑客故意去請求緩存中不存在的數據,致使全部的請求都懟到數據庫上,從而數據庫鏈接異常。

    解決方案:

    (一)利用互斥鎖,緩存失效的時候,先去得到鎖,獲得鎖了,再去請求數據庫。沒獲得鎖,則休眠一段時間重試

    (二)採用異步更新策略,不管key是否取到值,都直接返回。value值中維護一個緩存失效時間,緩存若是過時,異步起一個線程去讀數據庫,更新緩存。須要作緩存預熱(項目啓動前,先加載緩存)操做。

    (三)提供一個能迅速判斷請求是否有效的攔截機制,好比,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。若是不合法,則直接返回。

  緩存雪崩,即緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而致使數據庫鏈接異常。

    解決方案:

    (一)給緩存的失效時間,加上一個隨機值,避免集體失效。
    (二)使用互斥鎖,可是該方案吞吐量明顯降低了。
    (三)雙緩存。咱們有兩個緩存,緩存A和緩存B。緩存A的失效時間爲20分鐘,緩存B不設失效時間。本身作緩存預熱操做。而後細分如下幾個小點

  I 從緩存A讀數據庫,有則直接返回

  II A沒有數據,直接從B讀數據,直接返回,而且異步啓動一個更新線程。

  III 更新線程同時更新緩存A和緩存B。

如何解決redis的併發競爭key問題

  分析:這個問題大體就是,同時有多個子系統去set一個key。這個時候要注意什麼呢?你們思考過麼。須要說明一下,博主提早百度了一下,發現答案基本都是推薦用redis事務機制。博主不推薦使用redis的事務機制。由於咱們的生產環境,基本都是redis集羣環境,作了數據分片操做。你一個事務中有涉及到多個key操做的時候,這多個key不必定都存儲在同一個redis-server上。所以,redis的事務機制,十分雞肋。

  回答:以下所示

    (1)若是對這個key操做,不要求順序

      這種狀況下,準備一個分佈式鎖,你們去搶鎖,搶到鎖就作set操做便可,比較簡單。

    (2)若是對這個key操做,要求順序

      假設有一個key1,系統A須要將key1設置爲valueA,系統B須要將key1設置爲valueB,系統C須要將key1設置爲valueC.

  指望按照key1的value值按照 valueA-->valueB-->valueC的順序變化。這種時候咱們在數據寫入數據庫的時候,須要保存一個時間戳。假設時間戳以下

    系統A key 1 {valueA 3:00}
    系統B key 1 {valueB 3:05}
    系統C key 1 {valueC 3:10}

  那麼,假設這會系統B先搶到鎖,將key1設置爲{valueB 3:05}。接下來系統A搶到鎖,發現本身的valueA的時間戳早於緩存中的時間戳,那就不作set操做了。以此類推。

  其餘方法,好比利用隊列,將set方法變成串行訪問也能夠

相關文章
相關標籤/搜索