1. 前言
Redis 相對于傳統的關系型數據庫(例如 MySQL )而言,還具有設置過期時間的特性,在項目實戰中,我們經常關心的三元組是 {key,value,expire_time}
。這里的過期時間(expire_time)是的具體執行方式,涉及到 Redis 的緩存過期策略。
2. 緩存過期策略
面試官提問: Redis 里的 Key 超過失效時間,是如何處理的呢?
題目解析:
首先,我們要明白緩存過期的目的是為了在 Key 超過 expire_time 后,從內存中刪除,減少內存空間的占用。其次,要分析不同策略的定義、優點和缺點。Redis 的過期策略主要有三種實現方式:
(1)定時刪除:
- 定義:對于每一個有過期時間的 Key,創建一個定時器,到過期時間立即刪除;
- 優點:保存內存可以盡快釋放,減少過期 Key 對內存空間的占用;
- 缺點:占用大量的 CPU 資源去處理定時器,影響緩存的吞吐量,這和 Redis 設計追求性能的設定不符,所以一般不會采用這種策略。
(2)惰性刪除:
- 定義:過期的 Key 不做處理,只有當訪問這個 Key 時才會判斷是否過期,過期則清除;
- 優點:刪除操作只有在訪存的時候才可能執行,對 CPU 的占用做到了最小。
- 缺點:如果內存中大量的 Key 均過期,且一段時間內沒有被訪問,會占用大量內存。
(3)定期刪除:
- 定義:每隔一段時間全量掃描設置了過期時間的 Key,如果失效則從內存中刪除,否則不做處理;
- 優點:通過限制定時的頻率,來減少對 CPU 的占用和對內存的占用;
- 缺點:作為一種折中的方案,在內存友好方面,不如定時刪除策略;在 CPU 友好方面,不如惰性刪除。使用時的表現非常依賴配置的定期頻率。
3. 內存淘汰機制
面試官提問: Redis 的內存淘汰機制有哪些,能枚舉說明嗎?
題目解析:
我們需要注意,緩存過期策略和內存淘汰機制是容易混淆的兩個概念,兩者的目的不同。
- 緩存過期策略:針對過期 Key ,從內存中移除的方式。
- 內存淘汰機制:針對 Redis 內存不足時,業務還在繼續往 Redis 追加內容,如何處理已有的內容。
在 Redis 的 redis.conf
文件中,我們能找到八種可配置的內存淘汰機制:
- volatile-lru:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,移除最近最少使用的 key;
- allkeys-lru:當內存不足以容納新寫入數據時,在鍵空間中,移除最近最少使用的 key;
- volatile-lfu:當內存不足以容納新寫入數據時,在過期密集的鍵中,使用 LFU 算法進行刪除 key;
- allkeys-lfu:當內存不足以容納新寫入數據時,對所有的 key 執行 LFU 算法篩選過期;
- volatile-random:當內存不足以容納新寫入數據時,在設置了過期的鍵中,隨機刪除一個 key;
- allkeys-random:當內存不足以容納新寫入數據時,隨機刪除一個或者多個 key;
- volatile-ttl:當內存不足以容納新寫入數據時,在設置了過期時間的鍵空間中,有更早過期時間的 key 優先移除;
- noeviction:當內存不足以容納新寫入數據時,新寫入操作直接報錯,無法寫入。
上述算法按照特性可以分為幾類:LRU/LFU 算法、隨機刪除算法、優先淘汰歷史數據算法、報錯處理算法。
在項目中推薦兩種 LRU 算法,即如果 Redis 用作持久化數據庫,不配置緩存過期時間,采用 allkeys-lru ;如果 Redis 作為緩存數據庫,配置了 Key 過期時間,采用 volatile-lru 算法。
4. LRU 算法
面試官提問: 緩存過期的 LRU 算法原理是什么?
題目解析:
既然在 Redis 中談到了 LRU ,就不可避免解釋其原理。LRU(Least Recently Used,最近最少使用算法)是最常見的緩存淘汰算法,核心思想是 "如果數據最近被訪問過,那么將來被訪問的可能性也更高"。
?
LRU 算法的核心步驟在于:
- 新數據直接插入到鏈表頭部;
- 每當緩存命中(即緩存數據被訪問),則將被命中的數據移到鏈表頭部;
- 當鏈表滿的時候,將鏈表尾部的數據丟棄。
從性質上總結,越靠近鏈表頭部的數據越是不容易被淘汰,越靠近鏈表尾部的數據越是容易淘汰。
5. 小結
本章介紹了 Redis 緩存過期策略和內存淘汰策略,需要大家區分兩種策略解決的問題,同時需要針對 LRU 算法原理進行說明,必要性能夠做到手寫 LRU 算法的偽代碼。