Redis緩存機制詳解
Redis 作為一個高效的內存數據庫,常用于緩存系統。
其緩存機制有助于提高數據訪問速度、減輕后端數據庫壓力。
由于 Redis 是基于內存的數據庫,內存資源有限,因此需要有合理的數據淘汰策略以管理內存使用。
1. 內存數據淘汰策略
在 Redis 配置文件中(通常是 redis.conf
),可以通過 maxmemory-policy
配置來設定具體的淘汰策略。
常見的策略包括:
volatile-lru
: 從設置了過期時間的數據集中,移除最近最少使用的數據。allkeys-lru
: 從所有數據集中,移除最近最少使用的數據。volatile-lfu
: 從設置了過期時間的數據集中,移除最不常使用的數據。allkeys-lfu
: 從所有數據集中,移除最不常使用的數據。volatile-random
: 從設置了過期時間的數據集中,隨機移除數據。allkeys-random
: 從所有數據集中,隨機移除數據。volatile-ttl
: 從設置了過期時間的數據集中,移除即將過期的數據。noeviction
: 不移除任何數據,當內存滿時,返回錯誤。該策略通常不建議使用,因為它可能導致無法寫入新數據。
2. 數據過期機制
Redis 支持對鍵設置生存時間(TTL)。當鍵的生存時間到達之后,Redis 會自動刪除該鍵。
- EXPIRE key seconds: 設置鍵在指定秒數后過期。
- PEXPIRE key milliseconds: 設置鍵在指定毫秒數后過期。
- EXPIREAT key timestamp: 設置鍵在指定的時間戳 (單位為秒) 后過期。
- PEXPIREAT key milliseconds-timestamp: 設置鍵在指定的時間戳 (單位為毫秒) 后過期。
TTL key
和 PTTL key
命令檢查鍵的剩余生存時間。具體命令細節可查看Redis通用命令詳解。
3. LRU (Least Recently Used) 緩存實現
LRU(Least Recently Used,最近最少使用)是一種常見的緩存淘汰策略,用于在緩存空間不足時確定哪些數據應該被移除,以便為新數據騰出空間。
傳統的 LRU 算法要求在每次訪問數據時,都更新數據的訪問時間,然后在淘汰時選擇最久未被訪問的數據。
但是Redis 的 LRU 算法并不是嚴格意義上的 LRU 算法,而是近似的 LRU 算法。
- Redis 會定期隨機地從數據集中(默認是每秒鐘從部分數據集中選擇5個鍵),選擇一些鍵檢查是否過期或者需要淘汰。
- 這種方法相對于每次訪問時都更新訪問時間,大大減少了對每個數據訪問的性能開銷。
盡管 LRU 的實現略有不同,但它的核心思想與一般的 LRU 策略是相似的。
配置
-
maxmemory-policy: 在 Redis 配置文件中設置此參數,可以選擇不同的淘汰策略,包括
volatile-lru
(對設置了過期時間的數據使用 LRU 策略)、allkeys-lru
(對所有數據使用 LRU 策略)等。 -
maxmemory-samples: 這個參數可以設置每次淘汰時從數據集中隨機選擇的鍵的個數,默認是 5。可以根據實際情況調整以影響 LRU 的淘汰效果。
4. LFU (Least Frequently Used) 緩存實現
LFU(Least Frequently Used,最不常用),與LRU不同的是,LFU策略基于數據的訪問頻率進行淘汰,而不是最近訪問時間。
- 高效利用緩存:LFU特別適合那些訪問頻率有明顯差異的數據集,例如一些熱點數據被頻繁訪問,而其他數據較少訪問的場景。
- 防止緩存污染:LFU可以有效防止緩存被短時間內大量訪問但長期不再使用的數據占據。
和傳統的LFU算法一樣,Redis會優先淘汰那些訪問頻率較低的數據。
LFU策略的核心機制
-
訪問頻率計數器:
- 每個鍵都有一個訪問頻率計數器,用于記錄該鍵被訪問的次數。
- 這個計數器并不是簡單的增加,而是經過某種衰減處理,以防止頻繁訪問的鍵長期占據緩存。
-
衰減機制:
- 為了防止計數器無限增長,Redis采用了一種衰減機制,使得訪問頻率會隨著時間的推移而減小。
- 具體的衰減算法結合了訪問時間和訪問頻率,確保那些歷史上曾經被頻繁訪問但最近很少使用的鍵也會被適當淘汰。
-
近似實現:
- 類似于Redis的LRU實現,LFU策略也采用了一種近似方法來減少性能開銷。
- Redis 并不會在每次訪問時精確地更新所有鍵的訪問頻率,而是通過采樣和概率進行近似估算。
配置
- maxmemory-policy: 在Redis配置文件中,
maxmemory-policy
參數可以設置為allkeys-lfu
或volatile-lfu
:allkeys-lfu
: 對所有鍵使用LFU策略。volatile-lfu
: 僅對設置了過期時間的鍵使用LFU策略。
- lfu-log-factor: 這個參數控制訪問頻率計數器的衰減速率。默認值是10,表示每次訪問頻率以log(10)的速度增長。值越大,計數器增長越慢,從而更強調近期訪問頻率。
- lfu-decay-time: 這個參數控制頻率計數器的衰減時間。默認值是1小時,表示每小時衰減一次。更短的衰減時間意味著頻率計數器更快地減小,從而使得緩存更容易淘汰那些不再頻繁訪問的鍵。
LFU 淘汰過程
- 訪問頻率記錄:每次訪問一個鍵時,對應的訪問頻率計數器會根據
lfu-log-factor
進行更新。 - 定期衰減:根據
lfu-decay-time
,Redis會定期對所有鍵的訪問頻率計數器進行衰減。 - 選擇淘汰鍵:當需要淘汰鍵時,Redis會選擇那些訪問頻率最低的鍵進行淘汰。這些鍵的選擇也可能通過隨機采樣來完成,以減少性能開銷。
5. 緩存穿透、緩存擊穿和緩存雪崩
-
緩存穿透:
- 通常指緩存和數據庫中都沒有的數據,但大量請求卻涌入,直接打到數據庫上,導致數據庫壓力過大。
- 用戶請求的數據本身不存在(例如惡意攻擊請求大量不存在的數據)。
- 每次請求都會繞過緩存直接查詢數據庫,緩存不起作用。
常見解決辦法:
-
緩存空對象
-
使用布隆過濾器
-
緩存擊穿:
- 指的是指緩存中某個熱點數據失效(過期)后,瞬時大量請求直接落到數據庫,導致數據庫壓力驟增的現象。
- 熱點數據在緩存中存在,并且有許多請求正在訪問該數據。
- 緩存數據過期了,而這時有大量請求同時到來,所有請求都繞過緩存直接訪問數據庫。
常見解決方案:
- 緩存雪崩:
- 指的是緩存服務器(Redis)集群宕機或者大量緩存集中失效,導致大量請求直接打到數據庫上,可能會壓垮數據庫。
- 同一時刻大量緩存數據同時過期。
- 緩存服務器宕機或重啟,導致緩存不可用。
常見解決方案:
Tips:了解更多Redis知識,可以去博主的專欄查看哦~