分布式中Redis使用場景及遇到的問題

2021-08-28 10:49:11 字數 3740 閱讀 8366

4、redis 的過期策略和記憶體淘汰機制

5、redis 和資料庫雙寫一致性問題

6、如何應對快取穿透和快取雪崩問題

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

在實際開發中使用 redis 的時候,絕大部分人只會 set value 和 get value 兩個操作,對 redis 整體缺乏乙個認知。這裡對 redis 常見問題做乙個總結,解決大家的知識盲點。本文**:

在專案中使用 redis,主要考慮兩個角度:效能和併發。如果只是為了分布式鎖這些其他功能,還有其他中介軟體 zookpeer 等代替,並非一定要使用 redis。

1. 效能:

如下圖所示,我們在碰到需要執行耗時特別久,且結果不頻繁變動的 sql,就特別適合將執行結果放入快取。這樣,後面的請求就去快取中讀取,使得請求能夠迅速響應。

根據互動效果的不同,響應時間沒有固定標準。在理想狀態下,我們的頁面跳轉需要在瞬間解決,對於頁內操作則需要在剎那間解決。

2. 併發:

如下圖所示,在大併發的情況下,所有的請求直接訪問資料庫,資料庫會出現連線異常。這個時候,就需要使用 redis 做乙個緩衝操作,讓請求先訪問到 redis,而不是直接訪問資料庫。

使用 redis 的常見問題

這個問題是對 redis 內部機制的乙個考察。很多人都不知道 redis 是單執行緒工作模型。

原因主要是以下三點:

redis 執行緒模型,如圖所示:

redis-client 在操作的時候,會產生具有不同事件型別的 socket。在服務端,有一段 i/o 多路復用程式,將其置入佇列之中。然後,檔案事件分派器,依次去佇列中取,**到不同的事件處理器中。

最常規的 set/get 操作,value 可以是 string 也可以是數字。一般做一些複雜的計數功能的快取。

這裡 value 存放的是結構化的物件,比較方便的就是操作其中的某個字段。我在做單點登入的時候,就是用這種資料結構儲存使用者資訊,以cookieid 作為 key,設定 30 分鐘為快取過期時間,能很好的模擬出類似 session 的效果。

使用 list 的資料結構,可以做簡單的訊息佇列的功能。另外,可以利用 lrange 命令,做基於 redis的分頁功能,效能極佳,使用者體驗好。

因為 set 堆放的是一堆不重複值的集合。所以可以做全域性去重的功能。我們的系統一般都是集群部署,使用 jvm 自帶的 set 比較麻煩。另外,就是利用交集、並集、差集等操作,可以計算共同喜好,全部的喜好,自己獨有的喜好等功能。

sorted set 多了乙個權重引數 score,集合中的元素能夠按 score 進行排列。可以做排行榜應用,取 top n 操作。sorted set 可以用來做延時任務。

redis 是否用到家,從這就能看出來。比如你 redis 只能存 5g 資料,可是你寫了 10g,那會刪 5g 的資料。怎麼刪的,這個問題思考過麼?

正解:redis 採用的是定期刪除+惰性刪除策略。

為什麼不用定時刪除策略

定期刪除+惰性刪除如何工作

定期刪除,redis 預設每個 100ms 檢查,有過期 key 則刪除。需要說明的是,redis 不是每個 100ms 將所有的 key 檢查一次,而是隨機抽取進行檢查。如果只採用定期刪除策略,會導致很多 key 到時間沒有刪除。於是,惰性刪除派上用場。

採用定期刪除+惰性刪除就沒其他問題了麼

在 redis.conf 中有一行配置:

# maxmemory-policy volatile-lru
該配置就是配記憶體淘汰策略的:

allkeys-random:當記憶體不足以容納新寫入資料時,在鍵空間中,隨機移除某個 key。(不推薦,應該也沒人用吧,你不刪最少使用 key,去隨機刪)

