redis 的使用很廣泛,若是你沒有使用過 redis,都很差意思說本身是開發界的老司機。今天又到了知識普及時間。redis
一、持久化機制,能夠按期將內存中的數據持久化到硬盤上。算法
二、binlog功能,能夠將全部操做寫入日誌,當redis出現故障,可依照binlog進行數據恢復。數據庫
三、支持virtual memory,能夠限定內存使用大小,當數據超過閾值,則經過相似LRU的算法把內存中的最不經常使用數據保存到硬盤的頁面文件中。緩存
四、支持的數據類型更多,使用的想象空間更大。服務器
五、支持實物。併發
固然,這些也能夠看作 redis 的優勢。除了這些,被你們熟知的就是--快。對滴,就是快,redis 是一個快男,可是有時候快並不必定壞事。dom
一、速度快。異步
二、支持豐富數據類型: String ,List,Set,Sorted Set,Hash 。分佈式
三、豐富的特性。如訂閱發佈 Pub / Sub 功能、key 過時策略等。函數
四、持久化存儲。
一、過於依賴內存。
二、redis是單線程的,單臺服務器沒法充分利用多核服務器的CPU。
一、純內存操做。
二、單線程,避免頻繁上下文切換。
三、採用了非阻塞I/O多路複用機制。
四、使用底層模型不一樣,Redis直接本身構建了VM 機制 ,由於通常的系統調用系統函數的話,會浪費必定的時間去移動和請求。(有錢真的能夠隨心所欲,自給自足。)
一、緩存穿透
- 惡意攻擊,查詢數據庫中不存在的數據(未記錄緩存)
- 方案:
一、利用互斥鎖,緩存失效的時候,先去得到鎖,獲得鎖了,再去請求數據庫。沒獲得鎖,則休眠一段時間重試。
二、用異步更新策略,不管key是否取到值,都直接返回。value值中維護一個緩存失效時間,緩存若是過時,異步起一個線程去讀數據庫,更新緩存。須要作緩存預熱(項目啓動前,先加載緩存)操做。
三、提供一個能迅速判斷請求是否有效的攔截機制,好比,利用布隆過濾器,內部維護一系列合法有效的key。迅速判斷出,請求所攜帶的Key是否合法有效。若是不合法,則直接返回。
二、緩存雪崩
- 緩存同一時間大面積的失效,這個時候又來了一波請求,結果請求都懟到數據庫上,從而致使數據庫鏈接異常。
- 方案:
一、緩存時間加隨機數,設置不一樣有效期,避免同時失效。
二、分佈式部署,數據分散在不一樣的redis和數據庫。
三、永不過時(不建議)
三、緩存擊穿
- 單一 key 很是熱點,失效後直接請求數據庫。
- 方案:
一、永不過時
二、互斥鎖
四、redis 和數據庫雙寫一致性問題
- 分佈式常見問題。數據庫和緩存雙寫,就必然會存在不一致的問題。
- 方案:首先,採起正確更新策略,先更新數據庫,再刪緩存。其次,由於可能存在刪除緩存失敗的問題,提供一個補償措施便可,例如利用消息隊列。
五、redis 併發競爭 key 問題。
- 同時有多個子系統去set一個key。
- 方案:
一、redis 事物機制,不適用 redis 集羣(可能多個 key 不存儲在一個 redis-server 上)。
二、(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方法變成串行訪問也能夠。總之,靈活變通。
如下徹底複製來的,博主寫的已經很是好了,不須要再修飾了,哈哈哈。
分析:
這個問題其實至關重要,到底redis有沒用到家,這個問題就能夠看出來。好比你redis只能存5G數據,但是你寫了10G,那會刪5G的數據。怎麼刪的,這個問題思考過麼?還有,你的數據已經設置了過時時間,可是時間到了,內存佔用率仍是比較高,有思考過緣由麼?
回答:
redis採用的是按期刪除+惰性刪除策略。
爲何不用定時刪除策略?
定時刪除,用一個定時器來負責監視key,過時則自動刪除。雖然內存及時釋放,可是十分消耗CPU資源。在大併發請求下,CPU要將時間應用在處理請求,而不是刪除key,所以沒有采用這一策略.。
按期刪除+惰性刪除是如何工做的呢?
按期刪除,redis默認每一個100ms檢查,是否有過時的key,有過時key則刪除。須要說明的是,redis不是每一個100ms將全部的key檢查一次,而是隨機抽取進行檢查(若是每隔100ms,所有key進行檢查,redis豈不是卡死)。所以,若是隻採用按期刪除策略,會致使不少key到時間沒有刪除。
因而,惰性刪除派上用場。也就是說在你獲取某個key的時候,redis會檢查一下,這個key若是設置了過時時間那麼是否過時了?若是過時了此時就會刪除。
採用按期刪除+惰性刪除就沒其餘問題了麼?
不是的,若是按期刪除沒刪除key。而後你也沒即時去請求key,也就是說惰性刪除也沒生效。這樣,redis的內存會愈來愈高。那麼就應該採用內存淘汰機制。
在redis.conf中有一行配置
# maxmemory-policy volatile-lru
該配置就是配內存淘汰策略的(什麼,你沒配過?好好檢討一下本身)
1)noeviction:當內存不足以容納新寫入數據時,新寫入操做會報錯。應該沒人用吧。
2)allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的key。推薦使用,目前項目在用這種。
3)allkeys-random:當內存不足以容納新寫入數據時,在鍵空間中,隨機移除某個key。應該也沒人用吧,你不刪最少使用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(不刪除) 基本上一致。
老規矩,遇到好的文章要分享。
https://mp.weixin.qq.com/s/gEU8HtsQNPXY8bzkK-Qllg