volatile-lru:當記憶體不足以容納新寫入資料時,在設定了過期時間的鍵空間中,移除最近最少使用的 key。這種情況一般是把 redis 既當快取,又做持久化儲存的時候才用。(不推薦

一致性問題還可以再分為最終一致性和強一致性。資料庫和快取雙寫,就必然會存在不一致的問題。前提是如果對資料有強一致性要求,不能放快取。我們所做的一切,只能保證最終一致性。

另外,我們所做的方案從根本上來說,只能降低不一致發生的概率。因此,有強一致性要求的資料,不能放快取。首先,採取正確更新策略,先更新資料庫,再刪快取。其次,因為可能存在刪除快取失敗的問題,提供乙個補償措施即可,例如利用訊息佇列。

ps:可以參考

這兩個問題,一般中小型傳統軟體企業很難碰到。如果有大併發的專案,流量有幾百萬左右,這兩個問題一定要深刻考慮。快取穿透,即黑客故意去請求快取中不存在的資料,導致所有的請求都懟到資料庫上,從而資料庫連線異常。

快取穿透解決方案:

快取雪崩,即快取同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到資料庫上,從而導致資料庫連線異常。

快取雪崩解決方案:

這個問題大致就是,同時有多個子系統去 set 乙個 key。這個時候要注意什麼呢?大家基本都是推薦用 redis 事務機制。

但是我並不推薦使用 redis 的事務機制。因為我們的生產環境,基本都是 redis 集群環境,做了資料分片操作。你乙個事務中有涉及到多個 key 操作的時候,這多個 key 不一定都儲存在同乙個 redis-server 上。因此,redis 的事務機制,十分雞肋。

如果對這個 key 操作,不要求順序

這種情況下,準備乙個分布式鎖,大家去搶鎖,搶到鎖就做 set 操作即可,比較簡單。

如果對這個 key 操作,要求順序

假設有乙個 key1,系統 a 需要將 key1 設定為 valuea,系統 b 需要將 key1 設定為 valueb,系統 c 需要將 key1 設定為 valuec。

期望按照 key1 的 value 值按照 valuea > valueb > valuec 的順序變化。這種時候我們在資料寫入資料庫的時候,需要儲存乙個時間戳。

假設時間戳如下:

系統 a key 1

系統 b key 1

系統 c key 1

那麼,假設系統 b 先搶到鎖,將 key1 設定為。接下來系統 a 搶到鎖,發現自己的 valuea 的時間戳早於快取中的時間戳,那就不做 set 操作了,以此類推。其他方法,比如利用佇列,將 set 方法變成序列訪問也可以。

分布式快取Redis應用場景解析

redis的應用場景非常廣泛。雖然redis是乙個key value的記憶體資料庫,但在實際場景中,redis經常被作為快取來使用,如面對資料高併發的讀寫 海量資料的讀寫等。舉個例子,a 首頁一天有100萬人訪問,其中有乙個 積分 的板塊,要直接從資料庫查詢,那麼一天就要多消耗100萬次資料庫請求。...

Redis使用場景(二)分布式鎖詳盡版

分布式鎖除了 redis實現外還有 資料庫樂觀鎖和zookeeper效率有限。分布式鎖要滿足以下條件 互斥性 確保同一時刻只有乙個客戶端持有鎖。容錯性 大部分redis節點可用,客戶端就可以加鎖解鎖。統一性 加鎖和解鎖必須為同一客戶端。首先引包 redis.clients jedis 2.9.0 實...

zookeeper適用場景 分布式鎖實現

在zookeeper應用場景有關於分布式集群配置檔案同步問題的描述,設想一下如果有100臺機器同時對同一臺機器上某個檔案進行修改,如何才能保證文字不會被寫亂,這就是最簡單的分布式鎖,本文介紹利用zk實現分布式鎖。下面是寫鎖的實現步驟 分布式寫鎖 create乙個persistent型別的znode,...